Skip to content

Commit b57261b

Browse files
committed
5124: Updated controller actions
1 parent cdcf3ca commit b57261b

File tree

2 files changed

+134
-71
lines changed

2 files changed

+134
-71
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ os2loop_cura_login.start_get_jwt:
1717
_role: "anonymous"
1818

1919
os2loop_cura_login.authenticate:
20-
path: "/os2loop-login-hack/authenticate"
20+
path: "/os2loop-cura-login/authenticate"
2121
defaults:
2222
_title: "Authenticate with Cura login"
2323
_controller: '\Drupal\os2loop_cura_login\Controller\Os2loopCuraLoginController::authenticate'

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

Lines changed: 133 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77
use Drupal\Component\Datetime\TimeInterface;
88
use Drupal\Core\Controller\ControllerBase;
99
use Drupal\Core\Logger\RfcLogLevel;
10-
use Drupal\Core\Routing\TrustedRedirectResponse;
1110
use Drupal\Core\Url;
1211
use Drupal\os2loop_cura_login\Settings;
13-
use Drupal\user\Entity\User;
12+
use Drupal\user\UserInterface;
1413
use Drupal\user\UserStorageInterface;
1514
use Firebase\JWT\JWT;
1615
use Firebase\JWT\Key;
@@ -19,7 +18,6 @@
1918
use Psr\Log\LogLevel;
2019
use Symfony\Component\DependencyInjection\Attribute\Autowire;
2120
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
22-
use Symfony\Component\HttpFoundation\JsonResponse;
2321
use Symfony\Component\HttpFoundation\Request;
2422
use Symfony\Component\HttpFoundation\Response;
2523
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
@@ -86,17 +84,7 @@ public function start(Request $request, ?string $jwt): Response {
8684
throw new BadRequestHttpException('Missing or empty JWT');
8785
}
8886

89-
$secret = $this->settings->getSigningSecret();
90-
// @todo Get rid of the double base64 encoding.
91-
$secret = base64_decode($secret);
92-
93-
$originalLeeway = JWT::$leeway;
94-
$leeway = $this->settings->getJwtLeeway();
95-
if ($leeway > 0) {
96-
JWT::$leeway = $leeway;
97-
}
98-
$payload = (array) JWT::decode($jwt, new Key($secret, $this->settings->getSigningAlgorithm()));
99-
JWT::$leeway = $originalLeeway;
87+
$payload = $this->decodeJwt($jwt);
10088

