Skip to content

Commit

Permalink
Merge pull request #50 from vippsas/publication-2.4.13
Browse files Browse the repository at this point in the history
Fix an issue with parallel sign-in requests
  • Loading branch information
voleye authored Nov 27, 2023
2 parents e9e05b0 + f8ab246 commit ab5e265
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 9 deletions.
34 changes: 34 additions & 0 deletions Controller/Login/Redirect.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
*/
class Redirect implements ActionInterface
{
private const RETRY_OBTAIN_TOKEN_COUNTER = 3;

/**
* @var SessionManagerInterface|Session
*/
Expand Down Expand Up @@ -122,6 +124,9 @@ public function execute()
{
$code = $this->request->getParam('code');
$state = $this->request->getParam('state');

$this->customerSession->setData(StateKey::DATA_KEY_STATE, $state);

$resultRedirect = $this->resultRedirectFactory->create();

try {
Expand All @@ -141,6 +146,14 @@ public function execute()
// get token
$token = $this->tokenCommand->execute($code);

if (!$this->checkAttempts($token)) {
throw new LocalizedException(__('Can not obtain access token.'));
}

if (!$token) {
return $resultRedirect->setPath('vipps/login/redirect', ['code' => $code, 'state' => $state]);
}

// remember token
$this->storeToken($token);

Expand All @@ -159,6 +172,27 @@ public function execute()
return $resultRedirect->setPath('vipps/login/error');
}

/**
* @param string $token
*
* @return bool
*/
private function checkAttempts($token)
{
if ($token) {
$this->customerSession->setData('retry_obtain_token_counter', null);

return true;
}

$value = (int) ($this->customerSession->getData('retry_obtain_token_counter') ?? 0);
$value = $value > self::RETRY_OBTAIN_TOKEN_COUNTER ? 0 : $value;

$this->customerSession->setData('retry_obtain_token_counter', ++$value);

return !($value > self::RETRY_OBTAIN_TOKEN_COUNTER);
}

/**
* Save access token and vipps ID token in customer session data.
*
Expand Down
83 changes: 76 additions & 7 deletions Gateway/Command/TokenCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

namespace Vipps\Login\Gateway\Command;

use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Serialize\SerializerInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\HTTP\ClientFactory;
Expand Down Expand Up @@ -70,29 +71,35 @@ class TokenCommand
private $logger;

/**
* TokenCommand constructor.
*
* @var ResourceConnection
*/
private $resourceConnection;

/**
* @param ConfigInterface $config
* @param SerializerInterface $serializer
* @param ApiEndpointsInterface $apiEndpoints
* @param ClientFactory $httpClientFactory
* @param UrlInterface $url
* @param LoggerInterface $logger
* @param ResourceConnection $resourceConnection
*/
public function __construct(
ConfigInterface $config,
SerializerInterface $serializer,
ApiEndpointsInterface $apiEndpoints,
ClientFactory $httpClientFactory,
UrlInterface $url,
LoggerInterface $logger
LoggerInterface $logger,
ResourceConnection $resourceConnection
) {
$this->config = $config;
$this->httpClientFactory = $httpClientFactory;
$this->apiEndpoints = $apiEndpoints;
$this->serializer = $serializer;
$this->url = $url;
$this->logger = $logger;
$this->resourceConnection = $resourceConnection;
}

/**
Expand All @@ -105,6 +112,15 @@ public function __construct(
*/
public function execute($code)
{
$authRecord = $this->fetchAuthorizationRecord($code);
if (!$authRecord) {
return null;
}

if (isset($authRecord['payload'])) {
return $this->prepareResponse($authRecord['payload']);
}

$clientId = $this->config->getLoginClientId();
$clientSecret = $this->config->getLoginClientSecret();

Expand All @@ -119,17 +135,70 @@ public function execute($code)
'redirect_uri' => trim($this->url->getUrl('vipps/login/redirect'), '/')
]);

$token = $this->serializer->unserialize($httpClient->getBody());
$payload = $this->getPayload($token);
$this->storeAuthorizationRecord($code, $httpClient->getBody());

$token['id_token_payload'] = $payload;
return $token;
return $this->prepareResponse($httpClient->getBody());
} catch (\Exception $e) {
$this->logger->critical($e);
throw new LocalizedException(__('An error occurred trying to get token'), $e);
}
}

