Source

Target

View open merge request
Commits (31)
Showing with 305 additions and 53 deletions
+305 -53
.vendor/ .vendor/
.composer.lock .composer.lock
filelist
phpstan.neon
.idea/fusiondirectory-orchestrator.iml
.idea/modules.xml
.idea/php.xml
.idea/vcs.xml
.idea/codeStyles/codeStyleConfig.xml
...@@ -93,10 +93,3 @@ trigger-ci-ubuntu-focal: ...@@ -93,10 +93,3 @@ trigger-ci-ubuntu-focal:
project: ubuntu/focal-fusiondirectory-orchestrator-dev project: ubuntu/focal-fusiondirectory-orchestrator-dev
branch: "main" branch: "main"
trigger-ci-centos-7:
stage: trigger
only:
- dev
trigger:
project: centos/centos7-fusiondirectory-orchestrator-dev
branch: "main"
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
...@@ -55,7 +55,7 @@ class TaskController ...@@ -55,7 +55,7 @@ class TaskController
switch ($objectType) { switch ($objectType) {
case $objectType: case $objectType:
if (class_exists($objectType)) { if (class_exists($objectType)) {
$endpoint = new $objectType; $endpoint = new $objectType($this->gateway);
$result = $endpoint->processEndPointGet(); $result = $endpoint->processEndPointGet();
} }
break; break;
......
<?php
class MailUtils
{
public function __construct ()
{
}
public function sendMail ($setFrom, $setBCC, $recipients, $body, $signature, $subject, $receipt, $attachments)
{
$mail_controller = new \FusionDirectory\Mail\MailLib($setFrom,
$setBCC,
$recipients,
$body,
$signature,
$subject,
$receipt,
$attachments);
return $mail_controller->sendMail();
}
/**
* @return array
* Note : A simple retrieval methods of the mail backend configuration set in FusionDirectory
*/
public function getMailObjectConfiguration (TaskGateway $gateway): array
{
return $gateway->getLdapTasks(
"(objectClass=fdTasksConf)",
["fdTasksConfLastExecTime", "fdTasksConfIntervalEmails", "fdTasksConfMaxEmails"]
);
}
}
\ No newline at end of file
<?php <?php
class TokenUtils class ReminderTokenUtils
{ {
private function __construct () public function __construct ()
{ {
} }
...@@ -12,7 +12,7 @@ class TokenUtils ...@@ -12,7 +12,7 @@ class TokenUtils
* @return string * @return string
* @throws Exception * @throws Exception
*/ */
public static function generateToken (string $userDN, int $timeStamp, TaskGateway $gateway): string public function generateToken (string $userDN, int $timeStamp, TaskGateway $gateway): string
{ {
$token = NULL; $token = NULL;
// Salt has been generated with APG. // Salt has been generated with APG.
...@@ -25,10 +25,10 @@ class TokenUtils ...@@ -25,10 +25,10 @@ class TokenUtils
$token_hmac = hash_hmac("sha256", $time . $payload, $_ENV["SECRET_KEY"], TRUE); $token_hmac = hash_hmac("sha256", $time . $payload, $_ENV["SECRET_KEY"], TRUE);
// We need to have a token allowed to be used within an URL. // We need to have a token allowed to be used within an URL.
$token = Utils::base64urlEncode($token_hmac); $token = $this->base64urlEncode($token_hmac);
// Save token within LDAP // Save token within LDAP
self::saveTokenInLdap($userDN, $token, $timeStamp, $gateway); $this->saveTokenInLdap($userDN, $token, $timeStamp, $gateway);
return $token; return $token;
} }
...@@ -41,7 +41,7 @@ class TokenUtils ...@@ -41,7 +41,7 @@ class TokenUtils
* @return bool * @return bool
* @throws Exception * @throws Exception
*/ */
public static function saveTokenInLdap (string $userDN, string $token, int $days, TaskGateway $gateway): bool private function saveTokenInLdap (string $userDN, string $token, int $days, TaskGateway $gateway): bool
{ {
$result = FALSE; $result = FALSE;
...@@ -64,17 +64,17 @@ class TokenUtils ...@@ -64,17 +64,17 @@ class TokenUtils
// Verify if token ou branch exists // Verify if token ou branch exists
if (!self::tokenBranchExist('ou=tokens' . ',' . $_ENV["LDAP_BASE"], $gateway)) { if (!$this->tokenBranchExist('ou=tokens' . ',' . $_ENV["LDAP_BASE"], $gateway)) {
// Create the branch // Create the branch
self::createBranchToken($gateway); $this->createBranchToken($gateway);
} }
// The user token DN creation // The user token DN creation
$userTokenDN = 'cn=' . $uid . ',ou=tokens' . ',' . $_ENV["LDAP_BASE"]; $userTokenDN = 'cn=' . $uid . ',ou=tokens' . ',' . $_ENV["LDAP_BASE"];
// Verify if a token already exists for specified user and remove it to create new one correctly. // Verify if a token already exists for specified user and remove it to create new one correctly.
if (self::tokenBranchExist($userTokenDN, $gateway)) { if ($this->tokenBranchExist($userTokenDN, $gateway)) {
// Remove the user token // Remove the user token
self::removeUserToken($userTokenDN, $gateway); $this->removeUserToken($userTokenDN, $gateway);
} }
// Add token to LDAP for specific UID // Add token to LDAP for specific UID
...@@ -95,7 +95,7 @@ class TokenUtils ...@@ -95,7 +95,7 @@ class TokenUtils
* @return int * @return int
* Note : Simply return the difference between first and second call. (First call can be null). * Note : Simply return the difference between first and second call. (First call can be null).
*/ */
public static function getTokenExpiration (int $subTaskCall, int $firstCall, int $secondCall): int public function getTokenExpiration (int $subTaskCall, int $firstCall, int $secondCall): int
{ {
// if firstCall is empty, secondCall is the timestamp expiry for the token. // if firstCall is empty, secondCall is the timestamp expiry for the token.
$result = $secondCall; $result = $secondCall;
...@@ -115,7 +115,7 @@ class TokenUtils ...@@ -115,7 +115,7 @@ class TokenUtils
* @return void * @return void
* Note : Simply remove the token for specific user DN * Note : Simply remove the token for specific user DN
*/ */
public static function removeUserToken ($userTokenDN, TaskGateway $gateway): void private function removeUserToken ($userTokenDN, TaskGateway $gateway): void
{ {
// Add token to LDAP for specific UID // Add token to LDAP for specific UID
try { try {
...@@ -130,7 +130,7 @@ class TokenUtils ...@@ -130,7 +130,7 @@ class TokenUtils
* Create ou=pluginManager LDAP branch * Create ou=pluginManager LDAP branch
* @throws Exception * @throws Exception
*/ */
public static function createBranchToken (TaskGateway $gateway): void private function createBranchToken (TaskGateway $gateway): void
{ {
try { try {
ldap_add( ldap_add(
...@@ -153,7 +153,7 @@ class TokenUtils ...@@ -153,7 +153,7 @@ class TokenUtils
* @param string $taskDN * @param string $taskDN
* @return array * @return array
*/ */
public static function generateTokenUrl (string $token, array $mailTemplateForm, string $taskDN): array public function generateTokenUrl (string $token, array $mailTemplateForm, string $taskDN): array
{ {
//Only take the cn of the main task name : //Only take the cn of the main task name :
preg_match('/cn=([^,]+),ou=/', $taskDN, $matches); preg_match('/cn=([^,]+),ou=/', $taskDN, $matches);
...@@ -173,7 +173,7 @@ class TokenUtils ...@@ -173,7 +173,7 @@ class TokenUtils
* @return bool * @return bool
* Note : Simply inspect if the branch for token is existing. * Note : Simply inspect if the branch for token is existing.
*/ */
public static function tokenBranchExist (string $dn, TaskGateway $gateway): bool private function tokenBranchExist (string $dn, TaskGateway $gateway): bool
{ {
$result = FALSE; $result = FALSE;
...@@ -195,4 +195,14 @@ class TokenUtils ...@@ -195,4 +195,14 @@ class TokenUtils
return $result; return $result;
} }
/**
* @param string $text
* @return string
* Note : This come from jwtToken, as it is completely private - it is cloned here for now.
*/
private function base64urlEncode (string $text): string
{
return str_replace(["+", "/", "="], ["A", "B", ""], base64_encode($text));
}
} }
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
class Utils class Utils
{ {
private function __construct () public function __construct ()
{ {
} }
...@@ -11,22 +11,14 @@ class Utils ...@@ -11,22 +11,14 @@ class Utils
* @return array * @return array
* Note : Recursively filters out empty values and arrays at any depth. * Note : Recursively filters out empty values and arrays at any depth.
*/ */
public static function recursiveArrayFilter (array $array): array public function recursiveArrayFilter (array $array): array
{ {
// First filter the array for non-empty elements return array_filter($array, function ($item) {
$filtered = array_filter($array, function ($item) {
if (is_array($item)) { if (is_array($item)) {
// Recursively filter the sub-array $item = $this->recursiveArrayFilter($item);
$item = self::recursiveArrayFilter($item);
// Only retain non-empty arrays
return !empty($item);
} else {
// Retain non-empty scalar values
return !empty($item);
} }
return !empty($item);
}); });
return $filtered;
} }
/** /**
...@@ -36,7 +28,7 @@ class Utils ...@@ -36,7 +28,7 @@ class Utils
* @param array $keys * @param array $keys
* @return array * @return array
*/ */
public static function findMatchingKeys (?array $elements, array $keys): array public function findMatchingKeys (?array $elements, array $keys): array
{ {
$matching = []; $matching = [];
...@@ -58,28 +50,10 @@ class Utils ...@@ -58,28 +50,10 @@ class Utils
* @return array * @return array
* Note : simply return all values of a multi-dimensional array. * Note : simply return all values of a multi-dimensional array.
*/ */
public static function getArrayValuesRecursive ($array) public function getArrayValuesRecursive ($array)
{
$values = [];
foreach ($array as $value) {
if (is_array($value)) {
// If value is an array, merge its values recursively
$values = array_merge($values, self::getArrayValuesRecursive($value));
} else {
// If value is not an array, add it to the result
$values[] = $value;
}
}
return $values;
}
/**
* @param string $text
* @return string
* Note : This come from jwtToken, as it is completely private - it is cloned here for now.
*/
public static function base64urlEncode (string $text): string
{ {
return str_replace(["+", "/", "="], ["A", "B", ""], base64_encode($text)); return array_reduce($array, function ($carry, $value) {
return array_merge($carry, is_array($value) ? $this->getArrayValuesRecursive($value) : [$value]);
}, []);
} }
} }
\ No newline at end of file
<?php
use FusionDirectory\Rest\WebServiceCall;
class Archive implements EndpointInterface
{
private TaskGateway $gateway;
public function __construct (TaskGateway $gateway)
{
$this->gateway = $gateway;
}
/**
* @return array
* Part of the interface of orchestrator plugin to treat GET method
*/
public function processEndPointGet (): array
{
// Retrieve tasks of type 'archive'
return $this->gateway->getObjectTypeTask('archive');
}
/**
* @param array|null $data
* @return array
* @throws Exception
* Note: Part of the interface of orchestrator plugin to treat PATCH method
*/
public function processEndPointPatch (array $data = NULL): array
{
$result = [];
$archiveTasks = $this->gateway->getObjectTypeTask('archive');
// Initialize the WebServiceCall object for login
$webServiceCall = new WebServiceCall($_ENV['FUSION_DIRECTORY_API_URL'] . '/login', 'POST');
$webServiceCall->setCurlSettings(); // Perform login and set the token
foreach ($archiveTasks as $task) {
try {
if (!$this->gateway->statusAndScheduleCheck($task)) {
// Skip this task if it does not meet the status and schedule criteria
continue;
}
// Receive null or 'toBeArchived'
$supannState = $this->getUserSupannAccountStatus($task['fdtasksgranulardn'][0]);
if ($supannState !== 'toBeArchived') {
// The task does not meet the criteria for archiving and can therefore be suppressed
$result[$task['dn']]['result'] = "User does not meet the criteria for archiving.";
$this->gateway->removeSubTask($task['dn']);
continue;
}
// Set the archive endpoint and method using the same WebServiceCall object
$archiveUrl = $_ENV['FUSION_DIRECTORY_API_URL'] . '/archive/user/' . rawurlencode($task['fdtasksgranulardn'][0]);
$webServiceCall->setCurlSettings($archiveUrl, NULL, 'POST'); // Update settings for the archive request
$response = $webServiceCall->execute();
// Check if the HTTP status code is 204
if ($webServiceCall->getHttpStatusCode() === 204) {
$result[$task['dn']]['result'] = "User successfully archived.";
$this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], '2');
} else {
throw new Exception("Unexpected HTTP status code: " . $webServiceCall->getHttpStatusCode());
}
} catch (Exception $e) {
$result[$task['dn']]['result'] = "Error archiving user: " . $e->getMessage();
$this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], $e->getMessage());
}
}
return $result;
}
/**
* @param array|null $data
* @return array
* Note: Part of the interface of orchestrator plugin to treat POST method
*/
public function processEndPointPost (array $data = NULL): array
{
return [];
}
/**
* @param array|null $data
* @return array
* Note: Part of the interface of orchestrator plugin to treat DELETE method
*/
public function processEndPointDelete (array $data = NULL): array
{
return [];
}
/**
* Retrieve the supannAccountStatus of a user
* @param string $userDn
* @return string|null
*/
private function getUserSupannAccountStatus (string $userDn): ?string
{
$supannState = $this->gateway->getLdapTasks(
'(objectClass=supannPerson)',
['supannRessourceEtatDate'],
'',
$userDn
);
if ($this->hasToBeArchived($supannState)) {
return 'toBeArchived';
}
return NULL;
}
private function hasToBeArchived (array $supannState): bool
{
if (!isset($supannState[0]['supannressourceetatdate']) || !is_array($supannState[0]['supannressourceetatdate'])) {
return FALSE;
}
foreach ($supannState[0]['supannressourceetatdate'] as $key => $value) {
// Skip non-numeric keys (e.g., 'count')
if (!is_numeric($key)) {
continue;
}
if (strpos($value, '{COMPTE}I:toBeArchived') !== FALSE) {
return TRUE;
}
}
return FALSE;
}
}
\ No newline at end of file
...@@ -4,10 +4,13 @@ class Audit implements EndpointInterface ...@@ -4,10 +4,13 @@ class Audit implements EndpointInterface
{ {
private TaskGateway $gateway; private TaskGateway $gateway;
private string $errorMessage = 'No audit requiring removal';
private Utils $utils;
public function __construct (TaskGateway $gateway) public function __construct (TaskGateway $gateway)
{ {
$this->gateway = $gateway; $this->gateway = $gateway;
$this->utils = new Utils();
} }
/** /**
...@@ -47,13 +50,12 @@ class Audit implements EndpointInterface ...@@ -47,13 +50,12 @@ class Audit implements EndpointInterface
$result = $this->processAuditDeletion($this->gateway->getObjectTypeTask('Audit')); $result = $this->processAuditDeletion($this->gateway->getObjectTypeTask('Audit'));
// Recursive function to filter out empty arrays at any depth // Recursive function to filter out empty arrays at any depth
$nonEmptyResults = Utils::recursiveArrayFilter($result); $filteredResults = $this->utils->recursiveArrayFilter($result);
if (!empty($nonEmptyResults)) { if (empty($filteredResults)) {
return $nonEmptyResults; return [$this->errorMessage];
} else {
return ['No audit requiring removal'];
} }
return $filteredResults;
} }
/** /**
...@@ -63,24 +65,22 @@ class Audit implements EndpointInterface ...@@ -63,24 +65,22 @@ class Audit implements EndpointInterface
*/ */
public function processAuditDeletion (array $auditSubTasks): array public function processAuditDeletion (array $auditSubTasks): array
{ {
$result = []; return array_values(array_map(fn($task) => $this->processScheduledTask($task), array_filter($auditSubTasks, fn($task) => $this->gateway->statusAndScheduleCheck($task))));
}
foreach ($auditSubTasks as $task) {
// If the tasks must be treated - status and scheduled - process the sub-tasks
if ($this->gateway->statusAndScheduleCheck($task)) {
// Retrieve data from the main task.
$auditMainTask = $this->getAuditMainTask($task['fdtasksgranularmaster'][0]);
// Simply get the days to retain audit.
$auditRetention = $auditMainTask[0]['fdaudittasksretention'][0];
// Verification of all audit and their potential removal based on retention days passed, also update subtasks.
$result[] = $this->checkAuditPassedRetention($auditRetention, $task['dn'], $task['cn'][0]);
}
}
return $result; /**
* @param array $task
* @return array
* @throws Exception
*/
private function processScheduledTask (array $task): array
{
// Retrieve data from the main task.
$auditMainTask = $this->getAuditMainTask($task['fdtasksgranularmaster'][0]);
// Simply get the days to retain audit.
$auditRetention = $auditMainTask[0]['fdaudittasksretention'][0];
// Verification of all audit and their potential removal based on retention days passed, also update subtasks.
return $this->checkAuditPassedRetention($auditRetention, $task['dn'], $task['cn'][0]);
} }
/** /**
......
...@@ -4,10 +4,12 @@ class Notifications implements EndpointInterface ...@@ -4,10 +4,12 @@ class Notifications implements EndpointInterface
{ {
private TaskGateway $gateway; private TaskGateway $gateway;
private Utils $utils;
public function __construct (TaskGateway $gateway) public function __construct (TaskGateway $gateway)
{ {
$this->gateway = $gateway; $this->gateway = $gateway;
$this->utils = new Utils();
} }
/** /**
...@@ -82,7 +84,7 @@ class Notifications implements EndpointInterface ...@@ -82,7 +84,7 @@ class Notifications implements EndpointInterface
$this->gateway->unsetCountKeys($monitoredSupannResource); $this->gateway->unsetCountKeys($monitoredSupannResource);
// Find matching attributes between audited and monitored attributes // Find matching attributes between audited and monitored attributes
$matchingAttrs = Utils::findMatchingKeys($auditAttributes, $monitoredAttrs); $matchingAttrs = $this->utils->findMatchingKeys($auditAttributes, $monitoredAttrs);
// Verify Supann resource state if applicable // Verify Supann resource state if applicable
if ($this->shouldVerifySupannResource($monitoredSupannResource, $auditAttributes)) { if ($this->shouldVerifySupannResource($monitoredSupannResource, $auditAttributes)) {
...@@ -183,7 +185,7 @@ class Notifications implements EndpointInterface ...@@ -183,7 +185,7 @@ class Notifications implements EndpointInterface
} }
// Get all the values only of a multidimensional array. // Get all the values only of a multidimensional array.
$auditedValues = Utils::getArrayValuesRecursive($auditedAttrs); $auditedValues = $this->utils->getArrayValuesRecursive($auditedAttrs);
if (in_array($monitoredSupannState, $auditedValues)) { if (in_array($monitoredSupannState, $auditedValues)) {
$result = TRUE; $result = TRUE;
......
...@@ -4,10 +4,12 @@ class Reminder implements EndpointInterface ...@@ -4,10 +4,12 @@ class Reminder implements EndpointInterface
{ {
private TaskGateway $gateway; private TaskGateway $gateway;
private ReminderTokenUtils $reminderTokenUtils;
public function __construct (TaskGateway $gateway) public function __construct (TaskGateway $gateway)
{ {
$this->gateway = $gateway; $this->gateway = $gateway;
$this->reminderTokenUtils = new ReminderTokenUtils();
} }
/** /**
...@@ -109,13 +111,13 @@ class Reminder implements EndpointInterface ...@@ -109,13 +111,13 @@ class Reminder implements EndpointInterface
$reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['uid'] = $task['fdtasksgranulardn'][0]; $reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['uid'] = $task['fdtasksgranulardn'][0];
// Create timeStamp expiration for token // Create timeStamp expiration for token
$tokenExpire = TokenUtils::getTokenExpiration($task['fdtasksgranularhelper'][0], $tokenExpire = $this->reminderTokenUtils->getTokenExpiration($task['fdtasksgranularhelper'][0],
$remindersMainTask[0]['fdtasksreminderfirstcall'][0], $remindersMainTask[0]['fdtasksreminderfirstcall'][0],
$remindersMainTask[0]['fdtasksremindersecondcall'][0]); $remindersMainTask[0]['fdtasksremindersecondcall'][0]);
// Create token for SubTask // Create token for SubTask
$token = TokenUtils::generateToken($task['fdtasksgranulardn'][0], $tokenExpire, $this->gateway); $token = $this->reminderTokenUtils->generateToken($task['fdtasksgranulardn'][0], $tokenExpire, $this->gateway);
// Edit the mailForm with the url link containing the token // Edit the mailForm with the url link containing the token
$tokenMailTemplateForm = TokenUtils::generateTokenUrl($token, $mailTemplateForm, $remindersMainTaskName); $tokenMailTemplateForm = $this->reminderTokenUtils->generateTokenUrl($token, $mailTemplateForm, $remindersMainTaskName);
// Recipient email form // Recipient email form
$reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['mail'] = $tokenMailTemplateForm; $reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['mail'] = $tokenMailTemplateForm;
...@@ -136,13 +138,13 @@ class Reminder implements EndpointInterface ...@@ -136,13 +138,13 @@ class Reminder implements EndpointInterface
$reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['uid'] = $task['fdtasksgranulardn'][0]; $reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['uid'] = $task['fdtasksgranulardn'][0];
// Create timeStamp expiration for token // Create timeStamp expiration for token
$tokenExpire = TokenUtils::getTokenExpiration($task['fdtasksgranularhelper'][0], $tokenExpire = $this->reminderTokenUtils->getTokenExpiration($task['fdtasksgranularhelper'][0],
$remindersMainTask[0]['fdtasksreminderfirstcall'][0], $remindersMainTask[0]['fdtasksreminderfirstcall'][0],
$remindersMainTask[0]['fdtasksremindersecondcall'][0]); $remindersMainTask[0]['fdtasksremindersecondcall'][0]);
// Create token for SubTask // Create token for SubTask
$token = TokenUtils::generateToken($task['fdtasksgranulardn'][0], $tokenExpire, $this->gateway); $token = $this->reminderTokenUtils->generateToken($task['fdtasksgranulardn'][0], $tokenExpire, $this->gateway);
// Edit the mailForm with the url link containing the token // Edit the mailForm with the url link containing the token
$tokenMailTemplateForm = TokenUtils::generateTokenUrl($token, $mailTemplateForm, $remindersMainTaskName); $tokenMailTemplateForm = $this->reminderTokenUtils->generateTokenUrl($token, $mailTemplateForm, $remindersMainTaskName);
// Recipient email form // Recipient email form
$reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['mail'] = $tokenMailTemplateForm; $reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['mail'] = $tokenMailTemplateForm;
......