10189
$this->debug('@debug', [
10290
'@debug' => json_encode([
@@ -109,51 +97,36 @@ public function start(Request $request, ?string $jwt): Response {
10997
throw new BadRequestHttpException('Missing username');
11098
}
11199

112-
$user = $this->loadUser($username);
100+
// Check that we can get userinfo.
101+
$userinfo = $this->fetchUserinfo($username);
113102

114103
$this->debug('@debug', [
115104
'@debug' => json_encode([
116-
'user' => $user,
105+
'userinfo' => $userinfo,
117106
]),
118107
]);
119108

120-
if (empty($user)) {
109+
if (empty($userinfo)) {
121110
// Don't disclose whether or not the user exists.
122111
throw new BadRequestHttpException();
123112
}
124113

125-
// Check that we can get userinfo.
126-
$userinfo = $this->getUserinfo($user);
114+
$user = $this->ensureUser($username, $userinfo);
127115

128116
$this->debug('@debug', [
129117
'@debug' => json_encode([
130-
'userinfo' => $userinfo,
118+
'user' => $user,
131119
]),
132120
]);
133121

134-
if (empty($userinfo)) {
122+
if (empty($user)) {
123+
// Don't disclose whether or not the user exists.
135124
throw new BadRequestHttpException();
136125
}
137126

138-
// https://github.com/firebase/php-jwt?tab=readme-ov-file#example
139-
$payload = [
140-
// Issued at.
141-
'iat' => $this->time->getRequestTime(),
142-
// Expire af 60 seconds.
143-
'exp' => $this->time->getRequestTime() + 60,
144-
'username' => $username,
145-
];
146-
$jwt = JWT::encode($payload, self::JWT_KEY, 'HS256');
147-
148-
$url = Url::fromRoute('os2loop_cura_login.authenticate', [
149-
'username' => $username,
150-
'jwt' => $jwt,
151-
])->setAbsolute()->toString(TRUE)->getGeneratedUrl();
152-
153-
return new JsonResponse([
154-
'authenticate_url' => $url,
155-
'jwt' => $jwt,
156-
]);
127+
return Request::METHOD_POST === $request->getMethod()
128+
? $this->createAuthenticateResponse($user)
129+
: $this->authenticateUser($user);
157130
}
158131
catch (\Exception $exception) {
159132
$this->error('start: @message', ['@message' => $exception->getMessage(), $exception]);
@@ -162,17 +135,37 @@ public function start(Request $request, ?string $jwt): Response {
162135
}
163136

164137
/**
165-
* Authenticate user.
138+
* Create authenticate response.
139+
*/
140+
private function createAuthenticateResponse(UserInterface $user): Response {
141+
// https://github.com/firebase/php-jwt?tab=readme-ov-file#example
142+
$payload = [
143+
// Issued at.
144+
'iat' => $this->time->getRequestTime(),
145+
// Expire af 60 seconds.
146+
'exp' => $this->time->getRequestTime() + 60,
147+
'username' => $user->getAccountName(),
148+
];
149+
$jwt = $this->encodeJwt($payload);
150+
151+
$url = Url::fromRoute('os2loop_cura_login.authenticate', [
152+
'jwt' => $jwt,
153+
])->setAbsolute()->toString(TRUE)->getGeneratedUrl();
154+
155+
return new Response($url);
156+
}
157+
158+
/**
159+
* Authenticate action.
166160
*/
167161
public function authenticate(Request $request): Response {
168162
try {
169-
$username = $request->get('username');
170163
$jwt = $request->get('jwt');
171-
if (empty($username) || empty($jwt)) {
164+
if (empty($jwt)) {
172165
throw new BadRequestHttpException();
173166
}
174167

175-
$payload = (array) JWT::decode($jwt, new Key(self::JWT_KEY, 'HS256'));
168+
$payload = $this->decodeJwt($jwt);
176169
$username = $payload['username'] ?? NULL;
177170
if (empty($username)) {
178171
throw new BadRequestHttpException();
@@ -184,54 +177,124 @@ public function authenticate(Request $request): Response {
184177
throw new BadRequestHttpException();
185178
}
186179

187-
$this->updateUser($user);
188-
189-
user_login_finalize($user);
190-
191-
$url = Url::fromRoute('<front>')->setAbsolute()->toString(TRUE)->getGeneratedUrl();
192-
$this->messenger()->addStatus($this->t('Welcome @user.', ['@user' => $user->getDisplayName()]));
193-
194-
return new TrustedRedirectResponse($url);
180+
return $this->authenticateUser($user);
195181
}
196182
catch (\Exception $exception) {
197-
$this->error('start: @message', ['@message' => $exception->getMessage(), $exception]);
183+
$this->error('authenticate: @message', ['@message' => $exception->getMessage(), $exception]);
198184
throw new BadRequestException($exception->getMessage());
199185
}
200186
}
201187

202188
/**
203-
* Load user by username.
204-
*
205-
* @param string $username
206-
* The username.
207-
*
208-
* @return \Drupal\user\Entity\User|null
209-
* The user if any.
189+
* Authenticate user.
210190
*/
211-
private function loadUser(string $username): ?User {
212-
$users = $this->userStorage->loadByProperties(['name' => $username]);
191+
private function authenticateUser($user): Response {
192+
user_login_finalize($user);
213193

214-
return reset($users) ?: NULL;
194+
$this->messenger()->addStatus($this->t('Welcome Cura user @user.', ['@user' => $user->getDisplayName()]));
195+
196+
return $this->redirect('<front>');
215197
}
216198

217199
/**
218-
* Update user with info from IdP.
200+
* Encode JWT.
219201
*/
220-
private function updateUser(User $user): User {
221-
// $userinfo = $this->getUserinfo($user);
222-
// @todo Update user.
223-
return $user;
202+
private function encodeJwt(array $payload): string {
203+
$secret = $this->settings->getSigningSecret();
204+
// @todo Get rid of the double base64 encoding.
205+
$secret = base64_decode($secret);
206+
207+
return JWT::encode($payload, $secret, $this->settings->getSigningAlgorithm());
208+
}
209+
210+
/**
211+
* Decode JWT.
212+
*/
213+
private function decodeJwt(string $jwt): array {
214+
$secret = $this->settings->getSigningSecret();
215+
// @todo Get rid of the double base64 encoding.
216+
$secret = base64_decode($secret);
217+
218+
$originalLeeway = JWT::$leeway;
219+
$leeway = $this->settings->getJwtLeeway();
220+
if ($leeway > 0) {
221+
JWT::$leeway = $leeway;
222+
}
223+
$payload = (array) JWT::decode($jwt, new Key($secret, $this->settings->getSigningAlgorithm()));
224+
JWT::$leeway = $originalLeeway;
225+
226+
return $payload;
224227
}
225228

226229
/**
227230
* Get user info from userinfo endpoint.
228231
*/
229-
private function getUserinfo(User $user): array {
232+
private function fetchUserinfo(string $username): array {
230233
return [
231-
'name' => $user->getDisplayName(),
234+
// Drupal user fields.
235+
'name' => $username,
236+
'mail' => $username . '@cura.example.com',
237+
238+
// OS2Lloop fields
239+
// 'os2loop_user_address' => '',
240+
// 'os2loop_user_areas_of_expertise' => '',
241+
// 'os2loop_user_biography' => '',
242+
// 'os2loop_user_city' => '',
243+
// 'os2loop_user_external_list' => '',.
244+
'os2loop_user_family_name' => 'Cura',
245+
'os2loop_user_given_name' => 'User',
246+
// 'os2loop_user_image' => '',
247+
// 'os2loop_user_internal_list' => '',
248+
// 'os2loop_user_job_title' => '',
249+
// 'os2loop_user_phone_number' => '',
250+
// 'os2loop_user_place' => '',
251+
// 'os2loop_user_postal_code' => '',
252+
// 'os2loop_user_professions' => '',
232253
];
233254
}
234255

256+
/**
257+
* Ensure user exists.
258+
*
259+
* @param string $username
260+
* The username.
261+
* @param array $userinfo
262+
* The user info to set on the user.
263+
*
264+
* @return \Drupal\user\Entity\UserInterface
265+
* The newly created or updated user.
266+
*/
267+
private function ensureUser(string $username, array $userinfo): UserInterface {
268+
$user = $this->loadUser($username);
269+
270+
if (NULL === $user) {
271+
$user = $this->userStorage->create();
272+
}
273+
274+
foreach ($userinfo as $field => $value) {
275+
$currentValue = $user->get($field);
276+
if ($currentValue !== $value) {
277+
$user->set($field, $value);
278+
}
279+
}
280+
281+
// Make sure that the user is active.
282+
$user
283+
->activate()
284+
->save();
285+
286+
return $user;
287+
}
288+
289+
/**
290+
* Load user by username.
291+
*/
292+
private function loadUser(string $username) : ?UserInterface {
293+
$users = $this->userStorage->loadByProperties(['name' => $username]);
294+
295+
return reset($users) ?: NULL;
296+
}
297+
235298
/**
236299
* {@inheritdoc}
237300
*/

0 commit comments

Comments
 (0)