Skip to content

Commit b27986e

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

File tree

2 files changed

+134
-70
lines changed

2 files changed

+134
-70
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 & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
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;
1312
use Drupal\user\Entity\User;
13+
use Drupal\user\UserInterface;
1414
use Drupal\user\UserStorageInterface;
1515
use Firebase\JWT\JWT;
1616
use Firebase\JWT\Key;
@@ -19,7 +19,6 @@
1919
use Psr\Log\LogLevel;
2020
use Symfony\Component\DependencyInjection\Attribute\Autowire;
2121
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
22-
use Symfony\Component\HttpFoundation\JsonResponse;
2322
use Symfony\Component\HttpFoundation\Request;
2423
use Symfony\Component\HttpFoundation\Response;
2524
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
@@ -86,17 +85,7 @@ public function start(Request $request, ?string $jwt): Response {
8685
throw new BadRequestHttpException('Missing or empty JWT');
8786
}
8887

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;
88+
$payload = $this->decodeJwt($jwt);
10089

10190
$this->debug('@debug', [
10291
'@debug' => json_encode([
@@ -109,51 +98,36 @@ public function start(Request $request, ?string $jwt): Response {
10998
throw new BadRequestHttpException('Missing username');
11099
}
111100

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

114104
$this->debug('@debug', [
115105
'@debug' => json_encode([
116-
'user' => $user,
106+
'userinfo' => $userinfo,
117107
]),
118108
]);
119109

120-
if (empty($user)) {
110+
if (empty($userinfo)) {
121111
// Don't disclose whether or not the user exists.
122112
throw new BadRequestHttpException();
123113
}
124114

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

128117
$this->debug('@debug', [
129118
'@debug' => json_encode([
130-
'userinfo' => $userinfo,
119+
'user' => $user,
131120
]),
132121
]);
133122

134-
if (empty($userinfo)) {
123+
if (empty($user)) {
124+
// Don't disclose whether or not the user exists.
135125
throw new BadRequestHttpException();
136126
}
137127

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-
]);
128+
return Request::METHOD_POST === $request->getMethod()
129+
? $this->createAuthenticateResponse($user)
130+
: $this->authenticateUser($user);
157131
}
158132
catch (\Exception $exception) {
159133
$this->error('start: @message', ['@message' => $exception->getMessage(), $exception]);
@@ -162,17 +136,37 @@ public function start(Request $request, ?string $jwt): Response {
162136
}
163137

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

175-
$payload = (array) JWT::decode($jwt, new Key(self::JWT_KEY, 'HS256'));
169+
$payload = $this->decodeJwt($jwt);
176170
$username = $payload['username'] ?? NULL;
177171
if (empty($username)) {
178172
throw new BadRequestHttpException();
@@ -184,54 +178,124 @@ public function authenticate(Request $request): Response {
184178
throw new BadRequestHttpException();
185179
}
186180

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);
181+
return $this->authenticateUser($user);
195182
}
196183
catch (\Exception $exception) {
197-
$this->error('start: @message', ['@message' => $exception->getMessage(), $exception]);
184+
$this->error('authenticate: @message', ['@message' => $exception->getMessage(), $exception]);
198185
throw new BadRequestException($exception->getMessage());
199186
}
200187
}
201188

202189
/**
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.
190+
* Authenticate user.
210191
*/
211-
private function loadUser(string $username): ?User {
212-
$users = $this->userStorage->loadByProperties(['name' => $username]);
192+
private function authenticateUser($user): Response {
193+
user_login_finalize($user);
213194

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

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

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

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

0 commit comments

Comments
 (0)