Commit a4f6918e authored by pfrilling's avatar pfrilling
Browse files

Added coverage for the completeAuthorization method.

parent 3867d266
......@@ -2,7 +2,6 @@
declare(strict_types = 1);
use Drupal\Component\Utility\EmailValidatorInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
......@@ -11,11 +10,15 @@ use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\openid_connect\OpenIDConnectAuthmap;
use Drupal\openid_connect\Plugin\OpenIDConnectClientInterface;
use Drupal\Tests\UnitTestCase;
use Drupal\user\UserDataInterface;
use Drupal\openid_connect\OpenIDConnect;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\user\UserInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\DependencyInjection\ContainerBuilder;
/**
* Class OpenIDConnectTest.
......@@ -106,6 +109,13 @@ class OpenIDConnectTest extends UnitTestCase {
*/
protected $userStorage;
/**
* Mock of the open id connect logger.
*
* @var \PHPUnit\Framework\MockObject\MockObject
*/
protected $oidcLogger;
/**
* {@inheritDoc}
*/
......@@ -129,7 +139,7 @@ class OpenIDConnectTest extends UnitTestCase {
$this->entityTypeManager = $this
->createMock(EntityTypeManagerInterface::class);
$this->entityTypeManager->expects($this->once())
$this->entityTypeManager->expects($this->atLeastOnce())
->method('getStorage')
->with('user')
->willReturn($this->userStorage);
......@@ -143,8 +153,10 @@ class OpenIDConnectTest extends UnitTestCase {
$this->userData = $this
->createMock(UserDataInterface::class);
$this->emailValidator = $this
->createMock(EmailValidatorInterface::class);
$emailValidator = $this
->getMockBuilder('\Drupal\Component\Utility\EmailValidator')
->setMethods(NULL);
$this->emailValidator = $emailValidator->getMock();
$this->messenger = $this
->createMock(MessengerInterface::class);
......@@ -155,6 +167,18 @@ class OpenIDConnectTest extends UnitTestCase {
$this->logger = $this
->createMock(LoggerChannelFactoryInterface::class);
$this->oidcLogger = $this
->createMock(LoggerChannelInterface::class);
$this->logger->expects($this->atLeastOnce())
->method('get')
->with('openid_connect')
->willReturn($this->oidcLogger);
$container = new ContainerBuilder();
$container->set('string_translation', $this->getStringTranslationStub());
\Drupal::setContainer($container);
$this->openIdConnect = new OpenIDConnect(
$this->configFactory,
$this->authMap,
......@@ -478,4 +502,587 @@ class OpenIDConnectTest extends UnitTestCase {
];
}
/**
* Test coverate for the completeAuthorization() method.
*
* @param bool $authenticated
* Should the user be authenticated.
* @param string $destination
* Destination string.
* @param array $tokens
* Tokens array.
* @param array $userData
* The user data array.
* @param array $userInfo
* The user info array.
* @param bool $preAuthorize
* Whether to preauthorize or not.
* @param bool $accountExists
* Does the account already exist.
*
* @dataProvider dataProviderForCompleteAuthorization
* @runInSeparateProcess
*/
public function testCompleteAuthorization(
bool $authenticated,
string $destination,
array $tokens,
array $userData,
array $userInfo,
bool $preAuthorize,
bool $accountExists
): void {
$clientPluginId = $this->randomMachineName();
$this->currentUser->expects($this->once())
->method('isAuthenticated')
->willReturn($authenticated);
$client = $this
->createMock(OpenIDConnectClientInterface::class);
$moduleHandlerCount = 1;
if ($preAuthorize) {
$moduleHandlerCount = 3;
}
if ($authenticated) {
$this->expectException('RuntimeException');
}
else {
$client->expects($this->once())
->method('decodeIdToken')
->with($tokens['id_token'])
->willReturn($userData);
$client->expects($this->once())
->method('retrieveUserInfo')
->with($tokens['access_token'])
->willReturn($userInfo);
$client->expects($this->any())
->method('getPluginId')
->willReturn($clientPluginId);
if ($accountExists) {
if (!$preAuthorize) {
$moduleHandlerResults = [1, 2, FALSE];
}
else {
$returnedAccount = $this
->createMock(UserInterface::class);
if (!empty($userInfo['blocked'])) {
$returnedAccount->expects($this->once())
->method('isBlocked')
->willReturn(TRUE);
$this->messenger->expects($this->once())
->method('addError');
}
$moduleHandlerResults = [$returnedAccount];
}
$this->moduleHandler->expects($this->once())
->method('alter')
->with(
'openid_connect_userinfo',
$userInfo,
[
'tokens' => $tokens,
'plugin_id' => $clientPluginId,
'user_data' => $userData,
]
);
if (empty($userData) && empty($userInfo)) {
$this->oidcLogger->expects($this->once())
->method('error')
->with(
'No "sub" found from @provider (@code @error). Details: @details',
['@provider' => $clientPluginId]
);
}
if (!empty($userInfo) && empty($userInfo['email'])) {
$this->oidcLogger->expects($this->once())
->method('error')
->with(
'No e-mail address provided by @provider (@code @error). Details: @details',
['@provider' => $clientPluginId]
);
}
if (!empty($userInfo['sub'])) {
$account = $this->createMock(UserInterface::class);
$account->method('id')->willReturn(1234);
$account->method('isNew')->willReturn(FALSE);
$context = [
'tokens' => $tokens,
'plugin_id' => $clientPluginId,
'user_data' => $userData,
'userinfo' => $userInfo,
'sub' => $userInfo['sub'],
];
$this->authMap->expects($this->once())
->method('userLoadBySub')
->willReturn($account);
$this->moduleHandler->expects($this->any())
->method('invokeAll')
->withConsecutive(
['openid_connect_pre_authorize'],
['openid_connect_userinfo_save'],
['openid_connect_post_authorize']
)
->willReturnOnConsecutiveCalls(
$moduleHandlerResults,
TRUE,
TRUE
);
if ($preAuthorize) {
$this->entityFieldManager->expects($this->once())
->method('getFieldDefinitions')
->with('user', 'user')
->willReturn(['mail' => 'mail']);
$immutableConfig = $this
->createMock(ImmutableConfig::class);
$immutableConfig->expects($this->exactly(2))
->method('get')
->withConsecutive(
['always_save_userinfo'],
['userinfo_mappings']
)
->willReturnOnConsecutiveCalls(
TRUE,
['mail', 'name']
);
$this->configFactory->expects($this->exactly(2))
->method('get')
->with('openid_connect.settings')
->willReturn($immutableConfig);
}
}
}
else {
$account = FALSE;
$context = [
'tokens' => $tokens,
'plugin_id' => $clientPluginId,
'user_data' => $userData,
'userinfo' => $userInfo,
'sub' => $userInfo['sub'],
];
$this->authMap->expects($this->once())
->method('userLoadBySub')
->willReturn($account);
$this->moduleHandler->expects($this->any())
->method('invokeAll')
->willReturnCallback(function (...$args) use ($account, $context) {
$return = NULL;
switch ($args[0]) {
case 'openid_connect_pre_authorize':
$return = [];
break;
default:
$return = NULL;
break;
}
return $return;
});
if ($userInfo['email'] === 'invalid') {
$this->messenger->expects($this->once())
->method('addError');
}
else {
if ($userInfo['email'] === 'duplicate@valid.com') {
$account = $this
->createMock(UserInterface::class);
$this->userStorage->expects($this->once())
->method('loadByProperties')
->with(['mail' => $userInfo['email']])
->willReturn([$account]);
$immutableConfig = $this
->createMock(ImmutableConfig::class);
$immutableConfig->expects($this->once())
->method('get')
->with('connect_existing_users')
->willReturn(FALSE);
$this->configFactory->expects($this->once())
->method('get')
->with('openid_connect.settings')
->willReturn($immutableConfig);
$this->messenger->expects($this->once())
->method('addError');
}
elseif ($userInfo['email'] === 'connect@valid.com') {
$this->entityFieldManager->expects($this->any())
->method('getFieldDefinitions')
->with('user', 'user')
->willReturn(['mail' => 'mail']);
$context = [
'tokens' => $tokens,
'plugin_id' => $clientPluginId,
'user_data' => $userData,
];
$this->moduleHandler->expects($this->once())
->method('alter')
->with(
'openid_connect_userinfo',
$userInfo,
$context
);
if (isset($userInfo['newAccount']) && $userInfo['newAccount']) {
$account = FALSE;
}
else {
$account = $this
->createMock(UserInterface::class);
if (isset($userInfo['blocked']) && $userInfo['blocked']) {
$account->expects($this->once())
->method('isBlocked')
->willReturn(TRUE);
if ($accountExists) {
var_dump($accountExists);
$this->messenger->expects($this->once())
->method('addError');
}
}
}
if (isset($userInfo['newAccount']) && $userInfo['newAccount']) {
$this->userStorage->expects($this->once())
->method('loadByProperties')
->with(['mail' => $userInfo['email']])
->willReturn(FALSE);
}
else {
$this->userStorage->expects($this->once())
->method('loadByProperties')
->with(['mail' => $userInfo['email']])
->willReturn([$account]);
}
if (isset($userInfo['register'])) {
switch ($userInfo['register']) {
case 'admin_only':
if (empty($userInfo['registerOverride'])) {
$this->messenger->expects($this->once())
->method('addError');
}
break;
case 'visitors_admin_approval':
$this->messenger->expects($this->once())
->method('addMessage');
break;
}
}
$immutableConfig = $this
->createMock(ImmutableConfig::class);
$immutableConfig->expects($this->any())
->method('get')
->willReturnCallback(function ($config) use ($userInfo) {
$return = FALSE;
switch ($config) {
case 'connect_existing_users':
case 'override_registration_settings':
if (empty($userInfo['registerOverride']) && isset($userInfo['newAccount']) && $userInfo['newAccount']) {
$return = FALSE;
}
else {
$return = TRUE;
}
break;
case 'register':
if (isset($userInfo['register'])) {
$return = $userInfo['register'];
}
break;
case 'userinfo_mappings':
$return = ['mail' => 'mail'];
break;
}
return $return;
});
$this->configFactory->expects($this->any())
->method('get')
->willReturnCallback(function ($config) use ($immutableConfig) {
if (
$config === 'openid_connect.settings' ||
$config === 'user.settings'
) {
return $immutableConfig;
}
return FALSE;
});
}
}
}
}
$oidcMock = $this->getMockBuilder('\Drupal\openid_connect\OpenIDConnect')
->setConstructorArgs([
$this->configFactory,
$this->authMap,
$this->entityTypeManager,
$this->entityFieldManager,
$this->currentUser,
$this->userData,
$this->emailValidator,
$this->messenger,
$this->moduleHandler,
$this->logger,
])
->setMethods([
'userPropertiesIgnore',
'createUser',
])
->getMock();
$oidcMock->method('userPropertiesIgnore')
->willReturn(['uid' => 'uid', 'name' => 'name']);
$oidcMock->method('createUser')
->willReturn(
$this->createMock(UserInterface::class)
);
$authorization = $oidcMock
->completeAuthorization($client, $tokens, $destination);
if (empty($userData) && empty($userInfo)) {
$this->assertEquals(FALSE, $authorization);
}
if (!empty($userInfo) && empty($userInfo['email'])) {
$this->assertEquals(FALSE, $authorization);
}
}
/**
* Data provider for the testCompleteAuthorization() method.
*
* @return array|array[]
* Test parameters to pass to testCompleteAuthorization().
*/
public function dataProviderForCompleteAuthorization(): array {
$tokens = [
"id_token" => $this->randomMachineName(),
"access_token" => $this->randomMachineName(),
];
return [
[
TRUE,
'',
[],
[],
[],
FALSE,
TRUE,
],
[
FALSE,
'',
$tokens,
[],
[],
FALSE,
TRUE,
],
[
FALSE,
'',
$tokens,
[],
[
'email' => '',
],
FALSE,
TRUE,
],
[
FALSE,
'',
$tokens,
[],
[
'email' => 'test@test.com',
'sub' => $this->randomMachineName(),
],
FALSE,
TRUE,
],
[
FALSE,
'',
$tokens,
[],
[
'email' => 'test@test.com',
'sub' => $this->randomMachineName(),
],
TRUE,
TRUE,
],
[
FALSE,
'',
$tokens,
[],
[
'email' => 'invalid',
'sub' => $this->randomMachineName(),
],
TRUE,
FALSE,
],
[
FALSE,
'',
$tokens,
[],
[
'email' => 'duplicate@valid.com',
'sub' => $this->randomMachineName(),
],
TRUE,
FALSE,
],
[
FALSE,
'',
$tokens,
[],
[
'email' => 'connect@valid.com',
'sub' => $this->randomMachineName(),
],
TRUE,
FALSE,
],
[
FALSE,
'',
$tokens,
[],
[
'email' => 'connect@valid.com',
'blocked' => TRUE,
'sub' => $this->randomMachineName(),
],
TRUE,
FALSE,
],
[
FALSE,
'',
$tokens,
[],
[
'email' => 'connect@valid.com',
'blocked' => TRUE,
'sub' => 'TESTING',
],
TRUE,
TRUE,
],
[
FALSE,
'',
$tokens,
[],
[
'email' => 'connect@valid.com',
'newAccount' => TRUE,
'register' => 'admin_only',
'sub' => $this->randomMachineName(),
],
TRUE,
FALSE,
],
[
FALSE,
'',
$tokens,