View source
<?php
declare (strict_types=1);
namespace Drupal\Tests\entity_share_client\Functional;
use Drupal\consumers\Entity\Consumer;
use Drupal\Core\Site\Settings;
use Drupal\Core\Url;
use Drupal\entity_share_client\Entity\RemoteInterface;
use Drupal\Tests\simple_oauth\Functional\SimpleOauthTestTrait;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
use Drupal\user\UserInterface;
use GuzzleHttp\RequestOptions;
use League\OAuth2\Client\Token\AccessTokenInterface;
class AuthenticationOAuthTest extends AuthenticationTestBase {
use SimpleOauthTestTrait;
public static $modules = [
'serialization',
'simple_oauth',
];
protected $keyService;
protected $configFactory;
protected $clientSecret;
protected $clients;
protected $clientRole;
protected $clientRolePlain;
protected function setUp() : void {
parent::setUp();
$this->keyService = $this->container
->get('entity_share_client.key_provider');
foreach ($this->channels as $channel) {
$authorized_users = $channel
->get('authorized_users');
$authorized_users = array_merge($authorized_users, [
$this->adminUser
->uuid(),
]);
$channel
->set('authorized_users', $authorized_users);
$channel
->save();
}
$this
->createKey($this->adminUser);
$this
->createKey($this->channelUser);
$this->configFactory = $this->container
->get('config.factory');
$simple_oauth_settings = $this->configFactory
->getEditable('simple_oauth.settings');
$simple_oauth_settings
->set('access_token_expiration', 10);
$simple_oauth_settings
->set('refresh_token_expiration', 30);
$simple_oauth_settings
->save();
$plugin = $this
->createAuthenticationPlugin($this->adminUser, $this->remote);
$this->remote
->mergePluginConfig($plugin);
$this->remote
->save();
$this
->postSetupFixture();
}
protected function createAuthenticationPlugin(UserInterface $user, RemoteInterface $remote) {
$this
->serverOauthSetup();
$plugin = $this->authPluginManager
->createInstance('oauth');
$configuration = $plugin
->getConfiguration();
if ($this->keyValueStore
->get($configuration['uuid'] . '-' . $plugin
->getPluginId()) instanceof AccessTokenInterface) {
$this->keyValueStore
->delete($configuration['uuid'] . '-' . $plugin
->getPluginId());
}
$request_options = [
RequestOptions::HTTP_ERRORS => FALSE,
RequestOptions::ALLOW_REDIRECTS => [
'strict' => TRUE,
],
];
$site_settings = Settings::getAll();
$site_settings['http_client_config'] = $request_options;
new Settings($site_settings);
$credentials = [
'username' => $user
->getAccountName(),
'password' => $user->passRaw,
'client_id' => $this->clients[$user
->id()]
->uuid(),
'client_secret' => $this->clientSecret,
'authorization_path' => '/oauth/authorize',
'token_path' => '/oauth/token',
];
$access_token = '';
try {
$access_token = $plugin
->initializeToken($remote, $credentials);
} catch (\Exception $e) {
}
$this
->assertNotEmpty($access_token, 'The access token is not empty.');
unset($credentials['username']);
unset($credentials['password']);
$storage_key = $configuration['uuid'];
$this->keyValueStore
->set($storage_key, $credentials);
$this->keyValueStore
->set($storage_key . '-' . $plugin
->getPluginId(), $access_token);
$configuration['data'] = [
'credential_provider' => 'entity_share',
'storage_key' => $storage_key,
];
$plugin
->setConfiguration($configuration);
return $plugin;
}
public function testImport() {
foreach (static::$filesData as $file_data) {
$this
->assertFalse(file_exists($file_data['uri']), 'The physical file ' . $file_data['filename'] . ' has been deleted.');
}
$this
->pullChannel('node_es_test_en');
$this
->checkCreatedEntities();
foreach (static::$filesData as $file_definition) {
$this
->assertTrue(file_exists($file_definition['uri']), 'The physical file ' . $file_definition['filename'] . ' has been pulled and recreated.');
$this
->assertEquals(file_get_contents($file_definition['uri']), $file_definition['file_content'], 'The content of physical file ' . $file_definition['filename'] . ' is correct.');
}
$plugin = $this
->createAuthenticationPlugin($this->channelUser, $this->remote);
$this->remote
->mergePluginConfig($plugin);
$this->remote
->save();
$this
->resetImportedContent();
foreach (static::$filesData as $file_data) {
$this->fileSystem
->delete($file_data['uri']);
}
unset($this->entitiesData['file']);
unset($this->entitiesData['node']['en']['es_test_node_import_published']['field_es_test_file']);
$this
->resetRemoteCaches();
$this
->prepareContent();
$channel_infos = $this->remoteManager
->getChannelsInfos($this->remote);
$this
->reimportChannel($channel_infos);
$entity_storage = $this->entityTypeManager
->getStorage('node');
$published = $entity_storage
->loadByProperties([
'uuid' => 'es_test_node_import_published',
]);
$this
->assertEquals(count($published), 1, 'The published node was imported.');
$not_published = $entity_storage
->loadByProperties([
'uuid' => 'es_test_node_import_not_published',
]);
$this
->assertEquals(count($not_published), 0, 'The unpublished node was not imported.');
$this
->setupAuthorizationPluginWithKey($this->channelUser);
$this
->resetImportedContent();
$this
->resetRemoteCaches();
$this
->prepareContent();
$this
->reimportChannel($channel_infos);
$entity_storage = $this->entityTypeManager
->getStorage('node');
$published = $entity_storage
->loadByProperties([
'uuid' => 'es_test_node_import_published',
]);
$this
->assertEquals(count($published), 1, 'The published node was imported.');
$not_published = $entity_storage
->loadByProperties([
'uuid' => 'es_test_node_import_not_published',
]);
$this
->assertEquals(count($not_published), 0, 'The unpublished node was not imported.');
}
public function testTokenExpiration() {
$entity_share_entrypoint_url = Url::fromRoute('entity_share_server.resource_list');
$response = $this->remoteManager
->jsonApiRequest($this->remote, 'GET', $entity_share_entrypoint_url
->setAbsolute()
->toString());
$this
->assertNotNull($response, 'No exception caught during request');
$this
->assertEquals(200, $response
->getStatusCode());
$plugin = $this->remote
->getAuthPlugin();
$configuration = $plugin
->getConfiguration();
$access_token = $this->keyValueStore
->get($configuration['uuid'] . '-' . $plugin
->getPluginId());
$this
->assertFalse($access_token
->hasExpired(), 'The access token has not expired yet.');
sleep(30);
$this
->assertTrue($access_token
->hasExpired(), 'The access token has expired.');
$this
->resetRemoteCaches();
$response = $this->remoteManager
->jsonApiRequest($this->remote, 'GET', $entity_share_entrypoint_url
->setAbsolute()
->toString());
$this
->assertNotNull($response, 'No exception caught during request');
$this
->assertEquals(200, $response
->getStatusCode());
sleep(120);
$this
->resetRemoteCaches();
$response = $this->remoteManager
->jsonApiRequest($this->remote, 'GET', $entity_share_entrypoint_url
->setAbsolute()
->toString());
$this
->assertNotNull($response, 'No exception caught during request');
$this
->assertEquals(200, $response
->getStatusCode());
}
private function setupAuthorizationPluginWithKey(UserInterface $account) {
$plugin = $this->remote
->getAuthPlugin();
$configuration = $plugin
->getConfiguration();
if ($this->keyValueStore
->get($configuration['uuid'] . '-' . $plugin
->getPluginId()) instanceof AccessTokenInterface) {
$this->keyValueStore
->delete($configuration['uuid'] . '-' . $plugin
->getPluginId());
}
$credentials = $this->keyService
->getCredentials($plugin);
$credentials['username'] = $account
->getAccountName();
$credentials['password'] = $account->passRaw;
$request_options = [
RequestOptions::HTTP_ERRORS => FALSE,
RequestOptions::ALLOW_REDIRECTS => [
'strict' => TRUE,
],
];
$access_token = '';
try {
$access_token = $plugin
->initializeToken($this->remote, $credentials, $request_options);
} catch (\Exception $e) {
}
$this
->assertNotEmpty($access_token, 'The new access token is not empty.');
$this->keyValueStore
->set($configuration['uuid'] . '-' . $plugin
->getPluginId(), $access_token);
$configuration['data'] = [
'credential_provider' => 'key',
'storage_key' => 'key_oauth_' . $account
->id(),
];
$plugin
->setConfiguration($configuration);
$this->remote
->mergePluginConfig($plugin);
$this->remote
->save();
}
private function serverOauthSetup() {
$this->clientRole = Role::create([
'id' => $this
->getRandomGenerator()
->name(8, TRUE),
'label' => $this
->getRandomGenerator()
->word(5),
'is_admin' => FALSE,
]);
$this->clientRole
->grantPermission('grant simple_oauth codes');
$this->clientRole
->grantPermission('entity_share_server_access_channels');
$this->clientRole
->grantPermission('bypass node access');
$this->clientRole
->save();
$this->adminUser
->addRole($this->clientRole
->id());
$this->clientRolePlain = Role::create([
'id' => $this
->getRandomGenerator()
->name(8, TRUE),
'label' => $this
->getRandomGenerator()
->word(5),
'is_admin' => FALSE,
]);
$this->clientRolePlain
->grantPermission('grant simple_oauth codes');
$this->clientRolePlain
->grantPermission('entity_share_server_access_channels');
$this->clientRolePlain
->save();
$this->channelUser
->addRole($this->clientRolePlain
->id());
$this->clientSecret = $this
->getRandomGenerator()
->string();
$this
->createOauthConsumer($this->adminUser, $this->clientRole);
$this
->createOauthConsumer($this->channelUser, $this->clientRolePlain);
$this
->setUpKeys();
}
protected function createOauthConsumer(UserInterface $account, RoleInterface $role) {
$client = Consumer::create([
'owner_id' => '',
'user_id' => $account
->id(),
'label' => $this
->getRandomGenerator()
->name(),
'secret' => $this->clientSecret,
'confidential' => FALSE,
'third_party' => TRUE,
'roles' => [
[
'target_id' => $role
->id(),
],
],
]);
$client
->save();
$this->clients[$account
->id()] = $client;
}
protected function createKey(UserInterface $account) {
$this
->createTestKey('key_oauth_' . $account
->id(), 'entity_share_oauth', 'config');
$credentials = [
'client_id' => $this->clients[$account
->id()]
->uuid(),
'client_secret' => $this->clientSecret,
'authorization_path' => '/oauth/authorize',
'token_path' => '/oauth/token',
];
$output = '';
foreach ($credentials as $name => $value) {
$output .= "\"{$name}\": \"{$value}\"\n";
}
$key_value = <<<EOT
{
{<span class="php-variable">$output</span>}}
EOT;
$this->testKey
->setKeyValue($key_value);
$this->testKey
->save();
}
}