Skip to content
This repository was archived by the owner on Aug 9, 2021. It is now read-only.

Commit e83c75a

Browse files
committed
feat(agent): enroll by entity token
Signed-off-by: Thierry Bugier <[email protected]>
1 parent 2f260f0 commit e83c75a

File tree

2 files changed

+239
-85
lines changed

2 files changed

+239
-85
lines changed

inc/agent.class.php

+230-85
Original file line numberDiff line numberDiff line change
@@ -1384,97 +1384,242 @@ protected function enrollByInvitationToken($input) {
13841384
$input['version'] = $version;
13851385
$input['users_id'] = $agentAccount->getID();
13861386
$input['mdm_type'] = $mdmType;
1387-
$input['$systemPermission'] = $systemPermission;
1387+
$input['systemPermission'] = $systemPermission;
13881388
return $input;
13891389

13901390
}
13911391

13921392
/**
1393-
* @param string $serial
1394-
* @param array $authFactors
1395-
* @param string $csr Certificate Signing Request from the agent
1396-
* @param &string $notFoundMessage Contains the error message if the enrollment failed
1397-
* @return boolean|PluginFlyvemdmAgent
1398-
*
1393+
* Attemt to enroll with an entity invitation token
1394+
* @param array $input Enrollment data
1395+
* @return array|bool
13991396
*/
1400-
//protected static function enrollByEntityToken($serial, $authFactors, $csr, &$errorMessage) {
1401-
//global $DB;
1402-
1403-
//$token = $DB->escape($authFactors['entityToken']);
1404-
1405-
//// Find an entity matching the given token
1406-
//$entity = new PluginFlyvemdmEntityconfig();
1407-
//if (!$entity->getFromDBByCrit(['enroll_token' => $token])) {
1408-
// $errorMessage = "no entity token not found";
1409-
// return false;
1410-
//}
1411-
1412-
//// Create a new computer for the device being enrolled
1413-
//// TODO : Enable localization of the type
1414-
//$computerType = new ComputerType();
1415-
//$computerTypeId = $computerType->import(['name' => 'Smartphone']);
1416-
//if ($computerTypeId == -1 || $computerTypeId === false) {
1417-
// $computerTypeId = 0;
1418-
//}
1419-
//$computer = new Computer();
1420-
//$condition = "`serial`='" . $DB->escape($serial) . "' AND `entities_id`='" . $entity->getID() . "'";
1421-
//$computerCollection = $computer->find($condition);
1422-
//if (count($computerCollection) > 1) {
1423-
// $errorMessage = "failed to find the computer";
1424-
// return false;
1425-
//}
1426-
//if (count($computerCollection) == 1) {
1427-
1428-
// reset($computerCollection);
1429-
// $computer->getFromDB(key($computerCollection));
1430-
// $computerId = $computer->getID();
1431-
1432-
//} else {
1433-
// $computerId = $computer->add([
1434-
// 'entities_id' => $entity->getID(),
1435-
// 'serial' => $serial,
1436-
// 'computertypes_id' => $computerTypeId
1437-
// ]);
1438-
1439-
// if ($computerId === false) {
1440-
// $errorMessage = "failed to create the computer";
1441-
// return false;
1442-
// }
1443-
//}
1444-
1445-
//if (! $computerId > 0) {
1446-
// $errorMessage = "failed to update the computer";
1447-
// return false;
1448-
//}
1449-
1450-
//// Create an agent for this device, linked to the new computer
1451-
//$agent = new PluginFlyvemdmAgent();
1452-
//$condition = "`computers_id`='$computerId'";
1453-
//$agentCollection = $agent->find($condition);
1454-
//if (count($agentCollection) > 1) {
1455-
// return false;
1456-
//}
1457-
//if (count($agentCollection) == 1) {
1458-
1459-
// reset($agentCollection);
1460-
// $agent->getFromDB(key($agentCollection));
1461-
// $agentId = $agent->getId();
1462-
1463-
//} else {
1464-
// $agentId = $agent->add([
1465-
// 'entities_id' => $entity->getID(),
1466-
// 'computers_id' => $computer->getID(),
1467-
// 'token_expire' => '0000-00-00 00:00:00'
1468-
// ]);
1469-
//}
1470-
1471-
//if (! $agentId > 0) {
1472-
// return false;
1473-
//}
1474-
1475-
//return $agent;
1476-
1477-
//}
1397+
protected function enrollByEntityToken($input) {
1398+
$invitationToken = isset($input['_invitation_token']) ? $input['_invitation_token'] : null;
1399+
$csr = isset($input['csr']) ? $input['csr'] : null;
1400+
$version = isset($input['version']) ? $input['version'] : null;
1401+
$mdmType = isset($input['type']) ? $input['type'] : null;
1402+
$inventory = isset($input['inventory']) ? htmlspecialchars_decode(base64_decode($input['inventory']),
1403+
ENT_COMPAT | ENT_XML1) : null;
1404+
$systemPermission = isset($input['has_system_permission']) ? $input['has_system_permission'] : 0;
1405+
// For non-android agents, system permssion might be forced to 1 depending on the lack of such cosntraint
1406+
1407+
$input = [];
1408+
1409+
// Find the entity
1410+
$entityConfig = new PluginFlyvemdmEntityconfig();
1411+
if (!$entityConfig->getFromDBByToken($invitationToken)) {
1412+
$this->filterMessages(__('Entity token invalid', 'flyvemdm'));
1413+
return false;
1414+
}
1415+
$entity = new Entity();
1416+
if (!$entity->getFromDB($entityConfig->getID())) {
1417+
$this->filterMessages(__('Entity not found', 'flyvemdm'));
1418+
return false;
1419+
}
1420+
$entityId = $entity->getID();
1421+
1422+
if (empty($inventory)) {
1423+
$event = __('Device inventory XML is mandatory', 'flyvemdm');
1424+
$this->filterMessages($event);
1425+
$this->logInvitationEvent($invitation, $event);
1426+
return false;
1427+
}
1428+
1429+
if ($config['debug_save_inventory'] != '0') {
1430+
PluginFlyvemdmCommon::saveInventoryFile($inventory, $invitationToken);
1431+
}
1432+
$parsedXml = PluginFlyvemdmCommon::parseXML($inventory);
1433+
if (!$parsedXml) {
1434+
$event = __('Inventory XML is not well formed', 'flyvemdm');
1435+
$this->filterMessages($event);
1436+
$this->logInvitationEvent($invitation, $event);
1437+
return false;
1438+
}
1439+
1440+
if (empty($version)) {
1441+
$event = __('Agent version missing', 'flyvemdm');
1442+
$this->filterMessages($event);
1443+
$this->logInvitationEvent($invitation, $event);
1444+
return false;
1445+
}
1446+
1447+
if (empty($mdmType)) {
1448+
$event = __('MDM type missing', 'flyvemdm');
1449+
$this->filterMessages($event);
1450+
$this->logInvitationEvent($invitation, $event);
1451+
return false;
1452+
}
1453+
1454+
if (!in_array($mdmType, array_keys($this::getEnumMdmType()))) {
1455+
$event = __('unknown MDM type', 'flyvemdm');
1456+
$this->filterMessages($event);
1457+
$this->logInvitationEvent($invitation, $event);
1458+
return false;
1459+
}
1460+
1461+
if (preg_match(PluginFlyvemdmCommon::SEMVER_VERSION_REGEX, $version) !== 1) {
1462+
$event = __('Bad agent version', 'flyvemdm');
1463+
$this->filterMessages($event);
1464+
$this->logInvitationEvent($invitation, $event);
1465+
return false;
1466+
}
1467+
1468+
// Check the agent matches the minimum version requirement of the backend
1469+
$minVersion = $this->getMinVersioForType($mdmType);
1470+
if (version_compare($minVersion, $version) > 0) {
1471+
$event = __('The agent version is too low', 'flyvemdm');
1472+
$this->filterMessages($event);
1473+
$this->logInvitationEvent($invitation, $event);
1474+
return false;
1475+
}
1476+
1477+
// Check the agent shall provide or not the system permissions flag
1478+
switch ($mdmType) {
1479+
case 'android':
1480+
if ($systemPermission === null) {
1481+
$event = __('The agent does not advertise its system permissions', 'flyvemdm');
1482+
$this->filterMessages($event);
1483+
$this->logInvitationEvent($invitation, $event);
1484+
return false;
1485+
}
1486+
}
1487+
1488+
//sign the agent's certificate (if TLS enabled)
1489+
$input['certificate'] = '';
1490+
if ($config['mqtt_tls_for_clients'] != '0' && $config['mqtt_use_client_cert'] != '0') {
1491+
$answer = self::signCertificate($csr);
1492+
$crt = isset($answer['crt']) ? $answer['crt'] : false;
1493+
if ($crt === false) {
1494+
$event = __("Failed to sign the certificate", 'flyvemdm') . "\n " . $answer['message'];
1495+
$this->filterMessages($event);
1496+
$this->logInvitationEvent($invitation, $event);
1497+
return false;
1498+
}
1499+
$input['certificate'] = $crt;
1500+
}
1501+
1502+
// Create the device
1503+
$pfCommunication = new PluginFusioninventoryCommunication();
1504+
$_SESSION['glpi_fusionionventory_nolock'] = true;
1505+
ob_start();
1506+
if (!key_exists('glpi_plugin_fusioninventory', $_SESSION) || !key_exists('xmltags',
1507+
$_SESSION['glpi_plugin_fusioninventory'])) {
1508+
// forced reload of the FI plugin for correct import of inventory
1509+
unset($LOADED_PLUGINS['fusioninventory']);
1510+
Plugin::load('fusioninventory');
1511+
}
1512+
$pfCommunication->handleOCSCommunication('', $inventory, 'glpi');
1513+
$fiOutput = ob_get_contents();
1514+
ob_end_clean();
1515+
if (strlen($fiOutput) != 0) {
1516+
// FI print errors to sdt output and agents needs a correct response, let's save this to logs.
1517+
$this->logInvitationEvent($invitation, $fiOutput);
1518+
}
1519+
unset($_SESSION['glpi_fusionionventory_nolock']);
1520+
$fiAgentId = $_SESSION['plugin_fusioninventory_agents_id']; // generated by FusionInventory
1521+
1522+
if ($fiAgentId === 0 || !property_exists($parsedXml, 'DEVICEID')) {
1523+
$event = __('Cannot get the FusionInventory agent', 'flyvemdm');
1524+
$this->filterMessages($event);
1525+
$this->logInvitationEvent($invitation, $event);
1526+
return false;
1527+
}
1528+
1529+
$pfAgent = new PluginFusioninventoryAgent();
1530+
if (!$pfAgent->getFromDBByCrit(['device_id' => $parsedXml->DEVICEID])) {
1531+
$event = __('FusionInventory agent not created', 'flyvemdm');
1532+
$this->filterMessages($event);
1533+
$this->logInvitationEvent($invitation, $event);
1534+
return false;
1535+
}
1536+
$computerId = $pfAgent->getField(Computer::getForeignKeyField());
1537+
1538+
if ($computerId === 0) {
1539+
$event = __("Cannot create the device", 'flyvemdm');
1540+
$this->filterMessages($event);
1541+
$this->logInvitationEvent($invitation, $event);
1542+
return false;
1543+
}
1544+
1545+
// Set the type of computer
1546+
$computerTypeId = $config['computertypes_id'];
1547+
if ($computerTypeId == -1 || $computerTypeId === false) {
1548+
$computerTypeId = 0;
1549+
}
1550+
$computer = new Computer();
1551+
$computer->update([
1552+
'id' => $computerId,
1553+
'computertypes_id' => $computerTypeId,
1554+
'users_id' => $userId,
1555+
]);
1556+
1557+
// Awful hack because the current user profile does not
1558+
// have more rights than the profile of the agent.
1559+
// @see User::post_addItem()
1560+
// @see Profle::currentUserHaveMoreRightThan()
1561+
// @see Profile::getUnderActiveProfileRestrictRequest()
1562+
$backupProfileRight = $_SESSION['glpiactiveprofile']['profile'];
1563+
$_SESSION['glpiactiveprofile']['profile'] = $_SESSION['glpiactiveprofile']['profile'] | CREATE;
1564+
1565+
//create agent user account
1566+
$agentAccount = new User();
1567+
$agentAccount->add([
1568+
'usercategories_id' => $config['agentusercategories_id'],
1569+
'name' => 'flyvemdm-' . PluginFlyvemdmCommon::generateUUID(),
1570+
'realname' => $computer->getField('serial'),
1571+
'_profiles_id' => $config['agent_profiles_id'],
1572+
'profiles_id' => $config['agent_profiles_id'], // Default profile when user logs in
1573+
'_entities_id' => $entityId,
1574+
'_is_recursive' => 0,
1575+
'authtype' => Auth::DB_GLPI,
1576+
]);
1577+
1578+
// End of awful hack !
1579+
$_SESSION['glpiactiveprofile']['profile'] = $backupProfileRight;
1580+
1581+
if ($agentAccount->isNewItem()) {
1582+
$event = __('Cannot create a user account for the agent', 'flyvemdm');
1583+
$this->filterMessages($event);
1584+
$this->logInvitationEvent($invitation, $event);
1585+
return false;
1586+
}
1587+
1588+
$agentToken = User::getToken($agentAccount->getID(), 'api_token');
1589+
if ($agentToken === false) {
1590+
$event = __('Cannot create the API token for the agent', 'flyvemdm');
1591+
$this->filterMessages($event);
1592+
$this->logInvitationEvent($invitation, $event);
1593+
return false;
1594+
}
1595+
1596+
// Create the agent
1597+
$defaultFleet = PluginFlyvemdmFleet::getDefaultFleet();
1598+
if ($defaultFleet === null) {
1599+
$event = __("No default fleet available for the device", 'flyvemdm');
1600+
$this->filterMessages($event);
1601+
$this->logInvitationEvent($invitation, $event);
1602+
return false;
1603+
}
1604+
1605+
// Enrollment is about to succeed then cleanup subtopics
1606+
$this->fields['computers_id'] = $computerId;
1607+
$this->fields['entities_id'] = $entityId;
1608+
$this->cleanupSubtopics();
1609+
1610+
$input['name'] = '';
1611+
$input['computers_id'] = $computerId;
1612+
$input['entities_id'] = $entityId;
1613+
$input['plugin_flyvemdm_fleets_id'] = $defaultFleet->getID();
1614+
$input['_invitations_id'] = $invitation->getID();
1615+
$input['enroll_status'] = 'enrolled';
1616+
$input['version'] = $version;
1617+
$input['users_id'] = $agentAccount->getID();
1618+
$input['mdm_type'] = $mdmType;
1619+
$input['$systemPermission'] = $systemPermission;
1620+
1621+
return $input;
1622+
}
14781623

14791624
/**
14801625
* Erase delete persisted MQTT topics of the agent

inc/entityconfig.class.php

+9
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,15 @@ public function getFromDBOrCreate($ID) {
274274
return true;
275275
}
276276

277+
/**
278+
* Finds the entity configuration that matches the token given in argument
279+
* @param string $token
280+
* @return boolean true if the token exist
281+
*/
282+
public function getFromDBByToken($token) {
283+
return $this->getFromDBByCrit(['enroll_token' => $token]);
284+
}
285+
277286
/**
278287
* Gets the tabs name
279288
* @param CommonGLPI $item

0 commit comments

Comments
 (0)