Skip to content

Commit

Permalink
Merge branch 'magento:develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
thomas-kl1 committed May 28, 2021
2 parents 5ddbc7c + e4aea96 commit d5f0556
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 18 deletions.
5 changes: 5 additions & 0 deletions ReCaptchaUser/Test/Integration/LoginFormTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ private function checkSuccessfulGetResponse($shouldContainReCaptcha = false): vo
$this->getRequest()->setUri($this->backendUrl->getUrl('admin'));

$this->dispatch('backend/admin/auth/login');

if ($this->getResponse()->getHeader('Location')) {
$this->dispatch($this->getResponse()->getHeader('Location')->uri()->getPath());
}

$content = $this->getResponse()->getBody();

self::assertNotEmpty($content);
Expand Down
23 changes: 23 additions & 0 deletions ReCaptchaVersion2Checkbox/etc/csp_whitelist.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<csp_whitelist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Csp:etc/csp_whitelist.xsd">
<policies>
<policy id="frame-src">
<values>
<value id="google_com" type="host">https://www.google.com/recaptcha/</value>
</values>
</policy>
<policy id="script-src">
<values>
<value id="gstatic_com" type="host">https://www.gstatic.com/recaptcha/</value>
<value id="google_com" type="host">https://www.google.com/recaptcha/</value>
</values>
</policy>
</policies>
</csp_whitelist>

23 changes: 23 additions & 0 deletions ReCaptchaVersion2Invisible/etc/csp_whitelist.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<csp_whitelist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Csp:etc/csp_whitelist.xsd">
<policies>
<policy id="frame-src">
<values>
<value id="google_com" type="host">https://www.google.com/recaptcha/</value>
</values>
</policy>
<policy id="script-src">
<values>
<value id="gstatic_com" type="host">https://www.gstatic.com/recaptcha/</value>
<value id="google_com" type="host">https://www.google.com/recaptcha/</value>
</values>
</policy>
</policies>
</csp_whitelist>

23 changes: 23 additions & 0 deletions ReCaptchaVersion3Invisible/etc/csp_whitelist.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<csp_whitelist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Csp:etc/csp_whitelist.xsd">
<policies>
<policy id="frame-src">
<values>
<value id="google_com" type="host">https://www.google.com/recaptcha/</value>
</values>
</policy>
<policy id="script-src">
<values>
<value id="gstatic_com" type="host">https://www.gstatic.com/recaptcha/</value>
<value id="google_com" type="host">https://www.google.com/recaptcha/</value>
</values>
</policy>
</policies>
</csp_whitelist>

