diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 637199fb..db09c375 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,20 +1,24 @@ **GitHub Issue**: (link) -* Other Relevant Links (Google Groups discussion, related pull requests, Release pull requests, etc.) +* Other Relevant Links (Google Groups discussion, related pull requests, + Release pull requests, etc.) # What does this Pull Request do? -A brief description of what the intended result of the PR will be and/or what problem it solves. +A brief description of what the intended result of the PR will be and/or what + problem it solves. # What's new? -A in-depth description of the changes made by this PR. Technical details and possible side effects. +A in-depth description of the changes made by this PR. Technical details and + possible side effects. * Changes x feature to such that y * Added x * Removed y * Does this change require documentation to be updated? * Does this change add any new dependencies? -* Does this change require any other modifications to be made to the repository (ie. Regeneration activity, etc.)? +* Does this change require any other modifications to be made to the repository + (ie. Regeneration activity, etc.)? * Could this change impact execution of existing code? # How should this be tested? @@ -26,7 +30,8 @@ A description of what steps someone could take to: * Good testing instructions help get your PR completed faster. # Additional Notes: -Any additional information that you think would be helpful when reviewing this PR. +Any additional information that you think would be helpful when reviewing this + PR. # Interested parties -Tag (@ mention) interested parties or, if unsure, @Islandora-CLAW/committers \ No newline at end of file +Tag (@ mention) interested parties or, if unsure, @Islandora-CLAW/committers diff --git a/.gitignore b/.gitignore index 22d0d82f..3572ca42 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ vendor +/.idea/ diff --git a/composer.json b/composer.json index 19c5ef79..e0dec094 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,8 @@ "drupal/rules": "^3.0@alpha", "drupal/search_api": "^1.0@beta", "islandora/claw-jsonld": "dev-8.x-1.x", - "stomp-php/stomp-php": "4.*" + "stomp-php/stomp-php": "4.*", + "drupal/jwt": "1.0.0-alpha6" }, "require-dev": { "phpunit/phpunit": "^4.8", diff --git a/config/install/core.entity_form_display.fedora_resource.rdf_source.default.yml b/config/install/core.entity_form_display.fedora_resource.rdf_source.default.yml index 802d45ae..5fc2de42 100644 --- a/config/install/core.entity_form_display.fedora_resource.rdf_source.default.yml +++ b/config/install/core.entity_form_display.fedora_resource.rdf_source.default.yml @@ -64,4 +64,3 @@ content: placeholder: '' third_party_settings: { } hidden: { } - diff --git a/config/install/core.entity_view_mode.fedora_resource.teaser.yml b/config/install/core.entity_view_mode.fedora_resource.teaser.yml index d76f3f15..be1fa1a3 100644 --- a/config/install/core.entity_view_mode.fedora_resource.teaser.yml +++ b/config/install/core.entity_view_mode.fedora_resource.teaser.yml @@ -11,4 +11,3 @@ id: fedora_resource.teaser label: Teaser targetEntityType: fedora_resource cache: true - diff --git a/config/install/field.field.fedora_resource.rdf_source.field_ldp_contains.yml b/config/install/field.field.fedora_resource.rdf_source.field_ldp_contains.yml index 9810847c..1e2ece6d 100644 --- a/config/install/field.field.fedora_resource.rdf_source.field_ldp_contains.yml +++ b/config/install/field.field.fedora_resource.rdf_source.field_ldp_contains.yml @@ -28,4 +28,3 @@ settings: display_name: entity_reference_1 arguments: { } field_type: entity_reference - diff --git a/config/install/islandora.settings.yml b/config/install/islandora.settings.yml index 7c052397..60a09ba9 100644 --- a/config/install/islandora.settings.yml +++ b/config/install/islandora.settings.yml @@ -3,4 +3,3 @@ fedora_rest_endpoint: 'http://localhost:8080/fcrepo/rest' _core: default_config_hash: nDZDR2rrpXXQ-D_7BYrdDFAXYOsB5hgH6vCAMV5I3w8 broadcast_queue: islandora-connector-broadcast - diff --git a/config/install/rdf.mapping.fedora_resource_type.non_rdf_source.yml b/config/install/rdf.mapping.fedora_resource_type.non_rdf_source.yml index 0752fc35..521af677 100644 --- a/config/install/rdf.mapping.fedora_resource_type.non_rdf_source.yml +++ b/config/install/rdf.mapping.fedora_resource_type.non_rdf_source.yml @@ -45,4 +45,3 @@ fieldMappings: properties: - 'ldp:contains' mapping_type: rel - diff --git a/config/install/rdf.mapping.fedora_resource_type.rdf_source.yml b/config/install/rdf.mapping.fedora_resource_type.rdf_source.yml index 127b2e3a..071b3787 100644 --- a/config/install/rdf.mapping.fedora_resource_type.rdf_source.yml +++ b/config/install/rdf.mapping.fedora_resource_type.rdf_source.yml @@ -49,4 +49,3 @@ fieldMappings: properties: - 'ldp:contains' mapping_type: rel - diff --git a/config/install/rest.resource.entity.fedora_resource.yml b/config/install/rest.resource.entity.fedora_resource.yml index d4916551..15989cac 100644 --- a/config/install/rest.resource.entity.fedora_resource.yml +++ b/config/install/rest.resource.entity.fedora_resource.yml @@ -21,6 +21,4 @@ configuration: - json - xml supported_auth: - - basic_auth - - cookie - + - jwt_auth diff --git a/config/install/rules.reaction.broadcast_create_event.yml b/config/install/rules.reaction.broadcast_create_event.yml index 95e35c54..e2a097ce 100644 --- a/config/install/rules.reaction.broadcast_create_event.yml +++ b/config/install/rules.reaction.broadcast_create_event.yml @@ -54,4 +54,3 @@ expression: rules_tokens: { } provides_mapping: { } action_id: islandora_broadcast - diff --git a/config/install/rules.reaction.broadcast_delete_event.yml b/config/install/rules.reaction.broadcast_delete_event.yml index cb470615..f3a830ef 100644 --- a/config/install/rules.reaction.broadcast_delete_event.yml +++ b/config/install/rules.reaction.broadcast_delete_event.yml @@ -54,4 +54,3 @@ expression: rules_tokens: { } provides_mapping: { } action_id: islandora_broadcast - diff --git a/config/install/rules.reaction.broadcast_update_event.yml b/config/install/rules.reaction.broadcast_update_event.yml index deedc0cb..8db4f929 100644 --- a/config/install/rules.reaction.broadcast_update_event.yml +++ b/config/install/rules.reaction.broadcast_update_event.yml @@ -54,4 +54,3 @@ expression: rules_tokens: { } provides_mapping: { } action_id: islandora_broadcast - diff --git a/config/install/views.view.fedora_entities_reference.yml b/config/install/views.view.fedora_entities_reference.yml index b3aa6a67..b34cf8e0 100644 --- a/config/install/views.view.fedora_entities_reference.yml +++ b/config/install/views.view.fedora_entities_reference.yml @@ -167,4 +167,3 @@ display: - 'languages:language_interface' - user.permissions tags: { } - diff --git a/config/schema/fedora_resource_type.schema.yml b/config/schema/fedora_resource_type.schema.yml index 62d75a09..cde84179 100644 --- a/config/schema/fedora_resource_type.schema.yml +++ b/config/schema/fedora_resource_type.schema.yml @@ -21,4 +21,4 @@ search.plugin.node_search: label: 'Content ranking' sequence: type: integer - label: 'Influence' \ No newline at end of file + label: 'Influence' diff --git a/config/schema/islandora.schema.yml b/config/schema/islandora.schema.yml index 8756286d..6c88ccbc 100644 --- a/config/schema/islandora.schema.yml +++ b/config/schema/islandora.schema.yml @@ -11,4 +11,3 @@ islandora.settings: broadcast_queue: type: string label: 'Queue that handles distributing messages amongst multiple recipients' - diff --git a/islandora.info.yml b/islandora.info.yml index ed5c110d..20f75325 100644 --- a/islandora.info.yml +++ b/islandora.info.yml @@ -15,4 +15,4 @@ dependencies: - jsonld - rules - search_api -version: '8.x-1.x-dev' + - jwt diff --git a/islandora.links.action.yml b/islandora.links.action.yml index 2666c978..2aa6bf43 100644 --- a/islandora.links.action.yml +++ b/islandora.links.action.yml @@ -8,4 +8,3 @@ entity.fedora_resource_type.add_form: title: 'Add Fedora resource type' appears_on: - entity.fedora_resource_type.collection - diff --git a/islandora.permissions.yml b/islandora.permissions.yml index d5b5fb4e..e1fc0a80 100644 --- a/islandora.permissions.yml +++ b/islandora.permissions.yml @@ -23,4 +23,4 @@ view unpublished fedora resource entities: administer fedora resource type entities: title: 'Administer Fedora Resource Type entities' description: 'Allow to access administration of Fedora Resource Type entities (bundles).' - restrict access: true \ No newline at end of file + restrict access: true diff --git a/islandora.services.yml b/islandora.services.yml index e17fb7c4..d078fe08 100644 --- a/islandora.services.yml +++ b/islandora.services.yml @@ -12,3 +12,9 @@ services: class: Stomp\StatefulStomp factory: ['Drupal\islandora\StompFactory', create] arguments: ['@config.factory'] + islandora.jwt-subscriber: + class: Drupal\islandora\EventSubscriber\JwtEventSubscriber + factory: ['Drupal\islandora\EventSubscriber\JwtEventSubscriber', create] + arguments: ['@entity_type.manager', '@current_user'] + tags: + - { name: event_subscriber } diff --git a/src/Controller/FedoraResourceAddController.php b/src/Controller/FedoraResourceAddController.php index 738424ff..9b33634a 100644 --- a/src/Controller/FedoraResourceAddController.php +++ b/src/Controller/FedoraResourceAddController.php @@ -86,7 +86,7 @@ class FedoraResourceAddController extends ControllerBase { /** * Presents the creation form for fedora_resource entities of given type. * - * @param EntityInterface $fedora_resource_type + * @param \Drupal\Core\Entity\EntityInterface $fedora_resource_type * The custom bundle to add. * @param \Symfony\Component\HttpFoundation\Request $request * The current request object. @@ -104,7 +104,7 @@ class FedoraResourceAddController extends ControllerBase { /** * Provides the page title for this controller. * - * @param EntityInterface $fedora_resource_type + * @param \Drupal\Core\Entity\EntityInterface $fedora_resource_type * The custom bundle/type being added. * * @return string diff --git a/src/Entity/FedoraResource.php b/src/Entity/FedoraResource.php index c2ed215b..f31e16d0 100644 --- a/src/Entity/FedoraResource.php +++ b/src/Entity/FedoraResource.php @@ -69,26 +69,6 @@ class FedoraResource extends ContentEntityBase implements FedoraResourceInterfac use EntityChangedTrait; - /** - * Override this to have a rel ='uuid' for islandora entities. - * - * Stolen (but not inherited from EntityInterface) - * - * @param string $rel - * The link relationship type, for example: canonical or edit-form. - * @param array $options - * See \Drupal\Core\Routing\UrlGeneratorInterface::generateFromRoute() for - * the available options. - * - * @return \Drupal\Core\Url - * The URL object. - */ - public function toUrl($rel = 'canonical', array $options = []) { - // TODO: I Will override this to have a rel ='uuid' for islandora entities - // TODO: Change the autogenerated stub. - return parent::toUrl($rel, $options); - } - /** * Gets an array of placeholders for Fedora Resource Entity. * diff --git a/src/EventSubscriber/JwtEventSubscriber.php b/src/EventSubscriber/JwtEventSubscriber.php new file mode 100644 index 00000000..d32d4834 --- /dev/null +++ b/src/EventSubscriber/JwtEventSubscriber.php @@ -0,0 +1,140 @@ +userStorage = $userStorage; + $this->currentUser = $user; + } + + /** + * Factory. + * + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityManager + * Entity manager to get user storage. + * @param \Drupal\Core\Session\AccountInterface $user + * The current user. + */ + public static function create( + EntityTypeManagerInterface $entityManager, + AccountInterface $user + ) { + return new static( + $entityManager->getStorage('user'), + $user + ); + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + $events[JwtAuthEvents::VALIDATE][] = ['validate']; + $events[JwtAuthEvents::VALID][] = ['loadUser']; + $events[JwtAuthEvents::GENERATE][] = ['setIslandoraClaims']; + + return $events; + } + + /** + * Sets claims for a Islandora consumer on the JWT. + * + * @param \Drupal\jwt\Authentication\Event\JwtAuthGenerateEvent $event + * The event. + */ + public function setIslandoraClaims(JwtAuthGenerateEvent $event) { + global $base_secure_url; + + // Standard claims, validated at JWT validation time. + $event->addClaim('iat', time()); + $event->addClaim('exp', strtotime('+2 hour')); + + // Islandora claims we need to validate. + $event->addClaim('uid', $this->currentUser->id()); + $event->addClaim('name', $this->currentUser->getAccountName()); + $event->addClaim('roles', $this->currentUser->getRoles(FALSE)); + $event->addClaim('url', $base_secure_url); + } + + /** + * Validates that the Islandora data is present in the JWT. + * + * @param \Drupal\jwt\Authentication\Event\JwtAuthValidateEvent $event + * A JwtAuth event. + */ + public function validate(JwtAuthValidateEvent $event) { + $token = $event->getToken(); + + $uid = $token->getClaim('uid'); + $name = $token->getClaim('name'); + $roles = $token->getClaim('roles'); + $url = $token->getClaim('url'); + if ($uid === NULL || $name === NULL || $roles === NULL || $url === NULL) { + $event->invalidate("Expected data missing from payload."); + return; + } + + $user = $this->userStorage->load($uid); + if ($user === NULL) { + $event->invalidate("Specified UID does not exist."); + } + elseif ($user->getAccountName() !== $name) { + $event->invalidate("Account name does not match."); + } + } + + /** + * Load and set a Drupal user to be authentication based on the JWT's uid. + * + * @param \Drupal\jwt\Authentication\Event\JwtAuthValidEvent $event + * A JwtAuth event. + */ + public function loadUser(JwtAuthValidEvent $event) { + $token = $event->getToken(); + $uid = $token->getClaim('uid'); + $user = $this->userStorage->load($uid); + $event->setUser($user); + } + +} diff --git a/src/FedoraResourceInterface.php b/src/FedoraResourceInterface.php index 806504d7..59e871d3 100644 --- a/src/FedoraResourceInterface.php +++ b/src/FedoraResourceInterface.php @@ -86,7 +86,7 @@ interface FedoraResourceInterface extends ContentEntityInterface, EntityChangedI * Does the entity have a parent entity? * * @return bool - * Whether a parent entity was set. + * Whether a parent entity was set. */ public function hasParent(); @@ -94,7 +94,7 @@ interface FedoraResourceInterface extends ContentEntityInterface, EntityChangedI * Gets the id of the parent entity. * * @return int - * The id of the parent Fedora resource entity. + * The id of the parent Fedora resource entity. */ public function getParentId(); @@ -102,7 +102,7 @@ interface FedoraResourceInterface extends ContentEntityInterface, EntityChangedI * Get the parent entity. * * @return \Drupal\islandora\FedoraResourceInterface - * The actual entity of the parent Fedora resource. + * The actual entity of the parent Fedora resource. */ public function getParent(); @@ -110,10 +110,10 @@ interface FedoraResourceInterface extends ContentEntityInterface, EntityChangedI * Get the parent entity. * * @param \Drupal\Core\Entity\EntityTypeInterface $entity - * The parent entity. + * The parent entity. * * @return \Drupal\islandora\FedoraResourceInterface - * The called Fedora resource entity. + * The called Fedora resource entity. */ public function setParent(EntityTypeInterface $entity); diff --git a/src/Plugin/RulesAction/Broadcaster.php b/src/Plugin/RulesAction/Broadcaster.php index 05140f29..09abcd48 100644 --- a/src/Plugin/RulesAction/Broadcaster.php +++ b/src/Plugin/RulesAction/Broadcaster.php @@ -5,6 +5,7 @@ namespace Drupal\islandora\Plugin\RulesAction; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\islandora\Form\IslandoraSettingsForm; use Drupal\rules\Core\RulesActionBase; +use Drupal\jwt\Authentication\Provider\JwtAuth; use Stomp\Exception\StompException; use Stomp\StatefulStomp; use Stomp\Transport\Message; @@ -45,6 +46,13 @@ class Broadcaster extends RulesActionBase implements ContainerFactoryPluginInter */ protected $broadcastQueue; + /** + * The JWT Auth Service. + * + * @var \Drupal\jwt\Authentication\Provider\JwtAuth + */ + protected $auth; + /** * Constructs a BroadcastAction. * @@ -58,12 +66,22 @@ class Broadcaster extends RulesActionBase implements ContainerFactoryPluginInter * Name of queue that will handle distributing the broadcast. * @param \Stomp\StatefulStomp $stomp * Stomp client. + * @param \Drupal\jwt\Authentication\Provider\JwtAuth $auth + * JWT Auth client. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, $broadcast_queue, StatefulStomp $stomp) { + public function __construct( + array $configuration, + $plugin_id, + $plugin_definition, + $broadcast_queue, + StatefulStomp $stomp, + JwtAuth $auth + ) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->broadcastQueue = $broadcast_queue; $this->stomp = $stomp; + $this->auth = $auth; } /** @@ -79,7 +97,8 @@ class Broadcaster extends RulesActionBase implements ContainerFactoryPluginInter $plugin_id, $plugin_definition, $broadcastQueue, - $container->get('islandora.stomp') + $container->get('islandora.stomp'), + $container->get('jwt.authentication.jwt') ); } @@ -95,9 +114,25 @@ class Broadcaster extends RulesActionBase implements ContainerFactoryPluginInter // Transform recipients array into comma searated list. $recipients = array_map('trim', $recipients); $recipients = implode(',', $recipients); + $headers = ['IslandoraBroadcastRecipients' => $recipients]; + + // Include a token for later authentication in the message. + $token = $this->auth->generateToken(); + if ($token !== NULL) { + $headers['Authorization'] = "Bearer $token"; + } + else { + // JWT isn't properly configured. Log and notify user. + \Drupal::logger('islandora')->error( + 'Error getting JWT token for message: @msg', ['@msg' => $e->getMessage()] + ); + drupal_set_message( + t('Error getting JWT token for message. Check JWT Configuration.'), 'error' + ); + } // Transform message from string into a proper message object. - $message = new Message($message, ['IslandoraBroadcastRecipients' => $recipients]); + $message = new Message($message, $headers); // Send the message. try { diff --git a/src/Plugin/Search/FedoraEntitySearch.php b/src/Plugin/Search/FedoraEntitySearch.php index 6bec2546..e1905ef9 100644 --- a/src/Plugin/Search/FedoraEntitySearch.php +++ b/src/Plugin/Search/FedoraEntitySearch.php @@ -155,7 +155,7 @@ class FedoraResourceSearch extends ConfigurableSearchPluginBase implements Acces /** * {@inheritdoc} */ - static public function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $configuration, $plugin_id, @@ -189,6 +189,8 @@ class FedoraResourceSearch extends ConfigurableSearchPluginBase implements Acces * A config object for 'search.settings'. * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager * The language manager. + * @param \Drupal\Core\Render\RendererInterface $renderer + * Renderer. * @param \Drupal\Core\Session\AccountInterface $account * The $account object to use for checking for access to advanced search. */ @@ -458,7 +460,7 @@ class FedoraResourceSearch extends ConfigurableSearchPluginBase implements Acces /** * Adds the configured rankings to the search query. * - * @param SelectExtender $query + * @param \Drupal\Core\Database\Query\SelectExtender $query * A query object that has been extended with the Search DB Extender. */ protected function addFedoraResourceRankings(SelectExtender $query) { diff --git a/src/StompFactory.php b/src/StompFactory.php index 53c01a60..3f170182 100644 --- a/src/StompFactory.php +++ b/src/StompFactory.php @@ -21,7 +21,7 @@ class StompFactory { * @return \Stomp\StatefulStomp * Stomp client. */ - static public function create(ConfigFactoryInterface $config) { + public static function create(ConfigFactoryInterface $config) { // Get broker url from config. $settings = $config->get(IslandoraSettingsForm::CONFIG_NAME); $brokerUrl = $settings->get(IslandoraSettingsForm::BROKER_URL); diff --git a/tests/src/Kernel/BroadcasterTest.php b/tests/src/Kernel/BroadcasterTest.php index 81bfd330..02b023ab 100644 --- a/tests/src/Kernel/BroadcasterTest.php +++ b/tests/src/Kernel/BroadcasterTest.php @@ -97,7 +97,7 @@ class BroadcasterTest extends IslandoraKernelTestBase { /** * Utility function to create a broadcaster action from a Stomp prophecy. * - * @param StatefulStomp $stomp + * @param \Stomp\StatefulStomp $stomp * Stomp instance or prophecy. * * @return \Drupal\islandora\Plugin\RulesAction\Broadcaster @@ -106,6 +106,7 @@ class BroadcasterTest extends IslandoraKernelTestBase { protected function createBroadcaster(StatefulStomp $stomp) { // Pull the plugin definition out of the plugin system. $actionManager = $this->container->get('plugin.manager.rules_action'); + $jwt = $this->container->get('jwt.authentication.jwt'); $definitions = $actionManager->getDefinitions(); $pluginDefinition = $definitions['islandora_broadcast']; @@ -114,7 +115,8 @@ class BroadcasterTest extends IslandoraKernelTestBase { 'islandora_broadcast', $pluginDefinition, $this->testQueue, - $stomp + $stomp, + $jwt ); // Set the required contexts for the action to run. diff --git a/tests/src/Kernel/IslandoraKernelTestBase.php b/tests/src/Kernel/IslandoraKernelTestBase.php index bff7d6d9..a3884941 100644 --- a/tests/src/Kernel/IslandoraKernelTestBase.php +++ b/tests/src/Kernel/IslandoraKernelTestBase.php @@ -30,6 +30,8 @@ abstract class IslandoraKernelTestBase extends KernelTestBase { 'rules', 'jsonld', 'views', + 'key', + 'jwt', 'islandora', ]; diff --git a/tests/src/Kernel/JwtEventSubscriberTest.php b/tests/src/Kernel/JwtEventSubscriberTest.php new file mode 100644 index 00000000..449f84bc --- /dev/null +++ b/tests/src/Kernel/JwtEventSubscriberTest.php @@ -0,0 +1,141 @@ +user = $this->createUser(); + } + + /** + * @covers \Drupal\islandora\EventSubscriber\JwtEventSubscriber::setIslandoraClaims + */ + public function testGeneratesValidToken() { + $entity_storage = $this->container->get('entity_type.manager')->getStorage('user'); + $subscriber = new JwtEventSubscriber($entity_storage, $this->user); + + // Generate a new token. + $jwt = new JsonWebToken(); + $event = new JwtAuthGenerateEvent($jwt); + $subscriber->setIslandoraClaims($event); + + // Validate it. + $validateEvent = new JwtAuthValidateEvent($jwt); + $subscriber->validate($validateEvent); + + $this->assert($validateEvent->isValid(), "Generated tokens must be valid."); + } + + /** + * @covers \Drupal\islandora\EventSubscriber\JwtEventSubscriber::validate + */ + public function testInvalidatesMalformedToken() { + $entity_storage = $this->container->get('entity_type.manager')->getStorage('user'); + $subscriber = new JwtEventSubscriber($entity_storage, $this->user); + + // Create a new event with mock jwt that returns null for all functions. + $prophecy = $this->prophesize(JsonWebTokenInterface::class); + $jwt = $prophecy->reveal(); + $event = new JwtAuthValidateEvent($jwt); + + $subscriber->validate($event); + + assert(!$event->isValid(), "Malformed event must be invalidated"); + } + + /** + * @covers \Drupal\islandora\EventSubscriber\JwtEventSubscriber::validate + */ + public function testInvalidatesBadUid() { + // Mock user entity storage, returns null when loading user. + $prophecy = $this->prophesize(EntityStorageInterface::class); + $entity_storage = $prophecy->reveal(); + + $subscriber = new JwtEventSubscriber($entity_storage, $this->user); + + // Generate a new token. + $jwt = new JsonWebToken(); + $event = new JwtAuthGenerateEvent($jwt); + $subscriber->setIslandoraClaims($event); + + // Validate it. + $validateEvent = new JwtAuthValidateEvent($jwt); + $subscriber->validate($validateEvent); + + assert(!$validateEvent->isValid(), "Event must be invalidated when user cannot be loaded."); + } + + /** + * @covers \Drupal\islandora\EventSubscriber\JwtEventSubscriber::validate + */ + public function testInvliadatesBadAccount() { + $anotherUser = $this->createUser(); + + // Mock user entity storage, loads the wrong user. + $prophecy = $this->prophesize(EntityStorageInterface::class); + $prophecy->load($this->user->id())->willReturn($anotherUser); + $entity_storage = $prophecy->reveal(); + + $subscriber = new JwtEventSubscriber($entity_storage, $this->user); + + // Generate a new token. + $jwt = new JsonWebToken(); + $event = new JwtAuthGenerateEvent($jwt); + $subscriber->setIslandoraClaims($event); + + // Validate it. + $validateEvent = new JwtAuthValidateEvent($jwt); + $subscriber->validate($validateEvent); + + assert(!$validateEvent->isValid(), "Event must be invalidated when users don't align."); + } + + /** + * @covers \Drupal\islandora\EventSubscriber\JwtEventSubscriber::loadUser + */ + public function testLoadsUser() { + $entity_storage = $this->container->get('entity_type.manager')->getStorage('user'); + $subscriber = new JwtEventSubscriber($entity_storage, $this->user); + + // Generate a new token. + $jwt = new JsonWebToken(); + $event = new JwtAuthGenerateEvent($jwt); + $subscriber->setIslandoraClaims($event); + + $validEvent = new JwtAuthValidEvent($jwt); + $subscriber->loadUser($validEvent); + + $this->assert($validEvent->getUser()->id() == $this->user->id(), "Correct user must be loaded to valid event."); + } + +}