diff --git a/datamodels/2.x/itop-oauth-client/assets/js/oauth_connect.js b/datamodels/2.x/itop-oauth-client/assets/js/oauth_connect.js index 6b8b6c801..7b0635b33 100644 --- a/datamodels/2.x/itop-oauth-client/assets/js/oauth_connect.js +++ b/datamodels/2.x/itop-oauth-client/assets/js/oauth_connect.js @@ -92,6 +92,8 @@ const OAuthConnect = function(sClass, sId, sAjaxUri) { function (oData) { if (oData.status === 'success') { oOpenSignInWindow(oData.data.authorization_url, 'OAuth authorization') + } else { + CombodoModal.OpenErrorModal(oData.error_description); } } ); diff --git a/datamodels/2.x/itop-oauth-client/datamodel.itop-oauth-client.xml b/datamodels/2.x/itop-oauth-client/datamodel.itop-oauth-client.xml index 416ded52e..f05f956a3 100644 --- a/datamodels/2.x/itop-oauth-client/datamodel.itop-oauth-client.xml +++ b/datamodels/2.x/itop-oauth-client/datamodel.itop-oauth-client.xml @@ -380,6 +380,11 @@ HTML no true + + tenant + common + false +
@@ -405,15 +410,18 @@ HTML 50 - + 60 - + 70 - + 80 + + 90 + diff --git a/datamodels/2.x/itop-oauth-client/dictionaries/en.dict.itop-oauth-client.php b/datamodels/2.x/itop-oauth-client/dictionaries/en.dict.itop-oauth-client.php index 2b179f0de..05a7b2237 100644 --- a/datamodels/2.x/itop-oauth-client/dictionaries/en.dict.itop-oauth-client.php +++ b/datamodels/2.x/itop-oauth-client/dictionaries/en.dict.itop-oauth-client.php @@ -93,6 +93,8 @@ Dict::Add('EN US', 'English', 'English', array( 'Class:OAuthClientAzure/Attribute:used_for_smtp+' => 'At least one OAuth client must have this flag to “Yes”, if you want iTop to use it for sending mails', 'Class:OAuthClientAzure/Attribute:used_for_smtp/Value:yes' => 'Yes', 'Class:OAuthClientAzure/Attribute:used_for_smtp/Value:no' => 'No', + 'Class:OAuthClientAzure/Attribute:tenant' => 'Tenant', + 'Class:OAuthClientAzure/Attribute:tenant+' => 'Tenant ID of the configured application. For multi-tenant application, use "common".', )); // diff --git a/datamodels/2.x/itop-oauth-client/src/Controller/AjaxOauthClientController.php b/datamodels/2.x/itop-oauth-client/src/Controller/AjaxOauthClientController.php index ab1fab9da..dd6f79e27 100644 --- a/datamodels/2.x/itop-oauth-client/src/Controller/AjaxOauthClientController.php +++ b/datamodels/2.x/itop-oauth-client/src/Controller/AjaxOauthClientController.php @@ -10,6 +10,7 @@ use cmdbAbstractObject; use Combodo\iTop\Application\TwigBase\Controller\Controller; use Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory; use Dict; +use Exception; use IssueLog; use League\OAuth2\Client\Provider\Exception\IdentityProviderException; use MetaModel; @@ -32,8 +33,13 @@ class AjaxOauthClientController extends Controller $aResult = ['status' => 'success', 'data' => []]; - $sAuthorizationUrl = OAuthClientProviderFactory::GetAuthorizationUrl($oOAuthClient); - $aResult['data']['authorization_url'] = $sAuthorizationUrl; + try { + $sAuthorizationUrl = OAuthClientProviderFactory::GetAuthorizationUrl($oOAuthClient); + $aResult['data']['authorization_url'] = $sAuthorizationUrl; + } catch (Exception $oException) { + $aResult['status'] = 'error'; + $aResult['error_description'] = $oException->getMessage(); + } $this->DisplayJSONPage($aResult); } diff --git a/sources/Application/TwigBase/Controller/Controller.php b/sources/Application/TwigBase/Controller/Controller.php index a8377daf6..465eb3c04 100644 --- a/sources/Application/TwigBase/Controller/Controller.php +++ b/sources/Application/TwigBase/Controller/Controller.php @@ -256,6 +256,7 @@ abstract class Controller extends AbstractController } /** + * @since 3.0.0 N°3606 - Adapt TwigBase Controller for combodo-monitoring extension * @throws \Exception */ protected function CheckAccess() @@ -271,12 +272,23 @@ abstract class Controller extends AbstractController if (empty($sExecModule) || empty($sConfiguredAccessTokenValue)){ LoginWebPage::DoLogin($this->m_bMustBeAdmin); - }else { + } else { //token mode without login required - $sPassedToken = utils::ReadParam($this->m_sAccessTokenConfigParamId, null); - if ($sPassedToken !== $sConfiguredAccessTokenValue){ + //N°7147 - Error HTTP 500 due to access_token not URL decoded + $sPassedToken = utils::ReadPostedParam($this->m_sAccessTokenConfigParamId, null, false, 'raw_data'); + if (is_null($sPassedToken)){ + $sPassedToken = utils::ReadParam($this->m_sAccessTokenConfigParamId, null, false, 'raw_data'); + } + + $sDecodedPassedToken = urldecode($sPassedToken); + if ($sDecodedPassedToken !== $sConfiguredAccessTokenValue){ $sMsg = "Invalid token passed under '$this->m_sAccessTokenConfigParamId' http param to reach '$sExecModule' page."; - IssueLog::Error($sMsg); + IssueLog::Error($sMsg, null, + [ + 'sHtmlDecodedToken' => $sDecodedPassedToken, + 'conf param ID' => $this->m_sAccessTokenConfigParamId + ] + ); throw new Exception("Invalid token"); } } diff --git a/sources/Core/Authentication/Client/OAuth/OAuthClientProviderAzure.php b/sources/Core/Authentication/Client/OAuth/OAuthClientProviderAzure.php index 667d5875a..e77141d72 100644 --- a/sources/Core/Authentication/Client/OAuth/OAuthClientProviderAzure.php +++ b/sources/Core/Authentication/Client/OAuth/OAuthClientProviderAzure.php @@ -20,8 +20,9 @@ class OAuthClientProviderAzure extends OAuthClientProviderAbstract 'clientId' => $oOAuthClient->Get('client_id'), 'clientSecret' => $oOAuthClient->Get('client_secret'), 'redirectUri' => $oOAuthClient->Get('redirect_url'), + 'tenant' => $oOAuthClient->Get('tenant'), ]; $this->oVendorProvider = new Azure($aOptions, $collaborators); } -} \ No newline at end of file +} diff --git a/tests/php-unit-tests/unitary-tests/application/twigbase/ControllerTest.php b/tests/php-unit-tests/unitary-tests/application/twigbase/ControllerTest.php new file mode 100644 index 000000000..9a6c82804 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/application/twigbase/ControllerTest.php @@ -0,0 +1,75 @@ +RequireOnceUnitTestFile('FakeController.php'); + } + + public function CheckAccessProvider() { + return [ + 'simple token access OK' => [ + 'access_token' => 'toto123', + 'http_access_token' => 'toto123', + 'bSuccess' => true, + ], + 'simple token access OK sent by POST' => [ + 'access_token' => 'toto123', + 'http_access_token' => 'toto123', + 'bSuccess' => true, + 'bPost' => true, + ], + 'simple token access FAILED' => [ + 'access_token' => 'toto123', + 'http_access_token' => 'toto124', + 'bSuccess' => false, + ], + 'url encoded token access OK' => [ + 'access_token' => 'rfb4j"E?7}-ZJq4T^B*26pk8{;zxem', + 'http_access_token' => 'rfb4j%22E%3F7%7D-ZJq4T%5EB%2A26pk8%7B%3Bzxem', + 'bSuccess' => true, + ], + ]; + } + + /** + * Fix N°7147 + * @dataProvider CheckAccessProvider + */ + public function testCheckAccess($sConfiguredAccessToken, $sHttpAccessToken, $bSuccess, $bPost=false){ + $sModuleName = "MyModule"; + $sTokenParamName = "access_token_conf_param"; + + $_SESSION = []; + $_POST = []; + $_REQUEST = []; + + $_REQUEST['exec_module'] = $sModuleName; + if ($bPost){ + $_POST[$sTokenParamName] = $sHttpAccessToken; + } else { + $_REQUEST[$sTokenParamName] = $sHttpAccessToken; + } + + $oController = new FakeController(); + $oController->SetAccessTokenConfigParamId($sTokenParamName); + + MetaModel::GetConfig()->SetModuleSetting($sModuleName, $sTokenParamName, $sConfiguredAccessToken); + + if (! $bSuccess){ + $this->expectExceptionMessage("Invalid token"); + } + + $this->InvokeNonPublicMethod(FakeController::class, "CheckAccess", $oController); + + if ($bSuccess){ + $this->assertTrue(true, "no issue encountered"); + } + } +} diff --git a/tests/php-unit-tests/unitary-tests/application/twigbase/FakeController.php b/tests/php-unit-tests/unitary-tests/application/twigbase/FakeController.php new file mode 100644 index 000000000..262e0d8dd --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/application/twigbase/FakeController.php @@ -0,0 +1,5 @@ +