From 1e392d609f9e970f1449b1d4db00de7582e853af Mon Sep 17 00:00:00 2001 From: nilsteampassnet Date: Mon, 16 Sep 2024 20:47:31 +0200 Subject: [PATCH] 3.1.2 Merged PRs #4329, #4327, #4325, #4323, #4322, #4321 (thank you @corentin-soriano, @kcbieng) --- includes/config/include.php | 2 +- .../src/AzureAuthController.php | 69 ++++++++++--------- includes/tables_integrity.json | 2 +- .../src/AzureAuthController.php | 46 ++++++------- 4 files changed, 62 insertions(+), 57 deletions(-) diff --git a/includes/config/include.php b/includes/config/include.php index 209f99894..119a7a59b 100755 --- a/includes/config/include.php +++ b/includes/config/include.php @@ -28,7 +28,7 @@ define('TP_VERSION', '3.1.2'); define("UPGRADE_MIN_DATE", "1724862801"); -define('TP_VERSION_MINOR', '79'); +define('TP_VERSION_MINOR', '80'); define('TP_TOOL_NAME', 'Teampass'); define('TP_ONE_DAY_SECONDS', 86400); define('TP_ONE_WEEK_SECONDS', 604800); diff --git a/includes/libraries/teampassclasses/azureauthcontroller/src/AzureAuthController.php b/includes/libraries/teampassclasses/azureauthcontroller/src/AzureAuthController.php index 71f9a2d3a..24171ec8f 100644 --- a/includes/libraries/teampassclasses/azureauthcontroller/src/AzureAuthController.php +++ b/includes/libraries/teampassclasses/azureauthcontroller/src/AzureAuthController.php @@ -47,28 +47,41 @@ class AzureAuthController public function __construct(array $settings) { - // Utilisation du point de terminaison v2.0 + // Initialize the settings property + $this->settings = $settings; + + // Multi-tenant is not allowed + if (empty($settings['oauth2_tenant_id']) || $settings['oauth2_tenant_id'] === 'common') { + throw new Exception('Invalid tenant_id provided. Multi-tenant access is not allowed.'); + } + + // Using the v2.0 endpoint $this->provider = new Azure([ 'clientId' => $settings['oauth2_client_id'], 'clientSecret' => $settings['oauth2_client_secret'], 'tenant' => $settings['oauth2_tenant_id'], 'redirectUri' => $settings['cpassman_url'].'/index.php?post_type=oauth2', - 'urlAuthorize' => 'https://login.microsoftonline.com/' . $settings['oauth2_tenant_id'] . '/oauth2/v2.0/authorize', // Utilisation du endpoint v2.0 - 'urlAccessToken' => 'https://login.microsoftonline.com/' . $settings['oauth2_tenant_id'] . '/oauth2/v2.0/token', // Endpoint v2.0 pour le token - 'urlResourceOwnerDetails' => 'https://graph.microsoft.com/v1.0/me', // Endpoint pour obtenir les infos de l'utilisateur - 'scopes' => explode(",", $settings['oauth2_client_scopes']), // Les scopes sont définis dans les paramètres - 'defaultEndPointVersion' => '2.0', // Version du point de terminaison + 'urlAuthorize' => 'https://login.microsoftonline.com/' . $settings['oauth2_tenant_id'] . '/oauth2/v2.0/authorize', // Using the v2.0 endpoint + 'urlAccessToken' => 'https://login.microsoftonline.com/' . $settings['oauth2_tenant_id'] . '/oauth2/v2.0/token', // v2.0 endpoint for the token + 'urlResourceOwnerDetails' => 'https://graph.microsoft.com/v1.0/me', // Endpoint to get user info + 'scopes' => explode(",", $settings['oauth2_client_scopes']), // Scopes are defined in the settings + 'defaultEndPointVersion' => '2.0', // Endpoint version ]); } public function redirect() { + // Force a unique tenant by refusing any other configuration + if ($this->settings['oauth2_tenant_id'] === 'common') { + throw new Exception('Multi-tenant access is not allowed. Tenant must be specified.'); + } + // Force user to select account $options = [ 'prompt' => 'select_account' ]; - // Rediriger l'utilisateur vers Azure AD pour l'authentification + // Redirect the user to Azure AD for authentication $authUrl = $this->provider->getAuthorizationUrl($options); $_SESSION['oauth2state'] = $this->provider->getState(); header('Location: ' . $authUrl); @@ -77,32 +90,29 @@ public function redirect() public function callback() { - // Vérification de l'état CSRF + // CSRF state verification if (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) { unset($_SESSION['oauth2state']); - exit('État invalide'); + exit('Invalid state'); } try { - // Échanger le code d'autorisation contre un token d'accès + // Exchange the authorization code for an access token $token = $this->provider->getAccessToken('authorization_code', [ 'code' => $_GET['code'] ]); - //error_log('Token récupéré : ' . print_r($token, true)); - // Récupérer les informations de l'utilisateur via Microsoft Graph + // Retrieve user information via Microsoft Graph $graphUrl = 'https://graph.microsoft.com/v1.0/me'; $response = $this->provider->getAuthenticatedRequest('GET', $graphUrl, $token->getToken()); $user = $this->provider->getParsedResponse($response); - //error_log('Utilisateur récupéré : ' . print_r($user, true)); - - // Récupérer les groupes auxquels l'utilisateur appartient + // Retrieve the groups the user belongs to $groupsUrl = 'https://graph.microsoft.com/v1.0/me/memberOf'; $groupsResponse = $this->provider->getAuthenticatedRequest('GET', $groupsUrl, $token->getToken()); $groups = $this->provider->getParsedResponse($groupsResponse); - // Extraire uniquement les IDs et noms des groupes si disponibles + // Extract only the IDs and names of the groups if available $userGroups = []; if (isset($groups['value']) && is_array($groups['value'])) { foreach ($groups['value'] as $group) { @@ -112,23 +122,18 @@ public function callback() ]; } } - //error_log('Utilisateur : ' . print_r(array_merge($user, array('groups' => $userGroups)), true)); - - // Get groups - //$groups = $this->getAllGroups($token); - //error_log('Groupes récupérés : ' . print_r($groups, true)); - // Retourner les informations de l'utilisateur + // Return user information return [ 'error' => false, 'userOauth2Info' => array_merge($user, array('groups' => $userGroups, 'oauth2TokenUsed' => false, 'oauth2LoginOngoing' => true)), ]; } catch (\Exception $e) { - error_log('Erreur inattendue : ' . $e->getMessage()); + error_log('Unexpected error: ' . $e->getMessage()); return [ 'error' => true, - 'message' => 'Erreur lors de la récupération du token : ' . $e->getMessage(), + 'message' => 'Error retrieving token: ' . $e->getMessage(), ]; } } @@ -137,32 +142,32 @@ public function getAllGroups($token = null) { try { if (is_null($token)) { - // Obtenir un token avec les scopes appropriés pour accéder aux groupes + // Obtain a token with the appropriate scopes to access groups $token = $this->provider->getAccessToken('authorization_code', [ 'code' => $_GET['code'], ]); } - // Faire une requête pour récupérer tous les groupes + // Make a request to retrieve all groups $graphUrl = 'https://graph.microsoft.com/v1.0/groups'; $response = $this->provider->getAuthenticatedRequest('GET', $graphUrl, $token->getToken()); $groupsResponse = $this->provider->getParsedResponse($response); - // Initialiser un tableau pour stocker les groupes avec id et displayName + // Initialize an array to store groups with id and displayName $groupsList = []; - // Vérifier si la réponse contient des groupes + // Check if the response contains groups if (isset($groupsResponse['value']) && is_array($groupsResponse['value'])) { foreach ($groupsResponse['value'] as $group) { - // Extraire l'ID et le displayName de chaque groupe + // Extract the ID and displayName of each group $groupsList[] = [ - 'id' => $group['id'] ?? null, // Utiliser l'opérateur null coalescent pour éviter les erreurs + 'id' => $group['id'] ?? null, // Use null coalescing operator to avoid errors 'displayName' => $group['displayName'] ?? null, ]; } } - // Retourner la liste des groupes avec id et displayName + // Return the list of groups with id and displayName return $groupsList; } catch (Exception $e) { @@ -172,4 +177,4 @@ public function getAllGroups($token = null) ]; } } -} \ No newline at end of file +} diff --git a/includes/tables_integrity.json b/includes/tables_integrity.json index a8f02c4fa..984037a37 100644 --- a/includes/tables_integrity.json +++ b/includes/tables_integrity.json @@ -17,7 +17,7 @@ }, { "table_name": "background_tasks_logs", - "structure_hash": "8a3d4f647da31132347a3dc30bca5245bfa1cf15227f3b32343c528fa31337c2" + "structure_hash": "23087506a1f802b8def361c9cf77ab7cca9b6f7508199ea3b8ab0194209b099a" }, { "table_name": "cache", diff --git a/vendor/teampassclasses/azureauthcontroller/src/AzureAuthController.php b/vendor/teampassclasses/azureauthcontroller/src/AzureAuthController.php index eb204cb7f..24171ec8f 100644 --- a/vendor/teampassclasses/azureauthcontroller/src/AzureAuthController.php +++ b/vendor/teampassclasses/azureauthcontroller/src/AzureAuthController.php @@ -55,17 +55,17 @@ public function __construct(array $settings) throw new Exception('Invalid tenant_id provided. Multi-tenant access is not allowed.'); } - // Utilisation du point de terminaison v2.0 + // Using the v2.0 endpoint $this->provider = new Azure([ 'clientId' => $settings['oauth2_client_id'], 'clientSecret' => $settings['oauth2_client_secret'], 'tenant' => $settings['oauth2_tenant_id'], 'redirectUri' => $settings['cpassman_url'].'/index.php?post_type=oauth2', - 'urlAuthorize' => 'https://login.microsoftonline.com/' . $settings['oauth2_tenant_id'] . '/oauth2/v2.0/authorize', // Utilisation du endpoint v2.0 - 'urlAccessToken' => 'https://login.microsoftonline.com/' . $settings['oauth2_tenant_id'] . '/oauth2/v2.0/token', // Endpoint v2.0 pour le token - 'urlResourceOwnerDetails' => 'https://graph.microsoft.com/v1.0/me', // Endpoint pour obtenir les infos de l'utilisateur - 'scopes' => explode(",", $settings['oauth2_client_scopes']), // Les scopes sont définis dans les paramètres - 'defaultEndPointVersion' => '2.0', // Version du point de terminaison + 'urlAuthorize' => 'https://login.microsoftonline.com/' . $settings['oauth2_tenant_id'] . '/oauth2/v2.0/authorize', // Using the v2.0 endpoint + 'urlAccessToken' => 'https://login.microsoftonline.com/' . $settings['oauth2_tenant_id'] . '/oauth2/v2.0/token', // v2.0 endpoint for the token + 'urlResourceOwnerDetails' => 'https://graph.microsoft.com/v1.0/me', // Endpoint to get user info + 'scopes' => explode(",", $settings['oauth2_client_scopes']), // Scopes are defined in the settings + 'defaultEndPointVersion' => '2.0', // Endpoint version ]); } @@ -81,7 +81,7 @@ public function redirect() 'prompt' => 'select_account' ]; - // Rediriger l'utilisateur vers Azure AD pour l'authentification + // Redirect the user to Azure AD for authentication $authUrl = $this->provider->getAuthorizationUrl($options); $_SESSION['oauth2state'] = $this->provider->getState(); header('Location: ' . $authUrl); @@ -90,29 +90,29 @@ public function redirect() public function callback() { - // Vérification de l'état CSRF + // CSRF state verification if (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) { unset($_SESSION['oauth2state']); - exit('État invalide'); + exit('Invalid state'); } try { - // Échanger le code d'autorisation contre un token d'accès + // Exchange the authorization code for an access token $token = $this->provider->getAccessToken('authorization_code', [ 'code' => $_GET['code'] ]); - // Récupérer les informations de l'utilisateur via Microsoft Graph + // Retrieve user information via Microsoft Graph $graphUrl = 'https://graph.microsoft.com/v1.0/me'; $response = $this->provider->getAuthenticatedRequest('GET', $graphUrl, $token->getToken()); $user = $this->provider->getParsedResponse($response); - // Récupérer les groupes auxquels l'utilisateur appartient + // Retrieve the groups the user belongs to $groupsUrl = 'https://graph.microsoft.com/v1.0/me/memberOf'; $groupsResponse = $this->provider->getAuthenticatedRequest('GET', $groupsUrl, $token->getToken()); $groups = $this->provider->getParsedResponse($groupsResponse); - // Extraire uniquement les IDs et noms des groupes si disponibles + // Extract only the IDs and names of the groups if available $userGroups = []; if (isset($groups['value']) && is_array($groups['value'])) { foreach ($groups['value'] as $group) { @@ -123,17 +123,17 @@ public function callback() } } - // Retourner les informations de l'utilisateur + // Return user information return [ 'error' => false, 'userOauth2Info' => array_merge($user, array('groups' => $userGroups, 'oauth2TokenUsed' => false, 'oauth2LoginOngoing' => true)), ]; } catch (\Exception $e) { - error_log('Erreur inattendue : ' . $e->getMessage()); + error_log('Unexpected error: ' . $e->getMessage()); return [ 'error' => true, - 'message' => 'Erreur lors de la récupération du token : ' . $e->getMessage(), + 'message' => 'Error retrieving token: ' . $e->getMessage(), ]; } } @@ -142,32 +142,32 @@ public function getAllGroups($token = null) { try { if (is_null($token)) { - // Obtenir un token avec les scopes appropriés pour accéder aux groupes + // Obtain a token with the appropriate scopes to access groups $token = $this->provider->getAccessToken('authorization_code', [ 'code' => $_GET['code'], ]); } - // Faire une requête pour récupérer tous les groupes + // Make a request to retrieve all groups $graphUrl = 'https://graph.microsoft.com/v1.0/groups'; $response = $this->provider->getAuthenticatedRequest('GET', $graphUrl, $token->getToken()); $groupsResponse = $this->provider->getParsedResponse($response); - // Initialiser un tableau pour stocker les groupes avec id et displayName + // Initialize an array to store groups with id and displayName $groupsList = []; - // Vérifier si la réponse contient des groupes + // Check if the response contains groups if (isset($groupsResponse['value']) && is_array($groupsResponse['value'])) { foreach ($groupsResponse['value'] as $group) { - // Extraire l'ID et le displayName de chaque groupe + // Extract the ID and displayName of each group $groupsList[] = [ - 'id' => $group['id'] ?? null, // Utiliser l'opérateur null coalescent pour éviter les erreurs + 'id' => $group['id'] ?? null, // Use null coalescing operator to avoid errors 'displayName' => $group['displayName'] ?? null, ]; } } - // Retourner la liste des groupes avec id et displayName + // Return the list of groups with id and displayName return $groupsList; } catch (Exception $e) {