diff --git a/modules/simple_oauth_static_scope/simple_oauth_static_scope.info.yml b/modules/simple_oauth_static_scope/simple_oauth_static_scope.info.yml index 4442743bbaca2c4a128806b056eab464887743e5..53f85533467cea77972154d9a265526bd413d8e3 100644 --- a/modules/simple_oauth_static_scope/simple_oauth_static_scope.info.yml +++ b/modules/simple_oauth_static_scope/simple_oauth_static_scope.info.yml @@ -1,7 +1,7 @@ name: Simple OAuth static scope type: module description: 'Makes static (YAML) defined scopes available.' -core_version_requirement: ^10.2 || ^11 +core_version_requirement: ^10.3 || ^11 package: Authentication dependencies: - simple_oauth:simple_oauth diff --git a/modules/simple_oauth_static_scope/src/Plugin/Oauth2Scope.php b/modules/simple_oauth_static_scope/src/Plugin/Oauth2Scope.php index 1424a88f0159febec70029b43bab69b3e1f55a0f..608ec31d528942bb0e7cb5fe86730f3d3c70e1dd 100644 --- a/modules/simple_oauth_static_scope/src/Plugin/Oauth2Scope.php +++ b/modules/simple_oauth_static_scope/src/Plugin/Oauth2Scope.php @@ -108,4 +108,13 @@ class Oauth2Scope extends PluginBase implements Oauth2ScopePluginInterface, Cont ); } + /** + * {@inheritdoc} + */ + public function getPermissions(): array { + $granularity = $this->getGranularity(); + assert($granularity instanceof ScopeGranularityInterface); + return $granularity->getPermissions(); + } + } diff --git a/simple_oauth.info.yml b/simple_oauth.info.yml index 346c0f0793aa3395d0268aee3ed652036bdb0ee7..4527812c508c63bff1db934968d21c3572eb7371 100644 --- a/simple_oauth.info.yml +++ b/simple_oauth.info.yml @@ -1,7 +1,7 @@ name: Simple OAuth & OpenID Connect type: module description: 'The OAuth 2.0 Authorization Framework' -core_version_requirement: ^10.2 || ^11 +core_version_requirement: ^10.3 || ^11 package: Authentication configure: oauth2_token.settings dependencies: diff --git a/simple_oauth.services.yml b/simple_oauth.services.yml index 1ac7cdaa8d5a9e3416787810051281f4995e2d8d..81649e7628520d5069770e656197bf8f78fabb97 100644 --- a/simple_oauth.services.yml +++ b/simple_oauth.services.yml @@ -24,6 +24,8 @@ services: - '@simple_oauth.page_cache_request_policy.disallow_oauth2_token_requests' - '@psr7.http_message_factory' - '@psr7.http_foundation_factory' + - '@request_stack' + - '@permission_checker' tags: - { name: authentication_provider, provider_id: oauth2, global: TRUE, priority: 35 } simple_oauth.page_cache_request_policy.disallow_oauth2_token_requests: @@ -36,7 +38,16 @@ services: arguments: - '@Drupal\simple_oauth\EventSubscriber\ExceptionLoggingSubscriber.inner' - '@logger.channel.simple_oauth' - + cache_context.oauth2_scopes: + class: Drupal\simple_oauth\Oauth2ScopeCacheContext + arguments: [ '@current_user' ] + tags: + - { name: cache.context } + access_policy.simple_oauth: + class: Drupal\simple_oauth\Oauth2AccessPolicy + arguments: [ '@simple_oauth.oauth2_scope.provider' ] + tags: + - { name: access_policy } simple_oauth.normalizer.oauth2_token: class: Drupal\simple_oauth\Normalizer\TokenEntityNormalizer arguments: [ '@entity_type.manager' ] diff --git a/src/Authentication/Provider/SimpleOauthAuthenticationProvider.php b/src/Authentication/Provider/SimpleOauthAuthenticationProvider.php index fb03015acb32c706a935c61c7d442516bda3ee87..6187c6a14234dc5c3bf87d2a0047f09ae7fa8fc3 100644 --- a/src/Authentication/Provider/SimpleOauthAuthenticationProvider.php +++ b/src/Authentication/Provider/SimpleOauthAuthenticationProvider.php @@ -4,6 +4,7 @@ namespace Drupal\simple_oauth\Authentication\Provider; use Drupal\Core\Authentication\AuthenticationProviderInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Session\PermissionCheckerInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\simple_oauth\Authentication\TokenAuthUser; use Drupal\simple_oauth\Exception\OAuthUnauthorizedHttpException; @@ -13,6 +14,7 @@ use League\OAuth2\Server\Exception\OAuthServerException; use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface; use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; /** * OAuth2 authentication provider. @@ -23,68 +25,33 @@ class SimpleOauthAuthenticationProvider implements AuthenticationProviderInterfa use StringTranslationTrait; - /** - * The resource server factory. - * - * @var \Drupal\simple_oauth\Server\ResourceServerFactoryInterface - */ - protected ResourceServerFactoryInterface $resourceServerFactory; - - /** - * The entity type manager. - * - * @var \Drupal\Core\Entity\EntityTypeManagerInterface - */ - protected EntityTypeManagerInterface $entityTypeManager; - - /** - * The request policy. - * - * @var \Drupal\simple_oauth\PageCache\SimpleOauthRequestPolicyInterface - */ - protected SimpleOauthRequestPolicyInterface $oauthPageCacheRequestPolicy; - - /** - * The HTTP message factory. - * - * @var \Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface - */ - protected HttpMessageFactoryInterface $httpMessageFactory; - - /** - * The HTTP foundation factory. - * - * @var \Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface - */ - protected HttpFoundationFactoryInterface $httpFoundationFactory; - /** * Constructs an HTTP basic authentication provider object. * - * @param \Drupal\simple_oauth\Server\ResourceServerFactoryInterface $resource_server_factory + * @param \Drupal\simple_oauth\Server\ResourceServerFactoryInterface $resourceServerFactory * The resource server factory. - * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager * The entity type manager service. - * @param \Drupal\simple_oauth\PageCache\SimpleOauthRequestPolicyInterface $page_cache_request_policy + * @param \Drupal\simple_oauth\PageCache\SimpleOauthRequestPolicyInterface $oauthPageCacheRequestPolicy * The page cache request policy. - * @param \Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface $http_message_factory + * @param \Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface $httpMessageFactory * The HTTP message factory. - * @param \Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface $http_foundation_factory + * @param \Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface $httpFoundationFactory * The HTTP foundation factory. + * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack + * The request stack. + * @param \Drupal\Core\Session\PermissionCheckerInterface $permissionChecker + * The permission checker service. */ public function __construct( - ResourceServerFactoryInterface $resource_server_factory, - EntityTypeManagerInterface $entity_type_manager, - SimpleOauthRequestPolicyInterface $page_cache_request_policy, - HttpMessageFactoryInterface $http_message_factory, - HttpFoundationFactoryInterface $http_foundation_factory, - ) { - $this->resourceServerFactory = $resource_server_factory; - $this->entityTypeManager = $entity_type_manager; - $this->oauthPageCacheRequestPolicy = $page_cache_request_policy; - $this->httpMessageFactory = $http_message_factory; - $this->httpFoundationFactory = $http_foundation_factory; - } + protected readonly ResourceServerFactoryInterface $resourceServerFactory, + protected readonly EntityTypeManagerInterface $entityTypeManager, + protected readonly SimpleOauthRequestPolicyInterface $oauthPageCacheRequestPolicy, + protected readonly HttpMessageFactoryInterface $httpMessageFactory, + protected readonly HttpFoundationFactoryInterface $httpFoundationFactory, + protected readonly RequestStack $requestStack, + protected readonly PermissionCheckerInterface $permissionChecker, + ) {} /** * {@inheritdoc} @@ -129,8 +96,12 @@ class SimpleOauthAuthenticationProvider implements AuthenticationProviderInterfa 'value' => $auth_request->get('oauth_access_token_id'), ]); $token = reset($tokens); - - $account = new TokenAuthUser($token); + $account = new TokenAuthUser( + $this->permissionChecker, + $token, + $this->httpMessageFactory, + $this->requestStack + ); // Revoke the access token for the blocked user. if ($account->isBlocked() && $account->isAuthenticated()) { diff --git a/src/Authentication/TokenAuthUser.php b/src/Authentication/TokenAuthUser.php index 36853ea3d8b3025204b2b8c61ecc9a6e80a8a42c..f93f3a7ce462e742583562492d1100a3ffcf1892 100644 --- a/src/Authentication/TokenAuthUser.php +++ b/src/Authentication/TokenAuthUser.php @@ -7,10 +7,13 @@ use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Session\AccountInterface; use Drupal\consumers\Entity\Consumer; +use Drupal\Core\Session\PermissionCheckerInterface; use Drupal\simple_oauth\Entity\Oauth2TokenInterface; use Drupal\user\Entity\User; use Drupal\user\UserInterface; use League\OAuth2\Server\Exception\OAuthServerException; +use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; +use Symfony\Component\HttpFoundation\RequestStack; /** * The decorated user class with token information. @@ -26,13 +29,6 @@ class TokenAuthUser implements TokenAuthUserInterface { */ protected $subject; - /** - * The bearer token. - * - * @var \Drupal\simple_oauth\Entity\Oauth2TokenInterface - */ - protected Oauth2TokenInterface $token; - /** * The activated consumer instance. * @@ -43,24 +39,33 @@ class TokenAuthUser implements TokenAuthUserInterface { /** * Constructs a TokenAuthUser object. * + * @param \Drupal\Core\Session\PermissionCheckerInterface $permissionChecker + * The permission checker service. * @param \Drupal\simple_oauth\Entity\Oauth2TokenInterface $token * The underlying token. + * @param \Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface $httpMessageFactory + * The HTTP message factory. + * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack + * The request stack. * * @throws \League\OAuth2\Server\Exception\OAuthServerException * When there is no user. */ - public function __construct(Oauth2TokenInterface $token) { + public function __construct( + protected readonly PermissionCheckerInterface $permissionChecker, + protected readonly Oauth2TokenInterface $token, + protected readonly HttpMessageFactoryInterface $httpMessageFactory, + protected readonly RequestStack $requestStack, + ) { $this->consumer = $token->get('client')->entity; if (!$this->subject = $token->get('auth_user_id')->entity) { $this->subject = $this->consumer->get('user_id')->entity; } if (!$this->subject) { - $server_request = \Drupal::service('psr7.http_message_factory') - ->createRequest(\Drupal::request()); + $server_request = $httpMessageFactory->createRequest($requestStack->getCurrentRequest()); throw OAuthServerException::invalidClient($server_request); } - $this->token = $token; } /** @@ -81,18 +86,18 @@ class TokenAuthUser implements TokenAuthUserInterface { * {@inheritdoc} */ public function hasPermission($permission) { + if (!is_string($permission)) { + @trigger_error('Calling ' . __METHOD__ . '() with a $permission parameter of type other than string is deprecated in drupal:10.3.0 and will cause an error in drupal:11.0.0. See https://www.drupal.org/node/3411485', E_USER_DEPRECATED); + return FALSE; + } // When the 'auth_user_id' isn't available on the token (which can happen // with the 'client credentials' grant type): // has permission checks are then only performed on the scopes. if ($this->token->get('auth_user_id')->isEmpty()) { - return $this->token->hasPermission($permission); - } - // User #1 has all permissions. - if ((int) $this->id() === 1) { - return TRUE; + return $this->permissionChecker->hasPermission($permission, $this); } - return $this->token->hasPermission($permission) && $this->subject->hasPermission($permission); + return $this->permissionChecker->hasPermission($permission, $this) && $this->subject->hasPermission($permission); } /* --------------------------------------------------------------------------- diff --git a/src/Entity/Oauth2Scope.php b/src/Entity/Oauth2Scope.php index 618f318ce850148003883f5b03a6b09af1c120e1..7aeab01595893177a02e3335edf63ab37ef57ae9 100644 --- a/src/Entity/Oauth2Scope.php +++ b/src/Entity/Oauth2Scope.php @@ -257,6 +257,15 @@ class Oauth2Scope extends ConfigEntityBase implements Oauth2ScopeEntityInterface return $granularityCollection->get($this->granularity_id); } + /** + * {@inheritdoc} + */ + public function getPermissions(): array { + $granularity = $this->getGranularity(); + assert($granularity instanceof ScopeGranularityInterface); + return $granularity->getPermissions(); + } + /** * {@inheritdoc} */ diff --git a/src/Oauth2AccessPolicy.php b/src/Oauth2AccessPolicy.php new file mode 100644 index 0000000000000000000000000000000000000000..ec29edf2d91f89663d1463a6c68e24963868bf74 --- /dev/null +++ b/src/Oauth2AccessPolicy.php @@ -0,0 +1,47 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\simple_oauth; + +use Drupal\Core\Session\AccessPolicyBase; +use Drupal\Core\Session\AccountInterface; +use Drupal\Core\Session\CalculatedPermissionsItem; +use Drupal\Core\Session\RefinableCalculatedPermissionsInterface; +use Drupal\simple_oauth\Authentication\TokenAuthUserInterface; + +/** + * Grants permissions based on OAuth2 scopes. + */ +final class Oauth2AccessPolicy extends AccessPolicyBase { + + public function __construct(protected Oauth2ScopeProviderInterface $scopeProvider) {} + + /** + * {@inheritdoc} + */ + public function calculatePermissions(AccountInterface $account, string $scope): RefinableCalculatedPermissionsInterface { + $calculated_permissions = parent::calculatePermissions($account, $scope); + + if (!$account instanceof TokenAuthUserInterface) { + return $calculated_permissions; + } + + $token = $account->getToken(); + foreach ($token->get('scopes')->getScopes() as $oauth2_scope) { + $calculated_permissions + ->addItem(new CalculatedPermissionsItem($this->scopeProvider->getPermissions($oauth2_scope))) + ->addCacheableDependency($oauth2_scope); + } + + return $calculated_permissions; + } + + /** + * {@inheritdoc} + */ + public function getPersistentCacheContexts(): array { + return ['oauth2_scopes']; + } + +} diff --git a/src/Oauth2ScopeCacheContext.php b/src/Oauth2ScopeCacheContext.php new file mode 100644 index 0000000000000000000000000000000000000000..d89ca2e6273725ffac590deec3d068dd9f2b71e3 --- /dev/null +++ b/src/Oauth2ScopeCacheContext.php @@ -0,0 +1,57 @@ +<?php + +namespace Drupal\simple_oauth; + +use Drupal\Core\Cache\CacheableMetadata; +use Drupal\Core\Cache\Context\CalculatedCacheContextInterface; +use Drupal\Core\Session\AccountProxyInterface; +use Drupal\simple_oauth\Authentication\TokenAuthUserInterface; + +/** + * Defines the Oauth2ScopeCacheContext service, for "per scope" caching. + */ +class Oauth2ScopeCacheContext implements CalculatedCacheContextInterface { + + /** + * Constructs a new Oauth2ScopeCacheContext class. + * + * @param \Drupal\Core\Session\AccountProxyInterface $account + * The current user. + */ + public function __construct(protected AccountProxyInterface $account) {} + + /** + * {@inheritdoc} + */ + public static function getLabel() { + return t("OAuth2 scopes"); + } + + /** + * {@inheritdoc} + */ + public function getContext($oauth2_scope = NULL) { + $account = $this->account->getAccount(); + if (!$account instanceof TokenAuthUserInterface) { + return ''; + } + + $token = $account->getToken(); + $scope_names = array_map(function (Oauth2ScopeInterface $scope) { + return $scope->getName(); + }, $token->get('scopes')->getScopes()); + + if ($oauth2_scope === NULL) { + return implode(',', $scope_names); + } + return (in_array($oauth2_scope, $scope_names) ? 'true' : 'false'); + } + + /** + * {@inheritdoc} + */ + public function getCacheableMetadata($scope = NULL) { + return (new CacheableMetadata())->setCacheTags(['user:' . $this->account->id()]); + } + +} diff --git a/src/Oauth2ScopeInterface.php b/src/Oauth2ScopeInterface.php index 2c6619657654fc28902d1dcdb8709b91b6380dbd..d0e812594b33e0948dc508526b4ca7aab7c6ee7b 100644 --- a/src/Oauth2ScopeInterface.php +++ b/src/Oauth2ScopeInterface.php @@ -99,4 +99,12 @@ interface Oauth2ScopeInterface { */ public function getGranularity(): ?ScopeGranularityInterface; + /** + * Get the referenced permissions. + * + * @return array + * Returns the permissions. + */ + public function getPermissions(): array; + } diff --git a/src/Oauth2ScopeProvider.php b/src/Oauth2ScopeProvider.php index fb6418234f67327b8a716c28431799b245d38bb3..4b8913e0b606bc479a88f9da15b13d52f5c243d0 100644 --- a/src/Oauth2ScopeProvider.php +++ b/src/Oauth2ScopeProvider.php @@ -94,6 +94,25 @@ class Oauth2ScopeProvider implements Oauth2ScopeProviderInterface { return FALSE; } + /** + * {@inheritdoc} + */ + public function getPermissions(Oauth2ScopeInterface $scope): array { + if (!$scope->isUmbrella()) { + $granularity = $scope->getGranularity(); + assert($granularity instanceof ScopeGranularityInterface); + return $granularity->getPermissions(); + } + + $permissions = []; + $children = $this->loadChildren($scope->id()); + foreach ($children as $child) { + $permissions = array_unique(array_merge($permissions, $child->getPermissions())); + } + + return $permissions; + } + /** * Adds a permission to the flatten permission tree. * diff --git a/src/Oauth2ScopeProviderInterface.php b/src/Oauth2ScopeProviderInterface.php index 2b09874a0bfa6b672073a57fef94c4c87f70dee4..53adc01e1891aa1e39851d597842d48cfe1b63fa 100644 --- a/src/Oauth2ScopeProviderInterface.php +++ b/src/Oauth2ScopeProviderInterface.php @@ -20,4 +20,12 @@ interface Oauth2ScopeProviderInterface extends Oauth2ScopeAdapterInterface { */ public function scopeHasPermission(string $permission, Oauth2ScopeInterface $scope): bool; + /** + * Get the referenced permissions. + * + * @return array + * Returns the permissions. + */ + public function getPermissions(Oauth2ScopeInterface $scope): array; + } diff --git a/src/Plugin/ScopeGranularity/Permission.php b/src/Plugin/ScopeGranularity/Permission.php index ba7c4e9363c67df4c8892f9eb43c67c13ea83763..467cf1dc42bc5714ac7a3514c45b54c9a09b5ff3 100644 --- a/src/Plugin/ScopeGranularity/Permission.php +++ b/src/Plugin/ScopeGranularity/Permission.php @@ -76,6 +76,13 @@ class Permission extends ScopeGranularityBase implements ContainerFactoryPluginI return $this->getConfiguration()['permission'] === $permission; } + /** + * {@inheritdoc} + */ + public function getPermissions(): array { + return [$this->getConfiguration()['permission']]; + } + /** * {@inheritdoc} */ diff --git a/src/Plugin/ScopeGranularity/Role.php b/src/Plugin/ScopeGranularity/Role.php index 924a736a8d1cf4831e9fd02e20b55361b8b04e09..805adc5d49b1328c371ae201c183ee2ca44810ff 100644 --- a/src/Plugin/ScopeGranularity/Role.php +++ b/src/Plugin/ScopeGranularity/Role.php @@ -11,6 +11,7 @@ use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\simple_oauth\Attribute\ScopeGranularity; use Drupal\simple_oauth\Oauth2ScopeInterface; use Drupal\simple_oauth\Plugin\ScopeGranularityBase; +use Drupal\user\RoleInterface; use Drupal\user\RoleStorage; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -87,6 +88,33 @@ class Role extends ScopeGranularityBase implements ContainerFactoryPluginInterfa return $role_storage->isPermissionInRoles($permission, $rolesToCheck); } + /** + * {@inheritdoc} + */ + public function getPermissions(): array { + $role = $this->getConfiguration()['role']; + + $lockedRoles = [ + AccountInterface::AUTHENTICATED_ROLE, + AccountInterface::ANONYMOUS_ROLE, + ]; + $rolesToCheck = !in_array($role, $lockedRoles) + ? [AccountInterface::AUTHENTICATED_ROLE, $role] + : [$role]; + + $role_storage = $this->entityTypeManager->getStorage('user_role'); + assert($role_storage instanceof RoleStorage); + + $permissions = []; + foreach ($rolesToCheck as $roleToCheck) { + $role = $role_storage->load($roleToCheck); + assert($role instanceof RoleInterface); + $permissions = array_unique(array_merge($permissions, $role->getPermissions())); + } + + return $permissions; + } + /** * {@inheritdoc} */ diff --git a/src/Plugin/ScopeGranularityInterface.php b/src/Plugin/ScopeGranularityInterface.php index eb94b9bb433f9aa924b9a9fcc0f54b4f1c235fdb..36d6b3f308df2d45f95a06450cd6d45e305106be 100644 --- a/src/Plugin/ScopeGranularityInterface.php +++ b/src/Plugin/ScopeGranularityInterface.php @@ -32,4 +32,12 @@ interface ScopeGranularityInterface extends ConfigurableInterface, PluginFormInt */ public function hasPermission(string $permission): bool; + /** + * Returns a list of permissions assigned to the scope. + * + * @return array + * The permissions assigned to the scope. + */ + public function getPermissions(): array; + } diff --git a/tests/modules/simple_oauth_test/src/Plugin/ScopeGranularity/TestGranularity.php b/tests/modules/simple_oauth_test/src/Plugin/ScopeGranularity/TestGranularity.php index e483fdbcdc90e04dd4658b57e94dc22bd05f2531..f6843efce9aaa8ce15b3e43b17a43adcbea013bc 100644 --- a/tests/modules/simple_oauth_test/src/Plugin/ScopeGranularity/TestGranularity.php +++ b/tests/modules/simple_oauth_test/src/Plugin/ScopeGranularity/TestGranularity.php @@ -58,6 +58,13 @@ class TestGranularity extends ScopeGranularityBase { return TRUE; } + /** + * {@inheritdoc} + */ + public function getPermissions(): array { + return []; + } + /** * {@inheritdoc} */ diff --git a/tests/src/Unit/Authentication/Provider/SimpleOauthAuthenticationTest.php b/tests/src/Unit/Authentication/Provider/SimpleOauthAuthenticationTest.php index 6671ac7327beea6bc25eeee1df4b63140e46edaf..6f2762d19d16f560a7da2cf6c0ce858b76dc431d 100644 --- a/tests/src/Unit/Authentication/Provider/SimpleOauthAuthenticationTest.php +++ b/tests/src/Unit/Authentication/Provider/SimpleOauthAuthenticationTest.php @@ -5,6 +5,7 @@ namespace Drupal\Tests\simple_oauth\Unit\Authentication\Provider; use Drupal\Core\Authentication\AuthenticationProviderInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\PageCache\RequestPolicyInterface; +use Drupal\Core\Session\PermissionCheckerInterface; use Drupal\TestTools\Random; use Drupal\Tests\UnitTestCase; use Drupal\simple_oauth\Authentication\Provider\SimpleOauthAuthenticationProvider; @@ -15,6 +16,7 @@ use Prophecy\PhpUnit\ProphecyTrait; use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface; use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; /** * @coversDefaultClass \Drupal\simple_oauth\Authentication\Provider\SimpleOauthAuthenticationProvider @@ -48,12 +50,16 @@ class SimpleOauthAuthenticationTest extends UnitTestCase { $this->oauthPageCacheRequestPolicy = new DisallowSimpleOauthRequests(); $http_message_factory = $this->prophesize(HttpMessageFactoryInterface::class); $http_foundation_factory = $this->prophesize(HttpFoundationFactoryInterface::class); + $request_stack = $this->prophesize(RequestStack::class); + $permission_checker = $this->prophesize(PermissionCheckerInterface::class); $this->provider = new SimpleOauthAuthenticationProvider( $resource_server_factory->reveal(), $entity_type_manager->reveal(), $this->oauthPageCacheRequestPolicy, $http_message_factory->reveal(), $http_foundation_factory->reveal(), + $request_stack->reveal(), + $permission_checker->reveal() ); }