Source

Target

View open merge request
Commits (23)
Showing with 313 additions and 79 deletions
+313 -79
.vendor/
.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:
project: ubuntu/focal-fusiondirectory-orchestrator-dev
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
switch ($objectType) {
case $objectType:
if (class_exists($objectType)) {
$endpoint = new $objectType;
$endpoint = new $objectType($this->gateway);
$result = $endpoint->processEndPointGet();
}
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
class TokenUtils
class ReminderTokenUtils
{
private function __construct ()
public function __construct ()
{
}
......@@ -12,7 +12,7 @@ class TokenUtils
* @return string
* @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;
// Salt has been generated with APG.
......@@ -25,10 +25,10 @@ class TokenUtils
$token_hmac = hash_hmac("sha256", $time . $payload, $_ENV["SECRET_KEY"], TRUE);
// 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
self::saveTokenInLdap($userDN, $token, $timeStamp, $gateway);
$this->saveTokenInLdap($userDN, $token, $timeStamp, $gateway);
return $token;
}
......@@ -41,7 +41,7 @@ class TokenUtils
* @return bool
* @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;
......@@ -64,17 +64,17 @@ class TokenUtils
// 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
self::createBranchToken($gateway);
$this->createBranchToken($gateway);
}
// The user token DN creation
$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.
if (self::tokenBranchExist($userTokenDN, $gateway)) {
if ($this->tokenBranchExist($userTokenDN, $gateway)) {
// Remove the user token
self::removeUserToken($userTokenDN, $gateway);
$this->removeUserToken($userTokenDN, $gateway);
}
// Add token to LDAP for specific UID
......@@ -95,7 +95,7 @@ class TokenUtils
* @return int
* 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.
$result = $secondCall;
......@@ -115,7 +115,7 @@ class TokenUtils
* @return void
* 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
try {
......@@ -130,7 +130,7 @@ class TokenUtils
* Create ou=pluginManager LDAP branch
* @throws Exception
*/
public static function createBranchToken (TaskGateway $gateway): void
private function createBranchToken (TaskGateway $gateway): void
{
try {
ldap_add(
......@@ -153,7 +153,7 @@ class TokenUtils
* @param string $taskDN
* @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 :
preg_match('/cn=([^,]+),ou=/', $taskDN, $matches);
......@@ -173,7 +173,7 @@ class TokenUtils
* @return bool
* 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;
......@@ -195,4 +195,14 @@ class TokenUtils
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 @@
class Utils
{
private function __construct ()
public function __construct ()
{
}
......@@ -11,22 +11,14 @@ class Utils
* @return array
* 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
$filtered = array_filter($array, function ($item) {
return array_filter($array, function ($item) {
if (is_array($item)) {
// Recursively filter the sub-array
$item = self::recursiveArrayFilter($item);
// Only retain non-empty arrays
return !empty($item);
} else {
// Retain non-empty scalar values
return !empty($item);
$item = $this->recursiveArrayFilter($item);
}
return !empty($item);
});
return $filtered;
}
/**
......@@ -36,7 +28,7 @@ class Utils
* @param array $keys
* @return array
*/
public static function findMatchingKeys (?array $elements, array $keys): array
public function findMatchingKeys (?array $elements, array $keys): array
{
$matching = [];
......@@ -58,28 +50,10 @@ class Utils
* @return array
* Note : simply return all values of a multi-dimensional array.
*/
public static 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
public function getArrayValuesRecursive ($array)
{
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,12 @@ class Audit implements EndpointInterface
{
private TaskGateway $gateway;
private Utils $utils;
public function __construct (TaskGateway $gateway)
{
$this->gateway = $gateway;
$this->utils = new Utils();
}
/**
......@@ -47,7 +49,7 @@ class Audit implements EndpointInterface
$result = $this->processAuditDeletion($this->gateway->getObjectTypeTask('Audit'));
// Recursive function to filter out empty arrays at any depth
$nonEmptyResults = Utils::recursiveArrayFilter($result);
$nonEmptyResults = $this->utils->recursiveArrayFilter($result);
if (!empty($nonEmptyResults)) {
return $nonEmptyResults;
......
......@@ -4,10 +4,12 @@
class Mail implements EndpointInterface
{
private TaskGateway $gateway;
private MailUtils $mailUtils;
function __construct (TaskGateway $gateway)
{
$this->gateway = $gateway;
$this->mailUtils = new MailUtils();
}
/**
......@@ -56,7 +58,7 @@ class Mail implements EndpointInterface
public function processMailTasks (array $tasks): array
{
$result = [];
$fdTasksConf = $this->getMailObjectConfiguration();
$fdTasksConf = $this->mailUtils->getMailObjectConfiguration($this->gateway);
$maxMailsConfig = $this->returnMaximumMailToBeSend($fdTasksConf);
// Increment for anti=spam, starts at 0, each mail task only contain one email, addition if simply + one.
......@@ -64,14 +66,12 @@ class Mail implements EndpointInterface
if ($this->verifySpamProtection($fdTasksConf)) {
// Note : if list_tasks is empty, the controller receive null as result and will log/process it properly.
foreach ($tasks as $mail) {
foreach ($tasks as $task) {
// verify status before processing (to be checked with schedule as well).
if ($mail["fdtasksgranularstatus"][0] == 1 && $this->gateway->verifySchedule($mail["fdtasksgranularschedule"][0])) {
if ($this->gateway->statusAndScheduleCheck($task)) {
// Search for the related attached mail object.
$mailInfos = $this->retrieveMailTemplateInfos($mail["fdtasksgranularref"][0]);
$mailInfos = $this->retrieveMailTemplateInfos($task["fdtasksgranularref"][0]);
$mailContent = $mailInfos[0];
// Only takes arrays related to files attachments for the mail template selected
......@@ -80,9 +80,9 @@ class Mail implements EndpointInterface
$this->gateway->unsetCountKeys($mailInfos);
$mailAttachments = array_values($mailInfos);
$setFrom = $mail["fdtasksgranularmailfrom"][0];
$setBCC = $mail["fdtasksgranularmailbcc"][0] ?? NULL;
$recipients = $mail["fdtasksgranularmail"];
$setFrom = $task["fdtasksgranularmailfrom"][0];
$setBCC = $task["fdtasksgranularmailbcc"][0] ?? NULL;
$recipients = $task["fdtasksgranularmail"];
$body = $mailContent["fdmailtemplatebody"][0];
$signature = $mailContent["fdmailtemplatesignature"][0] ?? NULL;
$subject = $mailContent["fdmailtemplatesubject"][0];
......@@ -99,35 +99,14 @@ class Mail implements EndpointInterface
$attachments = NULL;
}
$mail_controller = new \FusionDirectory\Mail\MailLib($setFrom,
$setBCC,
$recipients,
$body,
$signature,
$subject,
$receipt,
$attachments);
$mailSentResult = $mail_controller->sendMail();
if ($mailSentResult[0] == "SUCCESS") {
// The third arguments "2" is the status code of success for mail as of now 18/11/22
$result[$mail["dn"]]['statusUpdate'] = $this->gateway->updateTaskStatus($mail["dn"], $mail["cn"][0], "2");
$result[$mail["dn"]]['mailStatus'] = 'mail : ' . $mail["dn"] . ' was successfully sent';
$result[$mail["dn"]]['updateLastMailExec'] = $this->gateway->updateLastMailExecTime($fdTasksConf[0]["dn"]);
} else {
$result[$mail["dn"]]['statusUpdate'] = $this->gateway->updateTaskStatus($mail["dn"], $mail["cn"][0], $mailSentResult[0]);
$result[$mail["dn"]]['Error'] = $mailSentResult;
}
$mailSentResult = $this->mailUtils->sendMail($setFrom, $setBCC, $recipients, $body, $signature, $subject, $receipt, $attachments);
$result[$task["dn"]] = $this->updateResult($mailSentResult, $task, $fdTasksConf);
// Verification anti-spam max mails to be sent and quit loop if matched
$maxMailsIncrement += 1; //Only one as recipients in mail object is always one email.
if ($maxMailsIncrement == $maxMailsConfig) {
break;
}
}
}
}
......@@ -135,18 +114,24 @@ class Mail implements EndpointInterface
return $result;
}
/**
* @return array
* Note : A simple retrieval methods of the mail backend configuration set in FusionDirectory
*/
private function getMailObjectConfiguration (): array
private function updateResult (array $mailSentResult, $task, $fdTasksConf): array
{
return $this->gateway->getLdapTasks(
"(objectClass=fdTasksConf)",
["fdTasksConfLastExecTime", "fdTasksConfIntervalEmails", "fdTasksConfMaxEmails"]
);
$result = [];
if ($mailSentResult[0] == "SUCCESS") {
// The third arguments "2" is the status code of success for mail as of now 18/11/22
$result['statusUpdate'] = $this->gateway->updateTaskStatus($task["dn"], $task["cn"][0], "2");
$result['mailStatus'] = 'mail : ' . $task["dn"] . ' was successfully sent';
$result['updateLastMailExec'] = $this->gateway->updateLastMailExecTime($fdTasksConf[0]["dn"]);
} else {
$result['statusUpdate'] = $this->gateway->updateTaskStatus($task["dn"], $task["cn"][0], $mailSentResult[0]);
$result['Error'] = $mailSentResult;
}
return $result;
}
/**
* @param array $fdTasksConf
* @return int
......@@ -172,11 +157,7 @@ class Mail implements EndpointInterface
// Multiplication is required to have the seconds
$spamInterval = $spamInterval * 60;
$antispam = $lastExec + $spamInterval;
if ($antispam <= time()) {
return TRUE;
}
return FALSE;
return $antispam <= time();
}
/**
......@@ -188,5 +169,4 @@ class Mail implements EndpointInterface
{
return $this->gateway->getLdapTasks("(|(objectClass=fdMailTemplate)(objectClass=fdMailAttachments))", [], $templateName);
}
}
......@@ -4,10 +4,12 @@ class Notifications implements EndpointInterface
{
private TaskGateway $gateway;
private Utils $utils;
public function __construct (TaskGateway $gateway)
{
$this->gateway = $gateway;
$this->utils = new Utils();
}
/**
......@@ -82,7 +84,7 @@ class Notifications implements EndpointInterface
$this->gateway->unsetCountKeys($monitoredSupannResource);
// 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
if ($this->shouldVerifySupannResource($monitoredSupannResource, $auditAttributes)) {
......@@ -183,7 +185,7 @@ class Notifications implements EndpointInterface
}
// Get all the values only of a multidimensional array.
$auditedValues = Utils::getArrayValuesRecursive($auditedAttrs);
$auditedValues = $this->utils->getArrayValuesRecursive($auditedAttrs);
if (in_array($monitoredSupannState, $auditedValues)) {
$result = TRUE;
......
......@@ -4,10 +4,12 @@ class Reminder implements EndpointInterface
{
private TaskGateway $gateway;
private ReminderTokenUtils $reminderTokenUtils;
public function __construct (TaskGateway $gateway)
{
$this->gateway = $gateway;
$this->reminderTokenUtils = new ReminderTokenUtils();
}
/**
......@@ -109,13 +111,13 @@ class Reminder implements EndpointInterface
$reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['uid'] = $task['fdtasksgranulardn'][0];
// Create timeStamp expiration for token
$tokenExpire = TokenUtils::getTokenExpiration($task['fdtasksgranularhelper'][0],
$tokenExpire = $this->reminderTokenUtils->getTokenExpiration($task['fdtasksgranularhelper'][0],
$remindersMainTask[0]['fdtasksreminderfirstcall'][0],
$remindersMainTask[0]['fdtasksremindersecondcall'][0]);
// 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
$tokenMailTemplateForm = TokenUtils::generateTokenUrl($token, $mailTemplateForm, $remindersMainTaskName);
$tokenMailTemplateForm = $this->reminderTokenUtils->generateTokenUrl($token, $mailTemplateForm, $remindersMainTaskName);
// Recipient email form
$reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['mail'] = $tokenMailTemplateForm;
......@@ -136,13 +138,13 @@ class Reminder implements EndpointInterface
$reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['uid'] = $task['fdtasksgranulardn'][0];
// Create timeStamp expiration for token
$tokenExpire = TokenUtils::getTokenExpiration($task['fdtasksgranularhelper'][0],
$tokenExpire = $this->reminderTokenUtils->getTokenExpiration($task['fdtasksgranularhelper'][0],
$remindersMainTask[0]['fdtasksreminderfirstcall'][0],
$remindersMainTask[0]['fdtasksremindersecondcall'][0]);
// 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
$tokenMailTemplateForm = TokenUtils::generateTokenUrl($token, $mailTemplateForm, $remindersMainTaskName);
$tokenMailTemplateForm = $this->reminderTokenUtils->generateTokenUrl($token, $mailTemplateForm, $remindersMainTaskName);
// Recipient email form
$reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['mail'] = $tokenMailTemplateForm;
......