5 changes: 4 additions & 1 deletion TwoFactorAuth/Model/Provider/Engine/Google.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ public function __construct(
private function generateSecret(): string
{
$secret = random_bytes(128);
return preg_replace('/[^A-Za-z0-9]/', '', Base32::encode($secret));
// seed for iOS devices to avoid errors with barcode
$seed = 'abcd';

return preg_replace('/[^A-Za-z0-9]/', '', Base32::encode($seed . $secret));
}

/**
Expand Down
141 changes: 132 additions & 9 deletions TwoFactorAuth/Test/Api/GoogleAuthenticateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,22 @@

namespace Magento\TwoFactorAuth\Test\Api;

use Magento\Framework\HTTP\ClientInterface;
use Magento\Framework\Serialize\SerializerInterface;
use Magento\Framework\UrlInterface;
use Magento\Framework\Webapi\Rest\Request;
use Magento\Integration\Model\Oauth\TokenFactory;
use Magento\Integration\Model\ResourceModel\Oauth\Token as TokenResource;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\WebapiAbstract;
use Magento\TwoFactorAuth\Api\TfaInterface;
use Magento\TwoFactorAuth\Model\Provider\Engine\Google;
use Magento\User\Model\UserFactory;
use OTPHP\TOTP;

/**
* Class checks google authentication behaviour
*/
class GoogleAuthenticateTest extends WebapiAbstract
{
const SERVICE_VERSION = 'V1';
Expand All @@ -37,18 +45,53 @@ class GoogleAuthenticateTest extends WebapiAbstract
*/
private $tfa;

/**
* @var ClientInterface
*/
private $client;

/**
* @var UrlInterface
*/
private $url;

/**
* @var SerializerInterface
*/
private $json;

/**
* @var TokenResource
*/
private $tokenResource;

/**
* @var TokenFactory
*/
private $tokenFactory;

/**
* @inheritdoc
*/
protected function setUp(): void
{
$objectManager = Bootstrap::getObjectManager();
$this->userFactory = $objectManager->get(UserFactory::class);
$this->google = $objectManager->get(Google::class);
$this->tfa = $objectManager->get(TfaInterface::class);
$this->client = $objectManager->get(ClientInterface::class);
$this->url = $objectManager->get(UrlInterface::class);
$this->json = $objectManager->get(SerializerInterface::class);
$this->tokenResource = $objectManager->get(TokenResource::class);
$this->tokenFactory = $objectManager->get(TokenFactory::class);
}

/**
* @magentoApiDataFixture Magento/User/_files/user_with_custom_role.php
*
* @return void
*/
public function testInvalidCredentials()
public function testInvalidCredentials(): void
{
$serviceInfo = $this->buildServiceInfo();

Expand Down Expand Up @@ -80,8 +123,10 @@ public function testInvalidCredentials()
/**
* @magentoConfigFixture twofactorauth/general/force_providers duo_security
* @magentoApiDataFixture Magento/User/_files/user_with_custom_role.php
*
* @return void
*/
public function testUnavailableProvider()
public function testUnavailableProvider(): void
{
$serviceInfo = $this->buildServiceInfo();

Expand Down Expand Up @@ -109,8 +154,10 @@ public function testUnavailableProvider()
/**
* @magentoConfigFixture twofactorauth/general/force_providers google
* @magentoApiDataFixture Magento/User/_files/user_with_custom_role.php
*
* @return void
*/
public function testInvalidToken()
public function testInvalidToken(): void
{
$userId = $this->getUserId();
$serviceInfo = $this->buildServiceInfo();
Expand Down Expand Up @@ -141,8 +188,10 @@ public function testInvalidToken()
/**
* @magentoConfigFixture twofactorauth/general/force_providers google
* @magentoApiDataFixture Magento/User/_files/user_with_custom_role.php
*
* @return void
*/
public function testNotConfiguredProvider()
public function testNotConfiguredProvider(): void
{
$userId = $this->getUserId();
$serviceInfo = $this->buildServiceInfo();
Expand Down Expand Up @@ -174,8 +223,10 @@ public function testNotConfiguredProvider()
* @magentoConfigFixture twofactorauth/general/force_providers google
* @magentoApiDataFixture Magento/User/_files/user_with_custom_role.php
* @magentoConfigFixture twofactorauth/google/otp_window 120
*
* @return void
*/
public function testValidToken()
public function testValidToken(): void
{
$userId = $this->getUserId();
$otp = $this->getUserOtp();
Expand All @@ -195,6 +246,37 @@ public function testValidToken()
self::assertMatchesRegularExpression('/^[a-z0-9]{32}$/', $response);
}

/**
* @magentoConfigFixture default/oauth/access_token_lifetime/admin 1
* @magentoConfigFixture twofactorauth/general/force_providers google
*
* @magentoApiDataFixture Magento/Webapi/_files/webapi_user.php
* @magentoApiDataFixture Magento/Customer/_files/customer.php
*
* @return void
*/
public function testAdminTokenLifetime(): void
{
$this->_markTestAsRestOnly();
$this->tfa->getProviderByCode(Google::CODE)->activate($this->getUserId('webapi_user'));
$otp = $this->getUserOtp('webapi_user');
$serviceInfo = $this->buildServiceInfo();
$requestData = [
'otp' => $otp,
'username' => 'webapi_user',
'password' => \Magento\TestFramework\Bootstrap::ADMIN_PASSWORD,
];
$accessToken = $this->_webApiCall($serviceInfo, $requestData);
$result = $this->doCustomerRequest($accessToken, 1);
$this->assertContains('customer@example.com', $this->json->unserialize($result));
$this->updateTokenCreatedTime($accessToken);
$result = $this->doCustomerRequest($accessToken, 1);
$this->assertContains(
'The consumer isn\'t authorized to access %resources.',
$this->json->unserialize($result)
);
}

/**
* @return array
*/
Expand All @@ -217,20 +299,61 @@ private function buildServiceInfo(): array
];
}

private function getUserId(): int
/**
* Get user id
*
* @param string $userName
* @return int
*/
private function getUserId($userName = 'customRoleUser'): int
{
$user = $this->userFactory->create();
$user->loadByUsername('customRoleUser');
$user->loadByUsername($userName);

return (int)$user->getId();
}

private function getUserOtp(): string
/**
* Get user otp
*
* @param string $userName
* @return string
*/
private function getUserOtp($userName = 'customRoleUser'): string
{
$user = $this->userFactory->create();
$user->loadByUsername('customRoleUser');
$user->loadByUsername($userName);
$totp = TOTP::create($this->google->getSecretCode($user));

return $totp->now();
}

/**
* Perform request to customers endpoint
*
* @param string $accessToken
* @return string
*/
private function doCustomerRequest(string $accessToken, $customerId): string
{
$this->client->addHeader('Authorization', 'Bearer ' . $accessToken);
$this->client->get($this->url->getBaseUrl() . 'rest/V1/customers/' . $customerId);

return $this->client->getBody();
}

/**
* Update token created time
*
* @param string $accessToken
* @return void
*/
private function updateTokenCreatedTime(string $accessToken): void
{
$token = $this->tokenFactory->create();
$token->loadByToken($accessToken);
$createdAt = (new \DateTime('-1 day'))->format('Y-m-d H:i:s');
$token->setCreatedAt($createdAt);
$this->tokenResource->save($token);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public function testUnauthenticated(): void
$this->dispatch('backend/admin/index/index');
//Login controller redirects to full start-up URL
$this->assertRedirect($this->stringContains('index'));
$properUrl = $this->getResponse()->getHeader('Location')->getFieldValue();
$properUrl = $this->getResponse()->getHeader('Location')->uri()->getPath();

//Login page must be rendered without redirects
$this->getRequest()->setDispatched(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public function testAuthenticateValidRequest()
'abc'
);

self::assertMatchesRegularExpression('/^[a-z0-9]{32}$/', $result);
self::assertNotEmpty($result);
}

/**
Expand Down Expand Up @@ -290,7 +290,7 @@ public function testCreateTokenWithOneTouch()
Bootstrap::ADMIN_PASSWORD
);

self::assertMatchesRegularExpression('/^[a-z0-9]{32}$/', $result);
self::assertNotEmpty($result);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ public function testVerifyValidRequest()
$signature
);

self::assertMatchesRegularExpression('/^[a-z0-9]{32}$/', $token);
self::assertNotEmpty($token);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ public function testVerifyValidRequest()
Bootstrap::ADMIN_PASSWORD,
json_encode($verifyData)
);
self::assertMatchesRegularExpression('/^[a-z0-9]{32}$/', $token);
self::assertNotEmpty($token);
}

/**
Expand Down
8 changes: 5 additions & 3 deletions TwoFactorAuth/Test/Integration/UserConfigManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ public function testShouldEncryptConfiguration(): void
$encryptor = Bootstrap::getObjectManager()->create(EncryptorInterface::class);

/** @var ResourceConnection $resourceConnection */
$connection = Bootstrap::getObjectManager()->get(ResourceConnection::class)
->getConnection(ResourceConnection::DEFAULT_CONNECTION);
$resourceConnection = Bootstrap::getObjectManager()->get(ResourceConnection::class);
$connection = $resourceConnection->getConnection(ResourceConnection::DEFAULT_CONNECTION);

$configPayload = ['a' => 1, 'b' => 2];

Expand All @@ -181,8 +181,10 @@ public function testShouldEncryptConfiguration(): void
$configPayload
);

$tfaUserConfig = $resourceConnection->getTableName('tfa_user_config');

$qry = $connection->select()
->from('tfa_user_config', 'encoded_config')
->from($tfaUserConfig, 'encoded_config')
->where('user_id = ?', (int)$dummyUser->getId());

$res = $connection->fetchOne($qry);
Expand Down
Loading

0 comments on commit d5f0556

Please sign in to comment.