Skip to content

Commit

Permalink
Merge pull request #15 from itk-dev/feature/multiple-stuff
Browse files Browse the repository at this point in the history
Feature/multiple stuff
  • Loading branch information
jekuaitk authored Aug 3, 2023
2 parents 93590b5 + 35cc4ba commit 1975317
Show file tree
Hide file tree
Showing 13 changed files with 462 additions and 65 deletions.
36 changes: 31 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ Implements an [OS2Web NemLog-in
`AuthProvider`](https://github.com/OS2web/os2web_nemlogin/blob/master/src/Annotation/AuthProvider.php),
[`OpenIDConnect`](src/Plugin/os2web/NemloginAuthProvider/OpenIDConnect.php), for
authenticating with [OpenID Connect](https://openid.net/connect/).
But allows for multiple of these to be defined eg. AD and NemLogin.

A controller,
[`OpenIDConnectController`](src/Controller/OpenIDConnectController.php), takes
care of the actual NemLog-in authenticating.
care of the actual authenticating.

## Installation

Expand All @@ -16,12 +17,24 @@ composer require itk-dev/os2forms_nemlogin_openid_connect
vendor/bin/drush pm:enable os2forms_nemlogin_openid_connect
```

The module has a soft dependency on `os2forms_organisation` in the sense that
the `OrganisationEventSubscriber` only will be initialized if the
`os2forms_organisation` module is installed. See the comments in
`OrganisationEventSubscriber::getSubscribedEvents`.

## Configuration

Go to `/admin/config/system/os2web-nemlogin/OpenIDConnect` to set up the OpenID
Go to `/admin/os2forms_nemlogin_openid_connect/settings` to set up providers, eg.

```yaml
openid_connect_nemlogin: OpenIDConnect Nemlogin
openid_connect_ad: OpenIDConnect AD
```
and then go to `/admin/config/system/os2web-nemlogin/«id»` to set up the OpenID
Connect configuration.

Enable “OpenIDConnect Nemlogin auth provider on
You should then see the provider having status `OK` on
`/admin/config/system/os2web-nemlogin`.

## Use on a webform
Expand All @@ -38,7 +51,7 @@ the form by requiring the value of a field (pre-filled with a value from a
previous submission) to match the value of a specified user property.

Before using authentication checks, “User claims” available for the checks must
be defined on `/admin/config/system/os2web-nemlogin/OpenIDConnect`.
be defined on `/admin/config/system/os2web-nemlogin/«id»`.

Edit a webform, go to Settings > Third Party Settings > OS2Forms > OS2Forms
NemID settings > Authentication settings and define which “User claim” value
Expand All @@ -47,7 +60,7 @@ must match a “Form element” value:
![Authentication settings](docs/assets/authentication-settings.png)

Note: The authentication check sits on top of the other access checks in
OS2Forms, i.e. it does not itself grant access, but adds additonal requirements
OS2Forms, i.e. it does not itself grant access, but adds additional requirements
that must be fulfilled before a user can fill in a form.

## Local test
Expand All @@ -69,4 +82,17 @@ $settings['os2forms_nemlogin_openid_connect']['local_test_users'] = [
],
];
// Override settings for specific plugins:
$settings['os2forms_nemlogin_openid_connect']['my-plugin-id']['local_test_mode'] = FALSE;
// Define local test users
// User id => user info (claims)
$settings['os2forms_nemlogin_openid_connect']['another-plugin-id']['local_test_users'] = [
'user087' => [
'id' => 'user087',
'name' => 'User 87',
],
];
```
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"itk-dev/openid-connect": "^3.1",
"itk-dev/drupal_psr6_cache": "^1.0",
"os2web/os2web_nemlogin": "^1.2",
"drupal/webform": "^6.0"
"drupal/webform": "^6.0",
"symfony/options-resolver": "^5.4 || ^6.0"
},
"require-dev": {
"drupal/coder": "^8.3",
Expand Down
2 changes: 2 additions & 0 deletions os2forms_nemlogin_openid_connect.info.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ dependencies:
# hook_webform_submission_prepare_form run after the one in os2forms_forloeb.
- drupal:os2forms_forloeb
- drupal:os2web_nemlogin

configure: os2forms_nemlogin_openid_connect.admin.settings
27 changes: 27 additions & 0 deletions os2forms_nemlogin_openid_connect.module
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\os2forms_nemlogin_openid_connect\Helper\Settings;
use Drupal\os2forms_nemlogin_openid_connect\Helper\WebformHelper;
use Drupal\webform\WebformSubmissionInterface;

Expand Down Expand Up @@ -62,8 +63,34 @@ function os2forms_nemlogin_openid_connect_theme(array $existing, string $type, s
'os2forms_nemlogin_openid_connect_local_test_users' => [
'variables' => [
'users' => NULL,
'plugin' => NULL,
'query' => NULL,
],
],
];
}

/**
* Implements hook_os2web_nemlogin_auth_provider_info_alter().
*
* Adds an OpenIDConnect auth provider for each declared provider.
*
* @see \Drupal\os2forms_nemlogin_openid_connect\Plugin\os2web\NemloginAuthProvider\OpenIDConnect
*
* @phpstan-param array<string, mixed> $definitions
*/
function os2forms_nemlogin_openid_connect_os2web_nemlogin_auth_provider_info_alter(array &$definitions): void {
if (isset($definitions['OpenIDConnect'])) {
$template = $definitions['OpenIDConnect'];
unset($definitions['OpenIDConnect']);

$providers = Drupal::service(Settings::class)->getProvidersAsArray();

foreach ($providers as $id => $label) {
$definitions[$id] = [
'id' => $id,
'label' => $label,
] + $template;
}
}
}
12 changes: 10 additions & 2 deletions os2forms_nemlogin_openid_connect.routing.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
os2forms_nemlogin_openid_connect.openid_connect_authenticate:
path: '/os2forms_nemlogin_openid_connect/authenticate'
path: '/os2forms_nemlogin_openid_connect/authenticate/{id}'
defaults:
_controller: 'Drupal\os2forms_nemlogin_openid_connect\Controller\OpenIDConnectController::main'
requirements:
Expand All @@ -9,11 +9,19 @@ os2forms_nemlogin_openid_connect.openid_connect_authenticate:
no_cache: 'TRUE'

os2forms_nemlogin_openid_connect.openid_connect_end_session:
path: '/os2forms_nemlogin_openid_connect/end-session'
path: '/os2forms_nemlogin_openid_connect/end-session/{id}'
defaults:
_controller: 'Drupal\os2forms_nemlogin_openid_connect\Controller\OpenIDConnectController::endSession'
requirements:
# Anonymous users must be able to access this route.
_access: 'TRUE'
options:
no_cache: 'TRUE'

os2forms_nemlogin_openid_connect.admin.settings:
path: '/admin/os2forms_nemlogin_openid_connect/settings'
defaults:
_form: '\Drupal\os2forms_nemlogin_openid_connect\Form\SettingsForm'
_title: 'OS2Forms NemLogin OpenID Connect settings'
requirements:
_permission: 'administer site configuration'
10 changes: 10 additions & 0 deletions os2forms_nemlogin_openid_connect.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,13 @@ services:
- '@os2web_nemlogin.auth_provider'
- '@messenger'
- '@current_route_match'

Drupal\os2forms_nemlogin_openid_connect\Helper\Settings:
arguments:
- "@keyvalue"

Drupal\os2forms_nemlogin_openid_connect\EventSubscriber\OrganisationEventSubscriber:
arguments:
- '@os2web_nemlogin.auth_provider'
tags:
- { name: 'event_subscriber' }
97 changes: 45 additions & 52 deletions src/Controller/OpenIDConnectController.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,54 +69,17 @@ class OpenIDConnectController implements ContainerInjectionInterface {
private $plugin;

/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
private $requestStack;

/**
* The session.
*
* @var \Symfony\Component\HttpFoundation\Session\SessionInterface
*/
private $session;

/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
private $languageManager;

/**
* The cache item pool.
*
* @var \Psr\Cache\CacheItemPoolInterface
*/
private $cacheItemPool;

/**
* The renderer.
*
* @var \Drupal\Core\Render\RendererInterface
*/
private $renderer;

/**
* Constructor.
* The constructor.
*/
public function __construct(AuthProviderService $authProviderService, RequestStack $requestStack, SessionInterface $session, CacheItemPoolInterface $cacheItemPool, LanguageManagerInterface $languageManager, LoggerInterface $logger, RendererInterface $renderer) {
$plugin = $authProviderService->getPluginInstance('OpenIDConnect');
assert($plugin instanceof OpenIDConnect);
$this->plugin = $plugin;

$this->requestStack = $requestStack;
$this->session = $session;
$this->cacheItemPool = $cacheItemPool;
$this->languageManager = $languageManager;
public function __construct(
private readonly AuthProviderService $authProviderService,
private readonly RequestStack $requestStack,
private readonly SessionInterface $session,
private readonly CacheItemPoolInterface $cacheItemPool,
private readonly LanguageManagerInterface $languageManager,
LoggerInterface $logger,
private readonly RendererInterface $renderer) {
$this->setLogger($logger);
$this->renderer = $renderer;
}

/**
Expand Down Expand Up @@ -144,7 +107,8 @@ public static function create(ContainerInterface $container): self {
*
* @phpstan-return array<string, mixed>|Response
*/
public function main() {
public function main(string $id) {
$this->initialize($id);
try {
$request = $this->requestStack->getCurrentRequest();

Expand Down Expand Up @@ -194,7 +158,9 @@ private function getOpenIdConfigurationProvider(): OpenIdConfigurationProvider {
private function getRedirectUri(): string {
return Url::fromRoute(
'os2forms_nemlogin_openid_connect.openid_connect_authenticate',
[],
[
'id' => $this->getPluginId(),
],
[
'absolute' => TRUE,
'language' => $this->languageManager->getLanguage(LanguageInterface::LANGCODE_NOT_APPLICABLE),
Expand Down Expand Up @@ -274,7 +240,10 @@ private function start(): Response {
'scope' => 'openid email profile',
];
$authorizationUrl = $this->isLocalTestMode()
? Url::fromRoute('os2forms_nemlogin_openid_connect.openid_connect_authenticate', $options + ['test' => TRUE])->toString(TRUE)->getGeneratedUrl()
? Url::fromRoute('os2forms_nemlogin_openid_connect.openid_connect_authenticate', $options + [
'id' => $this->getPluginId(),
'test' => TRUE,
])->toString(TRUE)->getGeneratedUrl()
: $provider->getAuthorizationUrl($options);

$this->setSessionValue(self::SESSION_STATE, $provider->getState());
Expand All @@ -288,7 +257,8 @@ private function start(): Response {
* @return \Symfony\Component\HttpFoundation\Response
* The response.
*/
public function endSession(): Response {
public function endSession(string $id): Response {
$this->initialize($id);
$provider = $this->getOpenIdConfigurationProvider();

$postLogoutRedirectUri = $this->getPostLogoutRedirectUri();
Expand Down Expand Up @@ -346,8 +316,14 @@ private function getLocalTestUsers(): array {
*/
private function getSettings(): array {
$settings = Settings::get('os2forms_nemlogin_openid_connect', NULL);
if (!is_array($settings)) {
$settings = [];
}

return $settings ?: [];
// Merge in plugin specific settings if any.
return isset($settings[$this->getPluginId()]) && is_array($settings[$this->getPluginId()])
? array_merge($settings, $settings[$this->getPluginId()])
: $settings;
}

/**
Expand All @@ -371,7 +347,8 @@ private function process(): Response {
$renderable = [
'#theme' => 'os2forms_nemlogin_openid_connect_local_test_users',
'#users' => $users,
'#query' => $request->query->all(),
'#plugin' => $this->plugin,
'#query' => ['id' => $this->getPluginId()] + $request->query->all(),
];

return new Response($this->renderer->renderPlain($renderable));
Expand Down Expand Up @@ -465,4 +442,20 @@ private function displayError(string $message, string $description = NULL): arra
];
}

/**
* Initialize.
*/
private function initialize(string $id): void {
$plugin = $this->authProviderService->getPluginInstance($id);
assert($plugin instanceof OpenIDConnect);
$this->plugin = $plugin;
}

/**
* Get plugin id.
*/
private function getPluginId(): string {
return $this->plugin->getPluginId();
}

}
Loading

0 comments on commit 1975317

Please sign in to comment.