Skip to content

Commit 84f3c3f

Browse files
authored
Merge pull request #396 from magento-performance/cabpi-197-admin-logout
CABPI-197 admin logout
2 parents 0d746ef + 590a806 commit 84f3c3f

File tree

8 files changed

+259
-11
lines changed

8 files changed

+259
-11
lines changed

app/code/Magento/AdminAdobeIms/Model/Auth.php

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414

1515
class Auth extends BackendAuth
1616
{
17+
/**
18+
* @var string
19+
*/
20+
private string $errorMessage = 'The account sign-in was incorrect or your account is disabled temporarily. '
21+
. 'Please wait and try again later.';
22+
1723
/**
1824
* Perform login process without password
1925
*
@@ -26,10 +32,7 @@ public function loginByUsername(string $username): void
2632
{
2733
if (empty($username)) {
2834
self::throwException(
29-
__(
30-
'The account sign-in was incorrect or your account is disabled temporarily. '
31-
. 'Please wait and try again later.'
32-
)
35+
__($this->errorMessage)
3336
);
3437
}
3538

@@ -48,10 +51,7 @@ public function loginByUsername(string $username): void
4851

4952
if (!$this->getAuthStorage()->getUser()) {
5053
self::throwException(
51-
__(
52-
'The account sign-in was incorrect or your account is disabled temporarily. '
53-
. 'Please wait and try again later.'
54-
)
54+
__($this->errorMessage)
5555
);
5656
}
5757
} catch (PluginAuthenticationException $e) {
@@ -67,8 +67,7 @@ public function loginByUsername(string $username): void
6767
);
6868
self::throwException(
6969
__(
70-
$e->getMessage()? : 'The account sign-in was incorrect or your account is disabled temporarily. '
71-
. 'Please wait and try again later.'
70+
$e->getMessage()? : $this->errorMessage
7271
)
7372
);
7473
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\AdminAdobeIms\Model;
9+
10+
use Magento\AdminAdobeIms\Exception\AdobeImsTokenAuthorizationException;
11+
use Magento\AdobeImsApi\Api\FlushUserTokensInterface;
12+
use Magento\AdobeImsApi\Api\GetAccessTokenInterface;
13+
use Magento\AdminAdobeIms\Service\ImsConfig;
14+
use Magento\AdobeImsApi\Api\LogOutInterface;
15+
use Magento\Framework\Exception\AuthorizationException;
16+
use Magento\Framework\Exception\LocalizedException;
17+
use Magento\Framework\HTTP\Client\CurlFactory;
18+
use Magento\AdminAdobeIms\Model\ImsConnection;
19+
use Psr\Log\LoggerInterface;
20+
21+
/**
22+
* Represent functionality for log out users from the Adobe account
23+
*/
24+
class LogOut implements LogOutInterface
25+
{
26+
/**
27+
* Successful result code.
28+
*/
29+
private const HTTP_OK = 200;
30+
31+
/**
32+
* @var LoggerInterface
33+
*/
34+
private $logger;
35+
36+
/**
37+
* @var CurlFactory
38+
*/
39+
private $curlFactory;
40+
41+
/**
42+
* @var GetAccessTokenInterface
43+
*/
44+
private $getAccessToken;
45+
46+
/**
47+
* @var FlushUserTokensInterface
48+
*/
49+
private $flushUserTokens;
50+
/**
51+
* @var ImsConfig
52+
*/
53+
private ImsConfig $imsConfig;
54+
/**
55+
* @var ImsConnection
56+
*/
57+
private ImsConnection $imsConnection;
58+
59+
/**
60+
* @param LoggerInterface $logger
61+
* @param ImsConfig $imsConfig
62+
* @param CurlFactory $curlFactory
63+
* @param GetAccessTokenInterface $getAccessToken
64+
* @param FlushUserTokensInterface $flushUserTokens
65+
* @param ImsConnection $imsConnection
66+
*/
67+
public function __construct(
68+
LoggerInterface $logger,
69+
ImsConfig $imsConfig,
70+
CurlFactory $curlFactory,
71+
GetAccessTokenInterface $getAccessToken,
72+
FlushUserTokensInterface $flushUserTokens,
73+
ImsConnection $imsConnection
74+
) {
75+
$this->logger = $logger;
76+
$this->curlFactory = $curlFactory;
77+
$this->getAccessToken = $getAccessToken;
78+
$this->flushUserTokens = $flushUserTokens;
79+
$this->imsConfig = $imsConfig;
80+
$this->imsConnection = $imsConnection;
81+
}
82+
83+
/**
84+
* @inheritDoc
85+
*/
86+
public function execute() : bool
87+
{
88+
try {
89+
$accessToken = $this->getAccessToken->execute();
90+
91+
if (empty($accessToken)) {
92+
return true;
93+
}
94+
95+
$this->externalLogOut($accessToken);
96+
$this->flushUserTokens->execute();
97+
return true;
98+
} catch (\Exception $exception) {
99+
$this->logger->critical($exception);
100+
return false;
101+
}
102+
}
103+
104+
/**
105+
* Logout user from Adobe IMS
106+
*
107+
* @param string $accessToken
108+
* @throws LocalizedException
109+
*/
110+
private function externalLogOut(string $accessToken): void
111+
{
112+
if (!$this->checkUserProfile($accessToken)) {
113+
throw new LocalizedException(
114+
__('An error occurred during logout operation.')
115+
);
116+
}
117+
$curl = $this->curlFactory->create();
118+
119+
$curl->addHeader('Content-Type', 'application/x-www-form-urlencoded');
120+
$curl->addHeader('cache-control', 'no-cache');
121+
122+
$curl->post(
123+
$this->imsConfig->getBackendLogoutUrl($accessToken),
124+
[]
125+
);
126+
127+
if ($curl->getStatus() !== self::HTTP_OK || ($this->checkUserProfile($accessToken))) {
128+
throw new LocalizedException(
129+
__('An error occurred during logout operation.')
130+
);
131+
}
132+
}
133+
134+
/**
135+
* Checks whether user profile could be got by the access token
136+
* - If the token is invalidated, profile information won't be returned
137+
*
138+
* @param string $accessToken
139+
* @return bool
140+
* @throws AuthorizationException
141+
*/
142+
private function checkUserProfile(string $accessToken): bool
143+
{
144+
try {
145+
$profile = $this->imsConnection->getProfile($accessToken);
146+
if (!empty($profile['email'])) {
147+
return true;
148+
}
149+
} catch (AdobeImsTokenAuthorizationException $exception) {
150+
return false;
151+
}
152+
return false;
153+
}
154+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\AdminAdobeIms\Observer;
10+
11+
use Magento\AdminAdobeIms\Model\LogOut;
12+
use Magento\Framework\Event\Observer;
13+
use Magento\Framework\Event\ObserverInterface;
14+
15+
class AdminLogoutObserver implements ObserverInterface
16+
{
17+
/**
18+
* @var LogOut
19+
*/
20+
private LogOut $logOut;
21+
22+
/**
23+
* @param LogOut $logOut
24+
*/
25+
public function __construct(
26+
LogOut $logOut
27+
) {
28+
$this->logOut = $logOut;
29+
}
30+
31+
/**
32+
* Perform logout action
33+
*
34+
* @param Observer $observer
35+
* @return $this
36+
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
37+
*/
38+
public function execute(Observer $observer)
39+
{
40+
$this->logOut->execute();
41+
return $this;
42+
}
43+
}

app/code/Magento/AdminAdobeIms/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,20 @@ The layout file `view/adminhtml/layout/adobe_ims_login.xml` adds:
7474

7575
We have included the minified css and the used svgs from Spectrum CSS with our module, but you can also use npm to install the latest versions.
7676
To rebuild the minified css run the command `./node_modules/.bin/postcss -o dist/index.min.css index.css` after npm install from inside the web directory.
77+
78+
# Admin Backend Login
79+
80+
Login with the help Adobe IMS Service is implemented. The redirect to Adobe IMS Service is performed-
81+
The redirect from Adobe IMS is done to \Magento\AdminAdobeIms\Controller\Adminhtml\OAuth\ImsCallback controller.
82+
83+
The access code comes from Adobe, the token response is got on the basis of the access code,
84+
client id (api key) and client secret (private key).
85+
The token response access taken is used for getting user profile information.
86+
If this is successful, the admin user will be logged in and the access and refresh tokens are saved in the `adobe_user_profile` table.
87+
88+
# Admin Backend Logout
89+
90+
The logout from Adobe IMS Service is performed when Magento Admin User is logged out.
91+
It's triggered by the event `controller_action_predispatch_adminhtml_auth_logout`
92+
93+
Token is invalidated with a call, if it's successful, the access and refresh token are deleted in the `adobe_user_profile` table.

app/code/Magento/AdminAdobeIms/Service/ImsConfig.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class ImsConfig extends Config
2626
public const XML_PATH_AUTH_URL_PATTERN = 'adobe_ims/integration/auth_url_pattern';
2727
public const XML_PATH_PROFILE_URL = 'adobe_ims/integration/profile_url';
2828
private const OAUTH_CALLBACK_URL = 'adobe_ims_auth/oauth/';
29+
public const XML_PATH_LOGOUT_URL = 'adobe_ims/integration/logout_url';
2930

3031
/**
3132
* @var ScopeConfigInterface
@@ -132,7 +133,6 @@ public function disableModule(): void
132133
}
133134

134135
/**
135-
* Update config
136136
* Get Profile URL
137137
*
138138
* @return string
@@ -147,6 +147,8 @@ public function getProfileUrl(): string
147147
}
148148

149149
/**
150+
* Update config using config writer
151+
*
150152
* @param string $path
151153
* @param string $value
152154
* @return void
@@ -232,6 +234,21 @@ private function getLocale(): string
232234
return $this->scopeConfig->getValue(Custom::XML_PATH_GENERAL_LOCALE_CODE);
233235
}
234236

237+
/**
238+
* Get BackendLogout URL
239+
*
240+
* @param string $accessToken
241+
* @return string
242+
*/
243+
public function getBackendLogoutUrl(string $accessToken) : string
244+
{
245+
return str_replace(
246+
['#{access_token}', '#{client_secret}', '#{client_id}'],
247+
[$accessToken, $this->getPrivateKey(), $this->getApiKey()],
248+
$this->scopeConfig->getValue(self::XML_PATH_LOGOUT_URL)
249+
);
250+
}
251+
235252
/**
236253
* Retrieve Organization Id
237254
*

app/code/Magento/AdminAdobeIms/Test/Unit/Model/ImsConnectionTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ class ImsConnectionTest extends TestCase
2828

2929
private const AUTH_URL_ERROR = 'https://adobe-login-url.com/authorize?error=invalid_scope';
3030

31+
/**
32+
* @var CurlFactory
33+
*/
34+
private $curlFactory;
35+
3136
/**
3237
* @var ImsConnection
3338
*/

app/code/Magento/AdminAdobeIms/etc/config.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<auth_url_pattern><![CDATA[https://ims-na1-stg1.adobelogin.com/ims/authorize/v2?client_id=#{client_id}&amp;redirect_uri=#{redirect_uri}&amp;locale=#{locale}&amp;scope=openid,creative_sdk,email,profile,additional_info,additional_info.roles&amp;response_type=code]]></auth_url_pattern>
1515
<token_url>https://ims-na1-stg1.adobelogin.com/ims/token</token_url>
1616
<profile_url><![CDATA[https://ims-na1-stg1.adobelogin.com/ims/profile/v1?client_id=#{client_id}]]></profile_url>
17+
<logout_url><![CDATA[https://ims-na1-stg1.adobelogin.com/ims/logout/v1?access_token=#{access_token}&amp;client_id=#{client_id}&amp;client_secret=#{client_secret}]]></logout_url>
1718
</integration>
1819
</adobe_ims>
1920
</default>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
9+
<event name="controller_action_predispatch_adminhtml_auth_logout">
10+
<observer name="admin_adobe_ims_observer" instance="Magento\AdminAdobeIms\Observer\AdminLogoutObserver" />
11+
</event>
12+
</config>

0 commit comments

Comments
 (0)