diff --git a/helfi_tunnistamo.module b/helfi_tunnistamo.module index bf3aa72..467c0fd 100644 --- a/helfi_tunnistamo.module +++ b/helfi_tunnistamo.module @@ -26,6 +26,15 @@ function helfi_tunnistamo_openid_connect_post_authorize(UserInterface $account, } $plugin->mapRoles($account, $context); $plugin->setUserPreferredAdminLanguage($account); + + // Once user logs in with openid connect, set user password to null. + // This prevents the user from logging in with the local user in the + // future. + if ($account->getPassword()) { + $account + ->setPassword(NULL) + ->save(); + } } /** diff --git a/helfi_tunnistamo.services.yml b/helfi_tunnistamo.services.yml index a1bff56..c92e0b2 100644 --- a/helfi_tunnistamo.services.yml +++ b/helfi_tunnistamo.services.yml @@ -1,9 +1,11 @@ services: - helfi_tunnistamo.http_exception_subscriber: - class: Drupal\helfi_tunnistamo\EventSubscriber\HttpExceptionSubscriber - arguments: ['@entity_type.manager', '@openid_connect.session', '@current_user'] - tags: - - { name: event_subscriber } + _defaults: + autowire: true + autoconfigure: true + logger.channel.helfi_tunnistamo: parent: logger.channel_base arguments: [ 'helfi_tunnistamo' ] + + Drupal\helfi_tunnistamo\EventSubscriber\HttpExceptionSubscriber: ~ + Drupal\helfi_tunnistamo\EventSubscriber\DisableExternalUsersPasswordSubscriber: ~ diff --git a/src/EventSubscriber/DisableExternalUsersPasswordSubscriber.php b/src/EventSubscriber/DisableExternalUsersPasswordSubscriber.php new file mode 100644 index 0000000..95c1c7f --- /dev/null +++ b/src/EventSubscriber/DisableExternalUsersPasswordSubscriber.php @@ -0,0 +1,59 @@ +database->select('authmap', 'am'); + $query->leftJoin('users_field_data', 'ufd', 'ufd.uid = am.uid'); + $query + ->fields('am', ['uid']) + ->condition('ufd.pass', NULL, 'IS NOT NULL') + // Make sure we have an upper bound. + ->range(0, 50); + + $storage = $this->entityTypeManager->getStorage('user'); + foreach ($query->execute()->fetchCol() as $id) { + /** @var \Drupal\user\UserInterface $account */ + $account = $storage->load($id); + + // Set user password to null. This prevents the user + // from logging in with the local user in the future. + $account + ->setPassword(NULL) + ->save(); + } + } + +} diff --git a/src/EventSubscriber/HttpExceptionSubscriber.php b/src/EventSubscriber/HttpExceptionSubscriber.php index d9d6fdb..0fcfc86 100644 --- a/src/EventSubscriber/HttpExceptionSubscriber.php +++ b/src/EventSubscriber/HttpExceptionSubscriber.php @@ -9,6 +9,7 @@ use Drupal\Core\Session\AccountProxyInterface; use Drupal\helfi_tunnistamo\Plugin\OpenIDConnectClient\Tunnistamo; use Drupal\openid_connect\OpenIDConnectSession; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpKernel\Event\ExceptionEvent; /** @@ -28,6 +29,7 @@ final class HttpExceptionSubscriber extends HttpExceptionSubscriberBase { */ public function __construct( private EntityTypeManagerInterface $entityTypeManager, + #[Autowire(service: 'openid_connect.session')] private OpenIDConnectSession $session, private AccountProxyInterface $accountProxy, ) { diff --git a/tests/src/Kernel/DisableExternalUsersPasswordSubscriberTest.php b/tests/src/Kernel/DisableExternalUsersPasswordSubscriberTest.php new file mode 100644 index 0000000..9f45d04 --- /dev/null +++ b/tests/src/Kernel/DisableExternalUsersPasswordSubscriberTest.php @@ -0,0 +1,52 @@ +container->get('externalauth.authmap'); + $external = $this->createUser(values: ['pass' => '123']); + $local = $this->createUser(values: ['pass' => '123']); + + // Add external auth to user. + $authmap->save($external, 'test_provider', 'test_authname'); + + // User login is enabled. + $this->assertNotEmpty($external->getPassword()); + $this->assertNotEmpty($local->getPassword()); + + $this->triggerEvent(); + + // User password is disabled. + $this->assertEmpty(User::load($external->id())->getPassword()); + $this->assertNotEmpty(User::load($local->id())->getPassword()); + } + + /** + * Triggers the post deploy event. + */ + private function triggerEvent() : void { + /** @var \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $service */ + $service = $this->container->get('event_dispatcher'); + $service->dispatch(new PostDeployEvent()); + } + +}