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 @@
+