private function fetchAuthorizationRecord($code): ?array
{
$connection = $this->resourceConnection->getConnection('write');
$connection->delete(
$connection->getTableName('vipps_login_authorization'),
\sprintf('created_at < %s', $connection->quote((new \DateTime())->modify('-5 min')->format('Y-m-d H:i-s')))
);

$select = $connection->select()
->from($connection->getTableName('vipps_login_authorization'))
->where('code = ?', $code);

$row = $connection->fetchRow($select);
if (!$row) {
try {
$connection->insert(
$connection->getTableName('vipps_login_authorization'),
[
'code' => $code,
'created_at' => (new \DateTime())->format('Y-m-d H:i:s'),
]
);

$row = $connection->fetchRow($select);
} catch (\Throwable $t) {
return null;
}
}

return $row;
}

private function storeAuthorizationRecord($code, $payload)
{
$connection = $this->resourceConnection->getConnection('write');

return $connection->update(
$connection->getTableName('vipps_login_authorization'),
[
'payload' => $payload
],
'code = ' . $connection->quote($code)
);
}

private function prepareResponse($body): array
{
$token = $this->serializer->unserialize($body);
$payload = $this->getPayload($token);

$token['id_token_payload'] = $payload;

return $token;
}

/**
* @param $token
*
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"psr/log": "~1.0"
},
"type": "magento2-module",
"version": "2.4.12",
"version": "2.4.13",
"license": [
"OSL-3.0",
"AFL-3.0"
Expand Down
16 changes: 16 additions & 0 deletions etc/db_schema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,20 @@
table="vipps_quote_addresses_relation" column="vipps_customer_address_id" referenceTable="vipps_customer_address"
referenceColumn="entity_id" onDelete="CASCADE"/>
</table>

<table name="vipps_login_authorization" resource="default" engine="innodb" comment="Vipps Login Authorization Table">
<column xsi:type="int" name="entity_id" unsigned="true" nullable="false" identity="true"
comment="Entity ID"/>
<column xsi:type="varchar" name="code" nullable="false" length="255" comment="code"/>
<column xsi:type="text" name="payload" nullable="true" comment="Payload"/>
<column xsi:type="datetime" name="created_at" nullable="true" comment="Creation Date"/>

<constraint xsi:type="primary" referenceId="PRIMARY">
<column name="entity_id"/>
</constraint>

<constraint xsi:type="unique" referenceId="VIPPS_LOGIN_AUTHORIZATION_CODE_UNIQUE">
<column name="code"/>
</constraint>
</table>
</schema>
12 changes: 12 additions & 0 deletions etc/db_schema_whitelist.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,17 @@
"VIPPS_QUOTE_ADDRES_RELATION_QUOTE_ADDR_ID_QUOTE_ADDR_ADDR_ID": true,
"FK_46E162119F9C6A5527FB629B614079C7": true
}
},
"vipps_login_authorization": {
"column": {
"entity_id": true,
"code": true,
"payload": true,
"created_at": true
},
"constraint": {
"PRIMARY": true,
"VIPPS_LOGIN_AUTHORIZATION_CODE": true
}
}
}
2 changes: 1 addition & 1 deletion etc/module.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
-->

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Vipps_Login" setup_version="2.4.12">
<module name="Vipps_Login" setup_version="2.4.13">
<sequence>
<module name="Magento_Customer"/>
<module name="Magento_Checkout"/>
Expand Down

0 comments on commit ab5e265

Please sign in to comment.