Skip to content

Commit 08dec18

Browse files
committed
5124: Cleaned up
1 parent 4f23686 commit 08dec18

File tree

10 files changed

+123
-69
lines changed

10 files changed

+123
-69
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ Versioning](https://semver.org/spec/v2.0.0.html).
88

99
## [Unreleased]
1010

11+
- [PR-375](https://github.com/itk-dev/os2loop/pull/375)
12+
Added Cura login module
13+
1114
## [1.2.5]
1215

1316
- [374](https://github.com/itk-dev/os2loop/pull/374)

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ for further details.
140140
## Coding standards
141141

142142
```sh
143-
docker compose exec phpfpm composer coding-standards-apply
144-
docker compose exec phpfpm composer coding-standards-check
143+
docker compose exec phpfpm vendor/bin/phpcs
144+
docker compose exec phpfpm vendor/bin/phpcbf
145145
```
146146

147147
```sh

web/profiles/custom/os2loop/modules/os2loop_cura_login/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,30 @@
33
Use `https://os2loop.example.com/os2loop-cura-login/start` as `linkURL` (or is it `formPostUrl`?) in the Cura link
44
configuration.
55

6+
## How does it work?
7+
8+
Cura will make a `POST` `multipart/form-data` request to `/os2loop-cura-login/start` with a `payload` parameter containing
9+
a JWT like
10+
11+
``` json
12+
{
13+
"header" : {
14+
"alg" : "HS256"
15+
},
16+
"payload" : {
17+
"brugerId" : "az…",
18+
"organisationsNavn" : "Digitalisering",
19+
"brugerensNavn" : "",
20+
"sorid" : "aarhus",
21+
"exp" : 1756978913
22+
},
23+
"signature" : ""
24+
}
25+
```
26+
27+
However, it can also make a `GET` request to `/os2loop-cura-login/start/{payload}` or
28+
`/os2loop-cura-login/start/payload={payload}`.
29+
630
## Example
731

832
``` shell
@@ -23,3 +47,11 @@ drush --uri='http://nginx:8080' os2loop-cura-login:get-login-url [email protected]
2347
# settings.local.php
2448
$config['os2loop_cura_login.settings']['log_level'] = \Drupal\Core\Logger\RfcLogLevel::DEBUG;
2549
```
50+
51+
Run
52+
53+
``` shell
54+
drush config:get os2loop_cura_login.settings --include-overridden
55+
```
56+
57+
to show the current module config.

web/profiles/custom/os2loop/modules/os2loop_cura_login/os2loop_cura_login.info.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
name: 'OS2Loop Cura login'
1+
name: "OS2Loop Cura login"
22
type: module
3-
description: 'OS2Loop Cura login'
4-
package: 'OS2Loop'
3+
description: "OS2Loop Cura login"
4+
package: "OS2Loop"
55
core_version_requirement: ^10 || ^11
66
dependencies:
77
- drupal:user
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
os2loop_cura_login.settings:
2-
title: 'OS2Loop Cura login settings'
2+
title: "OS2Loop Cura login settings"
33
route_name: os2loop_cura_login.settings
4-
description: 'Configure OS2Loop Cura login settings'
4+
description: "Configure OS2Loop Cura login settings"
55
parent: os2loop.group.admin
66
weight: 100
Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,34 @@
11
os2loop_cura_login.start:
2-
path: '/os2loop-cura-login/start'
2+
path: "/os2loop-cura-login/start"
33
defaults:
4-
_title: 'Start Cura login'
4+
_title: "Start Cura login with POST or GET"
55
_controller: '\Drupal\os2loop_cura_login\Controller\Os2loopCuraLoginController::start'
66
methods: [GET, POST]
77
requirements:
8-
_role: 'anonymous'
8+
_role: "anonymous"
9+
10+
os2loop_cura_login.start_get_jwt:
11+
path: "/os2loop-cura-login/start/{jwt}"
12+
defaults:
13+
_title: "Start Cura login with JWT in request path"
14+
_controller: '\Drupal\os2loop_cura_login\Controller\Os2loopCuraLoginController::start'
15+
methods: [GET]
16+
requirements:
17+
_role: "anonymous"
918

1019
os2loop_cura_login.authenticate:
11-
path: '/os2loop-login-hack/authenticate'
20+
path: "/os2loop-login-hack/authenticate"
1221
defaults:
13-
_title: 'Authenticate with Cura login'
22+
_title: "Authenticate with Cura login"
1423
_controller: '\Drupal\os2loop_cura_login\Controller\Os2loopCuraLoginController::authenticate'
1524
methods: [GET]
1625
requirements:
17-
_role: 'anonymous'
26+
_role: "anonymous"
1827

1928
os2loop_cura_login.settings:
20-
path: '/admin/config/os2loop/os2loop_cura_login/settings'
29+
path: "/admin/config/os2loop/os2loop_cura_login/settings"
2130
defaults:
2231
_form: '\Drupal\os2loop_cura_login\Form\SettingsForm'
23-
_title: 'OS2Loop Cura login settings'
32+
_title: "OS2Loop Cura login settings"
2433
requirements:
25-
_permission: 'administer site settings'
34+
_permission: "administer site settings"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
services:
22
logger.channel.os2loop_cura_login:
33
parent: logger.channel_base
4-
arguments: ['os2loop_cura_login']
4+
arguments: ["os2loop_cura_login"]

web/profiles/custom/os2loop/modules/os2loop_cura_login/src/Controller/Os2loopCuraLoginController.php

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,23 +57,29 @@ public function __construct(
5757
/**
5858
* Start user authentication.
5959
*/
60-
public function start(Request $request): Response {
60+
public function start(Request $request, ?string $jwt): Response {
6161
try {
62-
$content = NULL;
62+
$content = NULL;
6363
try {
6464
$content = (string) $request->getContent();
65-
} catch (\Exception) {}
65+
}
66+
catch (\Exception) {
67+
}
6668
$this->debug('@debug', [
6769
'@debug' => json_encode([
6870
'method' => $request->getMethod(),
71+
'headers' => $request->headers->all(),
6972
'query' => $request->query->all(),
7073
'content' => $content,
7174
]),
7275
]);
7376

74-
$jwt = Request::METHOD_POST === $request->getMethod()
75-
? $request->getContent()
76-
: $request->query->getString($this->config->get('token_param_name') ?? 'token');
77+
if (empty($jwt)) {
78+
$name = $this->config->get('payload_name') ?? 'payload';
79+
$jwt = Request::METHOD_POST === $request->getMethod()
80+
? $request->request->getString($name)
81+
: $request->query->getString($name);
82+
}
7783

7884
$this->debug('@debug', [
7985
'@debug' => json_encode([
@@ -85,15 +91,25 @@ public function start(Request $request): Response {
8591
throw new BadRequestHttpException('Missing or empty JWT');
8692
}
8793

88-
$payload = (array) JWT::decode($jwt, new Key($this->config->get('signing_secret'), $this->config->get('signing_algorithm')));
94+
$secret = $this->config->get('signing_secret');
95+
// @todo Get rid of the double base64 encoding.
96+
$secret = base64_decode($secret);
97+
98+
$originalLeeway = JWT::$leeway;
99+
$leeway = (int) $this->config->get('jwt_leeway');
100+
if ($leeway > 0) {
101+
JWT::$leeway = $leeway;
102+
}
103+
$payload = (array) JWT::decode($jwt, new Key($secret, $this->config->get('signing_algorithm')));
104+
JWT::$leeway = $originalLeeway;
89105

90106
$this->debug('@debug', [
91107
'@debug' => json_encode([
92108
'payload' => $payload,
93109
]),
94110
]);
95111

96-
$username = $payload['username'] ?? NULL;
112+
$username = $payload['username'] ?? $payload['brugerId'] ?? NULL;
97113
if (empty($username)) {
98114
throw new BadRequestHttpException('Missing username');
99115
}
@@ -221,9 +237,11 @@ private function getUserinfo(User $user): array {
221237
];
222238
}
223239

224-
public function log($level, \Stringable|string $message, array $context = []): void
225-
{
226-
// Lifted from LoggerChannel
240+
/**
241+
* {@inheritdoc}
242+
*/
243+
public function log($level, \Stringable|string $message, array $context = []): void {
244+
// Lifted from LoggerChannel.
227245
$levels = [
228246
LogLevel::EMERGENCY => RfcLogLevel::EMERGENCY,
229247
LogLevel::ALERT => RfcLogLevel::ALERT,
@@ -235,7 +253,7 @@ public function log($level, \Stringable|string $message, array $context = []): v
235253
LogLevel::DEBUG => RfcLogLevel::DEBUG,
236254
];
237255
$rfcLogLevel = $levels[$level] ?? RfcLogLevel::ERROR;
238-
if ((int)$this->config->get('log_level') >= $rfcLogLevel) {
256+
if ((int) $this->config->get('log_level') >= $rfcLogLevel) {
239257
$this->logger->log($level, $message, $context);
240258
}
241259
}

web/profiles/custom/os2loop/modules/os2loop_cura_login/src/Drush/Commands/Os2loopCuraLoginCommands.php

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,19 @@
22

33
namespace Drupal\os2loop_cura_login\Drush\Commands;
44

5-
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
65
use Drupal\Component\Datetime\TimeInterface;
76
use Drupal\Core\DependencyInjection\AutowireTrait;
87
use Drupal\Core\Url;
9-
use Drupal\Core\Utility\Token;
108
use Drush\Attributes as CLI;
119
use Drush\Commands\DrushCommands;
1210
use Firebase\JWT\JWT;
13-
use Http\Client\HttpClient;
1411
use Psr\Http\Client\ClientInterface;
15-
use Symfony\Component\DependencyInjection\ContainerInterface;
1612
use Symfony\Component\HttpFoundation\Request;
1713

1814
/**
1915
* A Drush commandfile.
2016
*/
21-
final class Os2loopCuraLoginCommands extends DrushCommands
22-
{
17+
final class Os2loopCuraLoginCommands extends DrushCommands {
2318
use AutowireTrait;
2419

2520
/**
@@ -42,10 +37,10 @@ public function __construct(
4237
public function commandName(
4338
$username,
4439
$options = [
45-
'get' => null,
46-
'secret' => null,
40+
'get' => NULL,
41+
'secret' => NULL,
4742
'algorithm' => 'HS256',
48-
]
43+
],
4944
) {
5045
// https://github.com/firebase/php-jwt?tab=readme-ov-file#example
5146
$payload = [
@@ -62,11 +57,12 @@ public function commandName(
6257
if ($name = $options['get']) {
6358
$method = Request::METHOD_GET;
6459
$routeParameters[$name] = $jwt;
65-
} else {
60+
}
61+
else {
6662
$method = Request::METHOD_POST;
6763
$requestOptions['body'] = $jwt;
6864
}
69-
$url = Url::fromRoute('os2loop_cura_login.start', $routeParameters)->setAbsolute()->toString(true)->getGeneratedUrl();
65+
$url = Url::fromRoute('os2loop_cura_login.start', $routeParameters)->setAbsolute()->toString(TRUE)->getGeneratedUrl();
7066
$this->io()->writeln($method === Request::METHOD_POST
7167
? sprintf('POST\'ing to %s', $url)
7268
: sprintf('GET\'ing %s', $url),
@@ -78,7 +74,7 @@ public function commandName(
7874
$url,
7975
$request->getStatusCode(),
8076
$request->getBody()->getContents(),
81-
], true);
77+
], TRUE);
8278
die(__FILE__ . ':' . __LINE__ . ':' . __METHOD__);
8379
}
8480

web/profiles/custom/os2loop/modules/os2loop_cura_login/src/Form/SettingsForm.php

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,17 @@ public function buildForm(array $form, FormStateInterface $form_state): array {
6666
'#description' => $this->t('Check this to generate a new random secret'),
6767
];
6868

69-
$form['token_param_name'] = [
69+
$form['payload_name'] = [
7070
'#type' => 'textfield',
71-
'#title' => $this->t('Token param name'),
72-
'#default_value' => $config->get('token_param_name'),
73-
'#description' => $this->t('Query string param name used for JWT token on GET request'),
71+
'#title' => $this->t('Payload name'),
72+
'#default_value' => $config->get('payload_name') ?? 'payload',
73+
'#description' => $this->t('Name of parameter used for payload'),
74+
];
75+
76+
$form['jwt_leeway'] = [
77+
'#type' => 'textfield',
78+
'#title' => $this->t('JWT leeway'),
79+
'#default_value' => $config->get('jwt_leeway') ?? 0,
7480
];
7581

7682
$form['log_level'] = [
@@ -80,42 +86,31 @@ public function buildForm(array $form, FormStateInterface $form_state): array {
8086
'#default_value' => $config->get('log_level') ?? RfcLogLevel::ERROR,
8187
];
8288

83-
$authenticationStartUrl = Url::fromRoute('os2loop_cura_login.start')->setAbsolute()->toString(true)->getGeneratedUrl();
89+
$authenticationStartUrl = Url::fromRoute('os2loop_cura_login.start')->setAbsolute()->toString(TRUE)->getGeneratedUrl();
8490
$form['info'] = [
8591
'#theme' => 'item_list',
8692
'#items' => [
87-
'#markup' => $this->t('Use <a href=":url">:url</a> as <code>linkURL</code>.', [':url' => $authenticationStartUrl]),
93+
'#markup' => $this->t('Use <a href=":url">:url</a> as <code>linkURL</code> for <code>postToGetLinkURL ≡ true</code>.', [':url' => $authenticationStartUrl]),
8894
],
8995
];
9096

91-
if ($name = $config->get('token_param_name')) {
92-
$authenticationStartUrl = Url::fromRoute('os2loop_cura_login.start', [$name => ''])->setAbsolute()->toString(true)->getGeneratedUrl();
93-
$authenticationStartUrl = str_replace(urlencode(''), '', $authenticationStartUrl);
97+
$authenticationStartUrl = Url::fromRoute('os2loop_cura_login.start', [])->setAbsolute()->toString(TRUE)->getGeneratedUrl();
98+
$authenticationStartUrl = rtrim($authenticationStartUrl, '/') . '/';
99+
$form['info']['#items'][] = [
100+
'#markup' => $this->t('Use <a href=":url">:url</a> as <code>linkURL</code> for <core><code>postToGetLinkURL ≡ false</code>.', [':url' => $authenticationStartUrl]),
101+
];
102+
103+
if ($name = $config->get('payload_name')) {
104+
$authenticationStartUrl = Url::fromRoute('os2loop_cura_login.start', [$name => ''])->setAbsolute()->toString(TRUE)->getGeneratedUrl();
105+
$authenticationStartUrl = str_replace(urlencode(''), '', $authenticationStartUrl);
94106
$form['info']['#items'][] = [
95-
'#markup' => $this->t('Use <a href=":url">:url</a> as <code>linkURL</code> for <core>GET</core>.', [':url' => $authenticationStartUrl]),
107+
'#markup' => $this->t('Use <a href=":url">:url</a> as <code>linkURL</code> for <core><code>postToGetLinkURL ≡ false</code>.', [':url' => $authenticationStartUrl]),
96108
];
97109
}
98110

99111
return parent::buildForm($form, $form_state);
100112
}
101113

102-
/**
103-
* {@inheritdoc}
104-
*/
105-
public function validateForm(array &$form, FormStateInterface $form_state): void {
106-
// @todo Validate the form here.
107-
// Example:
108-
// @code
109-
// if ($form_state->getValue('example') === 'wrong') {
110-
// $form_state->setErrorByName(
111-
// 'message',
112-
// $this->t('The value is not correct.'),
113-
// );
114-
// }
115-
// @endcode
116-
parent::validateForm($form, $form_state);
117-
}
118-
119114
/**
120115
* {@inheritdoc}
121116
*/
@@ -127,7 +122,8 @@ public function submitForm(array &$form, FormStateInterface $form_state): void {
127122
$this->config('os2loop_cura_login.settings')
128123
->set('signing_algorithm', $form_state->getValue('signing_algorithm'))
129124
->set('signing_secret', $secret)
130-
->set('token_param_name', $form_state->getValue('token_param_name'))
125+
->set('payload_name', $form_state->getValue('payload_name'))
126+
->set('jwt_leeway', $form_state->getValue('jwt_leeway'))
131127
->set('log_level', $form_state->getValue('log_level'))
132128
->save();
133129
parent::submitForm($form, $form_state);

0 commit comments

Comments
 (0)