diff --git a/oe_authentication.module b/oe_authentication.module new file mode 100644 index 00000000..ecb54034 --- /dev/null +++ b/oe_authentication.module @@ -0,0 +1,20 @@ +get('user.login')) { $defaults = $route->getDefaults(); unset($defaults['_form']); - $defaults['_controller'] = '\Drupal\oe_authentication\Controller\OeAuthenticationController::login'; + $defaults['_controller'] = '\Drupal\oe_authentication\Controller\AuthenticationController::login'; $route->setDefaults($defaults); } // Replace the core logout route. if ($route = $collection->get('user.logout')) { - $route->setDefault('_controller', '\Drupal\oe_authentication\Controller\OeAuthenticationController::logout'); + $route->setDefault('_controller', '\Drupal\oe_authentication\Controller\AuthenticationController::logout'); } // Remove these routes as to generate fatal errors wherever // functionality is missing. @@ -46,7 +46,7 @@ protected function alterRoutes(RouteCollection $collection) { ]; foreach ($routes_to_remove as $route_to_remove) { if ($route = $collection->get($route_to_remove)) { - $collection->remove($route_to_remove); + $route->setRequirement('_access', 'FALSE'); } } } diff --git a/src/UserProvider.php b/src/UserProvider.php index 4e82ee59..19f24133 100644 --- a/src/UserProvider.php +++ b/src/UserProvider.php @@ -5,6 +5,7 @@ namespace Drupal\oe_authentication; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\oe_authentication\Exception\AuthenticationException; use Drupal\user\UserInterface; use OpenEuropa\pcas\Security\Core\User\PCasUserInterface; @@ -84,13 +85,13 @@ protected function attachRoles(UserInterface $account, PCasUserInterface $pCasUs protected function doLoadAccount(PCasUserInterface $pCasUser) { $username = $pCasUser->get('cas:user'); if ($username === NULL) { - throw new \Exception('No username found on the PCas user.'); + throw new AuthenticationException('No username found on the PCas user.'); } $accounts = $this->userStorage->loadByProperties(['name' => $username]); if (empty($accounts)) { // Account does not exist, creation of new accounts is handled in. - // @see \Drupal\oe_authentication\Controller\OeAuthenticationController::login. + // @see \Drupal\oe_authentication\Controller\AuthenticationController::login. return FALSE; } @@ -108,8 +109,7 @@ protected function doLoadAccount(PCasUserInterface $pCasUser) { */ protected function createAccount(PCasUserInterface $pCasUser) { $name = $this->uniqueUsername($pCasUser->getUsername()); - // @todo Fix the retrieval of the email as not all CAS replies have "cas:email". - $mail = $pCasUser->get('cas:email'); + $mail = $this->extractEmailFromCasUser($pCasUser); /** @var \Drupal\user\Entity\User $account */ $account = $this->userStorage->create([ @@ -158,4 +158,37 @@ protected function canCreateNewAccounts() { return TRUE; } + /** + * Extracts the email address from a PCas user object. + * + * Since CAS implementations return differently the user information, + * we need to extract the email value generically. + * + * @todo Refactor and bring logic for user value retrieval to PCas library + * using configuration. + * + * @param \OpenEuropa\pcas\Security\Core\User\PCasUserInterface $pCasUser + * The PCas user object. + * + * @return string + * The email address. + */ + protected function extractEmailFromCasUser(PCasUserInterface $pCasUser): string { + if ($pCasUser->get('cas:email') !== NULL) { + return $pCasUser->get('cas:email'); + } + + // ECAS. + if ($pCasUser->get('cas:authenticationFactors') !== NULL) { + $auth_factors = $pCasUser->get('cas:authenticationFactors'); + if (isset($auth_factors['cas:moniker'])) { + return $auth_factors['cas:moniker']; + } + + throw new AuthenticationException('ECAS user email address is missing.'); + } + + throw new AuthenticationException('Could not determine user email from PCas response.'); + } + } diff --git a/tests/Kernel/PCasFactoryTest.php b/tests/Kernel/PCasFactoryTest.php new file mode 100644 index 00000000..edf000e1 --- /dev/null +++ b/tests/Kernel/PCasFactoryTest.php @@ -0,0 +1,75 @@ +installConfig([ + 'oe_authentication', + ]); + } + + /** + * Test default configuration options for the PCasFactory class. + */ + public function testDefaultConfiguration(): void { + $pcasfactory = new PCasFactory($this->container->get('session'), $this->container->get('config.factory')); + $pcas = $pcasfactory->getPCas(); + $properties = $pcas->getProperties(); + $this->assertEquals('http://authentication:8001', $properties['base_url']); + $login_protocol = [ + 'path' => '/login', + 'query' => [], + 'allowed_parameters' => ['service', 'renew', 'gateway'], + ]; + $this->assertEquals($login_protocol, $properties['protocol']['login']); + } + + /** + * Test custom configuration options for the PCasFactory class. + */ + public function testCustomConfiguration(): void { + $this->config('oe_authentication.settings') + ->set('base_url', 'https://ecas.ec.europa.eu/cas') + ->save(TRUE); + $protocols = [ + 'login' => [ + 'path' => '/login', + 'query' => [], + 'allowed_parameters' => ['service', 'renew', 'gateway'], + ], + ]; + $pcasfactory = new PCasFactory($this->container->get('session'), $this->container->get('config.factory'), $protocols); + $pcas = $pcasfactory->getPCas(); + $properties = $pcas->getProperties(); + $this->assertEquals('https://ecas.ec.europa.eu/cas', $properties['base_url']); + $this->assertEquals($protocols, $properties['protocol']); + } + +}