strapi-plugin-oidc 1.3.2 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +92 -44
- package/dist/admin/{index-BqyGGX8X.js → index-BnFRueNv.js} +163 -33
- package/dist/admin/{index-CFmg9Kxl.mjs → index-CY4s-vtv.mjs} +167 -37
- package/dist/admin/{index-Cse9ex24.js → index-RMgj1w0B.js} +15 -2
- package/dist/admin/{index-D1ypRUlq.mjs → index-ZRaWWFUL.mjs} +15 -2
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +257 -219
- package/dist/server/index.mjs +257 -219
- package/package.json +11 -4
package/dist/server/index.js
CHANGED
|
@@ -164,7 +164,6 @@ const config = {
|
|
|
164
164
|
OIDC_AUTHORIZATION_ENDPOINT: "",
|
|
165
165
|
OIDC_TOKEN_ENDPOINT: "",
|
|
166
166
|
OIDC_USER_INFO_ENDPOINT: "",
|
|
167
|
-
OIDC_USER_INFO_ENDPOINT_WITH_AUTH_HEADER: false,
|
|
168
167
|
OIDC_GRANT_TYPE: "authorization_code",
|
|
169
168
|
OIDC_FAMILY_NAME_FIELD: "family_name",
|
|
170
169
|
OIDC_GIVEN_NAME_FIELD: "given_name",
|
|
@@ -223,45 +222,43 @@ function clearAuthCookies(strapi2, ctx) {
|
|
|
223
222
|
ctx.cookies.set("strapi_admin_refresh", "", options2);
|
|
224
223
|
ctx.cookies.set("oidc_authenticated", "", { ...options2, path: "/" });
|
|
225
224
|
}
|
|
225
|
+
const REQUIRED_CONFIG_KEYS = [
|
|
226
|
+
"OIDC_CLIENT_ID",
|
|
227
|
+
"OIDC_CLIENT_SECRET",
|
|
228
|
+
"OIDC_REDIRECT_URI",
|
|
229
|
+
"OIDC_SCOPES",
|
|
230
|
+
"OIDC_TOKEN_ENDPOINT",
|
|
231
|
+
"OIDC_USER_INFO_ENDPOINT",
|
|
232
|
+
"OIDC_GRANT_TYPE",
|
|
233
|
+
"OIDC_FAMILY_NAME_FIELD",
|
|
234
|
+
"OIDC_GIVEN_NAME_FIELD",
|
|
235
|
+
"OIDC_AUTHORIZATION_ENDPOINT"
|
|
236
|
+
];
|
|
226
237
|
function configValidation() {
|
|
227
238
|
const config2 = strapi.config.get("plugin::strapi-plugin-oidc");
|
|
228
|
-
|
|
229
|
-
"OIDC_CLIENT_ID",
|
|
230
|
-
"OIDC_CLIENT_SECRET",
|
|
231
|
-
"OIDC_REDIRECT_URI",
|
|
232
|
-
"OIDC_SCOPES",
|
|
233
|
-
"OIDC_TOKEN_ENDPOINT",
|
|
234
|
-
"OIDC_USER_INFO_ENDPOINT",
|
|
235
|
-
"OIDC_GRANT_TYPE",
|
|
236
|
-
"OIDC_FAMILY_NAME_FIELD",
|
|
237
|
-
"OIDC_GIVEN_NAME_FIELD",
|
|
238
|
-
"OIDC_AUTHORIZATION_ENDPOINT"
|
|
239
|
-
];
|
|
240
|
-
if (requiredKeys.every((key) => config2[key])) {
|
|
239
|
+
if (REQUIRED_CONFIG_KEYS.every((key) => config2[key])) {
|
|
241
240
|
return config2;
|
|
242
241
|
}
|
|
243
|
-
throw new Error(
|
|
242
|
+
throw new Error(
|
|
243
|
+
`The following configuration keys are required: ${REQUIRED_CONFIG_KEYS.join(", ")}`
|
|
244
|
+
);
|
|
244
245
|
}
|
|
245
246
|
async function oidcSignIn(ctx) {
|
|
246
|
-
let { state } = ctx.query;
|
|
247
247
|
const { OIDC_CLIENT_ID, OIDC_REDIRECT_URI, OIDC_SCOPES, OIDC_AUTHORIZATION_ENDPOINT } = configValidation();
|
|
248
248
|
const { code_verifier: codeVerifier, code_challenge: codeChallenge } = await pkceChallenge__default.default();
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
249
|
+
const state = node_crypto.randomBytes(32).toString("base64url");
|
|
250
|
+
const nonce = node_crypto.randomBytes(32).toString("base64url");
|
|
252
251
|
const isProduction = strapi.config.get("environment") === "production";
|
|
253
|
-
|
|
252
|
+
const cookieOptions = {
|
|
254
253
|
httpOnly: true,
|
|
255
254
|
maxAge: 6e5,
|
|
255
|
+
// 10 minutes
|
|
256
256
|
secure: isProduction && ctx.request.secure,
|
|
257
257
|
sameSite: "lax"
|
|
258
|
-
}
|
|
259
|
-
ctx.cookies.set("
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
secure: isProduction && ctx.request.secure,
|
|
263
|
-
sameSite: "lax"
|
|
264
|
-
});
|
|
258
|
+
};
|
|
259
|
+
ctx.cookies.set("oidc_code_verifier", codeVerifier, cookieOptions);
|
|
260
|
+
ctx.cookies.set("oidc_state", state, cookieOptions);
|
|
261
|
+
ctx.cookies.set("oidc_nonce", nonce, cookieOptions);
|
|
265
262
|
const params = new URLSearchParams();
|
|
266
263
|
params.append("response_type", "code");
|
|
267
264
|
params.append("client_id", OIDC_CLIENT_ID);
|
|
@@ -270,11 +267,12 @@ async function oidcSignIn(ctx) {
|
|
|
270
267
|
params.append("code_challenge", codeChallenge);
|
|
271
268
|
params.append("code_challenge_method", "S256");
|
|
272
269
|
params.append("state", state);
|
|
270
|
+
params.append("nonce", nonce);
|
|
273
271
|
const authorizationUrl = `${OIDC_AUTHORIZATION_ENDPOINT}?${params.toString()}`;
|
|
274
272
|
ctx.set("Location", authorizationUrl);
|
|
275
273
|
return ctx.send({}, 302);
|
|
276
274
|
}
|
|
277
|
-
async function exchangeTokenAndFetchUserInfo(config2, params) {
|
|
275
|
+
async function exchangeTokenAndFetchUserInfo(config2, params, expectedNonce) {
|
|
278
276
|
const response = await fetch(config2.OIDC_TOKEN_ENDPOINT, {
|
|
279
277
|
method: "POST",
|
|
280
278
|
body: params,
|
|
@@ -283,31 +281,28 @@ async function exchangeTokenAndFetchUserInfo(config2, params) {
|
|
|
283
281
|
}
|
|
284
282
|
});
|
|
285
283
|
if (!response.ok) {
|
|
286
|
-
|
|
287
|
-
throw new Error(
|
|
288
|
-
`Failed to exchange token: ${response.status} ${response.statusText} - ${errText}`
|
|
289
|
-
);
|
|
284
|
+
throw new Error("Token exchange failed");
|
|
290
285
|
}
|
|
291
286
|
const tokenData = await response.json();
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
287
|
+
if (tokenData.id_token) {
|
|
288
|
+
try {
|
|
289
|
+
const payloadB64 = tokenData.id_token.split(".")[1];
|
|
290
|
+
const idTokenPayload = JSON.parse(Buffer.from(payloadB64, "base64url").toString("utf8"));
|
|
291
|
+
if (idTokenPayload.nonce !== expectedNonce) {
|
|
292
|
+
throw new Error("Nonce mismatch");
|
|
293
|
+
}
|
|
294
|
+
} catch (e) {
|
|
295
|
+
if (e.message === "Nonce mismatch") throw e;
|
|
296
|
+
throw new Error("Failed to parse ID token");
|
|
297
|
+
}
|
|
299
298
|
}
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
headers: userInfoEndpointHeaders
|
|
299
|
+
const userResponse = await fetch(config2.OIDC_USER_INFO_ENDPOINT, {
|
|
300
|
+
headers: { Authorization: `Bearer ${tokenData.access_token}` }
|
|
303
301
|
});
|
|
304
302
|
if (!userResponse.ok) {
|
|
305
|
-
|
|
306
|
-
throw new Error(
|
|
307
|
-
`Failed to fetch user info: ${userResponse.status} ${userResponse.statusText} - ${errText}`
|
|
308
|
-
);
|
|
303
|
+
throw new Error("Failed to fetch user info");
|
|
309
304
|
}
|
|
310
|
-
return
|
|
305
|
+
return userResponse.json();
|
|
311
306
|
}
|
|
312
307
|
async function registerNewUser(userService, oauthService2, roleService2, email, userResponseData, whitelistUser, config2, ctx) {
|
|
313
308
|
let roles2 = [];
|
|
@@ -331,22 +326,16 @@ async function registerNewUser(userService, oauthService2, roleService2, email,
|
|
|
331
326
|
async function handleUserAuthentication(userService, oauthService2, roleService2, whitelistService2, userResponseData, config2, ctx) {
|
|
332
327
|
const email = String(userResponseData.email).toLowerCase();
|
|
333
328
|
const whitelistUser = await whitelistService2.checkWhitelistForEmail(email);
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
userResponseData,
|
|
345
|
-
whitelistUser,
|
|
346
|
-
config2,
|
|
347
|
-
ctx
|
|
348
|
-
);
|
|
349
|
-
}
|
|
329
|
+
const activateUser = await userService.findOneByEmail(email) ?? await registerNewUser(
|
|
330
|
+
userService,
|
|
331
|
+
oauthService2,
|
|
332
|
+
roleService2,
|
|
333
|
+
email,
|
|
334
|
+
userResponseData,
|
|
335
|
+
whitelistUser,
|
|
336
|
+
config2,
|
|
337
|
+
ctx
|
|
338
|
+
);
|
|
350
339
|
const jwtToken = await oauthService2.generateToken(activateUser, ctx);
|
|
351
340
|
oauthService2.triggerSignInSuccess(activateUser);
|
|
352
341
|
return { activateUser, jwtToken };
|
|
@@ -362,8 +351,10 @@ async function oidcSignInCallback(ctx) {
|
|
|
362
351
|
}
|
|
363
352
|
const oidcState = ctx.cookies.get("oidc_state");
|
|
364
353
|
const codeVerifier = ctx.cookies.get("oidc_code_verifier");
|
|
354
|
+
const oidcNonce = ctx.cookies.get("oidc_nonce");
|
|
365
355
|
ctx.cookies.set("oidc_state", null);
|
|
366
356
|
ctx.cookies.set("oidc_code_verifier", null);
|
|
357
|
+
ctx.cookies.set("oidc_nonce", null);
|
|
367
358
|
if (!ctx.query.state || ctx.query.state !== oidcState) {
|
|
368
359
|
return ctx.send(oauthService2.renderSignUpError("Invalid state"));
|
|
369
360
|
}
|
|
@@ -375,7 +366,7 @@ async function oidcSignInCallback(ctx) {
|
|
|
375
366
|
params.append("grant_type", config2.OIDC_GRANT_TYPE);
|
|
376
367
|
params.append("code_verifier", codeVerifier);
|
|
377
368
|
try {
|
|
378
|
-
const userResponseData = await exchangeTokenAndFetchUserInfo(config2, params);
|
|
369
|
+
const userResponseData = await exchangeTokenAndFetchUserInfo(config2, params, oidcNonce);
|
|
379
370
|
const { activateUser, jwtToken } = await handleUserAuthentication(
|
|
380
371
|
userService,
|
|
381
372
|
oauthService2,
|
|
@@ -391,7 +382,7 @@ async function oidcSignInCallback(ctx) {
|
|
|
391
382
|
ctx.send(html);
|
|
392
383
|
} catch (e) {
|
|
393
384
|
console.error("ERROR CAUGHT IN OIDC SIGNIN:", e);
|
|
394
|
-
ctx.send(oauthService2.renderSignUpError(
|
|
385
|
+
ctx.send(oauthService2.renderSignUpError("Authentication failed. Please try again."));
|
|
395
386
|
}
|
|
396
387
|
}
|
|
397
388
|
async function logout(ctx) {
|
|
@@ -438,8 +429,11 @@ const role = {
|
|
|
438
429
|
find,
|
|
439
430
|
update
|
|
440
431
|
};
|
|
432
|
+
function getWhitelistService() {
|
|
433
|
+
return strapi.plugin("strapi-plugin-oidc").service("whitelist");
|
|
434
|
+
}
|
|
441
435
|
async function info(ctx) {
|
|
442
|
-
const whitelistService2 =
|
|
436
|
+
const whitelistService2 = getWhitelistService();
|
|
443
437
|
const settings = await whitelistService2.getSettings();
|
|
444
438
|
const whitelistUsers = await whitelistService2.getUsers();
|
|
445
439
|
ctx.body = {
|
|
@@ -450,8 +444,9 @@ async function info(ctx) {
|
|
|
450
444
|
};
|
|
451
445
|
}
|
|
452
446
|
async function updateSettings(ctx) {
|
|
453
|
-
|
|
454
|
-
|
|
447
|
+
const { useWhitelist } = ctx.request.body;
|
|
448
|
+
let { enforceOIDC } = ctx.request.body;
|
|
449
|
+
const whitelistService2 = getWhitelistService();
|
|
455
450
|
if (useWhitelist && enforceOIDC) {
|
|
456
451
|
const users = await whitelistService2.getUsers();
|
|
457
452
|
if (users.length === 0) {
|
|
@@ -462,7 +457,7 @@ async function updateSettings(ctx) {
|
|
|
462
457
|
ctx.body = { useWhitelist, enforceOIDC };
|
|
463
458
|
}
|
|
464
459
|
async function publicSettings(ctx) {
|
|
465
|
-
const whitelistService2 =
|
|
460
|
+
const whitelistService2 = getWhitelistService();
|
|
466
461
|
const settings = await whitelistService2.getSettings();
|
|
467
462
|
const config2 = strapi.config.get("plugin::strapi-plugin-oidc");
|
|
468
463
|
ctx.body = {
|
|
@@ -482,10 +477,11 @@ async function register(ctx) {
|
|
|
482
477
|
where: { email: { $in: emailList } },
|
|
483
478
|
populate: ["roles"]
|
|
484
479
|
});
|
|
485
|
-
const
|
|
480
|
+
const existingUsersByEmail = new Map(existingUsers.map((u) => [u.email, u]));
|
|
481
|
+
const whitelistService2 = getWhitelistService();
|
|
486
482
|
let matchedExistingUsersCount = 0;
|
|
487
483
|
for (const singleEmail of emailList) {
|
|
488
|
-
const existingUser =
|
|
484
|
+
const existingUser = existingUsersByEmail.get(singleEmail);
|
|
489
485
|
let finalRoles = roles2;
|
|
490
486
|
if (existingUser?.roles) {
|
|
491
487
|
finalRoles = existingUser.roles.map((r) => String(r.id));
|
|
@@ -502,14 +498,56 @@ async function register(ctx) {
|
|
|
502
498
|
}
|
|
503
499
|
async function removeEmail(ctx) {
|
|
504
500
|
const { id } = ctx.params;
|
|
505
|
-
const whitelistService2 =
|
|
501
|
+
const whitelistService2 = getWhitelistService();
|
|
506
502
|
await whitelistService2.removeUser(id);
|
|
507
503
|
ctx.body = {};
|
|
508
504
|
}
|
|
505
|
+
async function deleteAll(ctx) {
|
|
506
|
+
await strapi.query("plugin::strapi-plugin-oidc.whitelists").deleteMany({});
|
|
507
|
+
ctx.body = {};
|
|
508
|
+
}
|
|
509
|
+
async function importUsers(ctx) {
|
|
510
|
+
const { users } = ctx.request.body;
|
|
511
|
+
if (!Array.isArray(users)) {
|
|
512
|
+
ctx.status = 400;
|
|
513
|
+
ctx.body = { error: "Expected { users: [{email, roles}] }" };
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const allRoles = await strapi.query("admin::role").findMany({});
|
|
517
|
+
const roleNameToId = new Map(allRoles.map((r) => [r.name, String(r.id)]));
|
|
518
|
+
const resolveRole = (nameOrId) => roleNameToId.get(nameOrId) ?? nameOrId;
|
|
519
|
+
const normalized = users.filter((u) => u?.email).map((u) => ({
|
|
520
|
+
email: String(u.email).trim().toLowerCase(),
|
|
521
|
+
roles: (Array.isArray(u.roles) ? u.roles : []).map(resolveRole)
|
|
522
|
+
}));
|
|
523
|
+
const seen = /* @__PURE__ */ new Set();
|
|
524
|
+
const deduped = normalized.filter((u) => {
|
|
525
|
+
if (seen.has(u.email)) return false;
|
|
526
|
+
seen.add(u.email);
|
|
527
|
+
return true;
|
|
528
|
+
});
|
|
529
|
+
const strapiUsers = await strapi.query("admin::user").findMany({
|
|
530
|
+
where: { email: { $in: deduped.map((u) => u.email) } },
|
|
531
|
+
populate: ["roles"]
|
|
532
|
+
});
|
|
533
|
+
const strapiUserMap = new Map(strapiUsers.map((u) => [u.email, u]));
|
|
534
|
+
const whitelistService2 = getWhitelistService();
|
|
535
|
+
const existing = await whitelistService2.getUsers();
|
|
536
|
+
const existingEmails = new Set(existing.map((u) => u.email));
|
|
537
|
+
let importedCount = 0;
|
|
538
|
+
for (const user of deduped) {
|
|
539
|
+
if (existingEmails.has(user.email)) continue;
|
|
540
|
+
const strapiUser = strapiUserMap.get(user.email);
|
|
541
|
+
const finalRoles = strapiUser?.roles?.length ? strapiUser.roles.map((r) => String(r.id)) : user.roles;
|
|
542
|
+
await whitelistService2.registerUser(user.email, finalRoles);
|
|
543
|
+
importedCount++;
|
|
544
|
+
}
|
|
545
|
+
ctx.body = { importedCount };
|
|
546
|
+
}
|
|
509
547
|
async function syncUsers(ctx) {
|
|
510
|
-
|
|
511
|
-
users =
|
|
512
|
-
const whitelistService2 =
|
|
548
|
+
const { users: rawUsers } = ctx.request.body;
|
|
549
|
+
const users = rawUsers.map((u) => ({ ...u, email: String(u.email).toLowerCase() }));
|
|
550
|
+
const whitelistService2 = getWhitelistService();
|
|
513
551
|
const currentUsers = await whitelistService2.getUsers();
|
|
514
552
|
let matchedExistingUsersCount = 0;
|
|
515
553
|
const emailsToSync = users.map((u) => u.email);
|
|
@@ -517,26 +555,29 @@ async function syncUsers(ctx) {
|
|
|
517
555
|
where: { email: { $in: emailsToSync } },
|
|
518
556
|
populate: ["roles"]
|
|
519
557
|
});
|
|
558
|
+
const syncEmailSet = new Set(emailsToSync);
|
|
559
|
+
const currentUsersByEmail = new Map(currentUsers.map((u) => [u.email, u]));
|
|
560
|
+
const strapiUsersByEmail = new Map(existingStrapiUsers.map((u) => [u.email, u]));
|
|
520
561
|
for (const currUser of currentUsers) {
|
|
521
|
-
if (!
|
|
562
|
+
if (!syncEmailSet.has(currUser.email)) {
|
|
522
563
|
await whitelistService2.removeUser(currUser.id);
|
|
523
564
|
}
|
|
524
565
|
}
|
|
525
566
|
for (const user of users) {
|
|
526
|
-
const
|
|
567
|
+
const currUser = currentUsersByEmail.get(user.email);
|
|
527
568
|
let finalRoles = user.roles;
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
569
|
+
if (!currUser) {
|
|
570
|
+
const existingStrapiUser = strapiUsersByEmail.get(user.email);
|
|
571
|
+
if (existingStrapiUser?.roles) {
|
|
572
|
+
finalRoles = existingStrapiUser.roles.map((r) => String(r.id));
|
|
573
|
+
matchedExistingUsersCount++;
|
|
574
|
+
}
|
|
575
|
+
await whitelistService2.registerUser(user.email, finalRoles);
|
|
576
|
+
} else {
|
|
534
577
|
await strapi.query("plugin::strapi-plugin-oidc.whitelists").update({
|
|
535
578
|
where: { id: currUser.id },
|
|
536
579
|
data: { roles: finalRoles }
|
|
537
580
|
});
|
|
538
|
-
} else {
|
|
539
|
-
await whitelistService2.registerUser(user.email, finalRoles);
|
|
540
581
|
}
|
|
541
582
|
}
|
|
542
583
|
ctx.body = { matchedExistingUsersCount };
|
|
@@ -547,7 +588,9 @@ const whitelist = {
|
|
|
547
588
|
publicSettings,
|
|
548
589
|
register,
|
|
549
590
|
removeEmail,
|
|
550
|
-
|
|
591
|
+
deleteAll,
|
|
592
|
+
syncUsers,
|
|
593
|
+
importUsers
|
|
551
594
|
};
|
|
552
595
|
const controllers = {
|
|
553
596
|
oidc,
|
|
@@ -571,134 +614,133 @@ const rateLimitMiddleware = async (ctx, next) => {
|
|
|
571
614
|
rateLimitMap.set(ip, requestStamps);
|
|
572
615
|
await next();
|
|
573
616
|
};
|
|
574
|
-
const
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
policies: [
|
|
581
|
-
"admin::isAuthenticatedAdmin",
|
|
582
|
-
{ name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.read"] } }
|
|
583
|
-
]
|
|
584
|
-
}
|
|
585
|
-
},
|
|
586
|
-
{
|
|
587
|
-
method: "PUT",
|
|
588
|
-
path: "/oidc-roles",
|
|
589
|
-
handler: "role.update",
|
|
590
|
-
config: {
|
|
591
|
-
policies: [
|
|
592
|
-
"admin::isAuthenticatedAdmin",
|
|
593
|
-
{
|
|
594
|
-
name: "admin::hasPermissions",
|
|
595
|
-
config: { actions: ["plugin::strapi-plugin-oidc.update"] }
|
|
596
|
-
}
|
|
597
|
-
]
|
|
598
|
-
}
|
|
599
|
-
},
|
|
600
|
-
{
|
|
601
|
-
method: "GET",
|
|
602
|
-
path: "/oidc",
|
|
603
|
-
handler: "oidc.oidcSignIn",
|
|
604
|
-
config: {
|
|
605
|
-
auth: false,
|
|
606
|
-
middlewares: [rateLimitMiddleware]
|
|
607
|
-
}
|
|
608
|
-
},
|
|
609
|
-
{
|
|
610
|
-
method: "GET",
|
|
611
|
-
path: "/oidc/callback",
|
|
612
|
-
handler: "oidc.oidcSignInCallback",
|
|
613
|
-
config: {
|
|
614
|
-
auth: false,
|
|
615
|
-
middlewares: [rateLimitMiddleware]
|
|
616
|
-
}
|
|
617
|
-
},
|
|
618
|
-
{
|
|
619
|
-
method: "GET",
|
|
620
|
-
path: "/logout",
|
|
621
|
-
handler: "oidc.logout",
|
|
622
|
-
config: {
|
|
623
|
-
auth: false
|
|
624
|
-
}
|
|
625
|
-
},
|
|
626
|
-
{
|
|
627
|
-
method: "GET",
|
|
628
|
-
path: "/whitelist",
|
|
629
|
-
handler: "whitelist.info",
|
|
630
|
-
config: {
|
|
631
|
-
policies: [
|
|
632
|
-
"admin::isAuthenticatedAdmin",
|
|
633
|
-
{ name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.read"] } }
|
|
634
|
-
]
|
|
635
|
-
}
|
|
636
|
-
},
|
|
637
|
-
{
|
|
638
|
-
method: "PUT",
|
|
639
|
-
path: "/whitelist/settings",
|
|
640
|
-
handler: "whitelist.updateSettings",
|
|
641
|
-
config: {
|
|
642
|
-
policies: [
|
|
643
|
-
"admin::isAuthenticatedAdmin",
|
|
644
|
-
{
|
|
645
|
-
name: "admin::hasPermissions",
|
|
646
|
-
config: { actions: ["plugin::strapi-plugin-oidc.update"] }
|
|
647
|
-
}
|
|
648
|
-
]
|
|
649
|
-
}
|
|
650
|
-
},
|
|
651
|
-
{
|
|
652
|
-
method: "GET",
|
|
653
|
-
path: "/settings/public",
|
|
654
|
-
handler: "whitelist.publicSettings",
|
|
655
|
-
config: {
|
|
656
|
-
auth: false
|
|
657
|
-
}
|
|
658
|
-
},
|
|
659
|
-
{
|
|
660
|
-
method: "PUT",
|
|
661
|
-
path: "/whitelist/sync",
|
|
662
|
-
handler: "whitelist.syncUsers",
|
|
663
|
-
config: {
|
|
664
|
-
policies: [
|
|
665
|
-
"admin::isAuthenticatedAdmin",
|
|
666
|
-
{
|
|
667
|
-
name: "admin::hasPermissions",
|
|
668
|
-
config: { actions: ["plugin::strapi-plugin-oidc.update"] }
|
|
669
|
-
}
|
|
670
|
-
]
|
|
671
|
-
}
|
|
672
|
-
},
|
|
673
|
-
{
|
|
674
|
-
method: "POST",
|
|
675
|
-
path: "/whitelist",
|
|
676
|
-
handler: "whitelist.register",
|
|
677
|
-
config: {
|
|
678
|
-
policies: [
|
|
679
|
-
"admin::isAuthenticatedAdmin",
|
|
680
|
-
{
|
|
681
|
-
name: "admin::hasPermissions",
|
|
682
|
-
config: { actions: ["plugin::strapi-plugin-oidc.update"] }
|
|
683
|
-
}
|
|
684
|
-
]
|
|
617
|
+
const adminPolicies = (action) => ({
|
|
618
|
+
policies: [
|
|
619
|
+
"admin::isAuthenticatedAdmin",
|
|
620
|
+
{
|
|
621
|
+
name: "admin::hasPermissions",
|
|
622
|
+
config: { actions: [`plugin::strapi-plugin-oidc.${action}`] }
|
|
685
623
|
}
|
|
624
|
+
]
|
|
625
|
+
});
|
|
626
|
+
const routes = {
|
|
627
|
+
admin: {
|
|
628
|
+
type: "admin",
|
|
629
|
+
routes: [
|
|
630
|
+
{
|
|
631
|
+
method: "GET",
|
|
632
|
+
path: "/oidc-roles",
|
|
633
|
+
handler: "role.find",
|
|
634
|
+
config: adminPolicies("read")
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
method: "PUT",
|
|
638
|
+
path: "/oidc-roles",
|
|
639
|
+
handler: "role.update",
|
|
640
|
+
config: adminPolicies("update")
|
|
641
|
+
},
|
|
642
|
+
{
|
|
643
|
+
method: "GET",
|
|
644
|
+
path: "/oidc",
|
|
645
|
+
handler: "oidc.oidcSignIn",
|
|
646
|
+
config: { auth: false, middlewares: [rateLimitMiddleware] }
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
method: "GET",
|
|
650
|
+
path: "/oidc/callback",
|
|
651
|
+
handler: "oidc.oidcSignInCallback",
|
|
652
|
+
config: { auth: false, middlewares: [rateLimitMiddleware] }
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
method: "GET",
|
|
656
|
+
path: "/logout",
|
|
657
|
+
handler: "oidc.logout",
|
|
658
|
+
config: { auth: false }
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
method: "GET",
|
|
662
|
+
path: "/whitelist",
|
|
663
|
+
handler: "whitelist.info",
|
|
664
|
+
config: adminPolicies("read")
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
method: "PUT",
|
|
668
|
+
path: "/whitelist/settings",
|
|
669
|
+
handler: "whitelist.updateSettings",
|
|
670
|
+
config: adminPolicies("update")
|
|
671
|
+
},
|
|
672
|
+
{
|
|
673
|
+
method: "GET",
|
|
674
|
+
path: "/settings/public",
|
|
675
|
+
handler: "whitelist.publicSettings",
|
|
676
|
+
config: { auth: false }
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
method: "PUT",
|
|
680
|
+
path: "/whitelist/sync",
|
|
681
|
+
handler: "whitelist.syncUsers",
|
|
682
|
+
config: adminPolicies("update")
|
|
683
|
+
},
|
|
684
|
+
{
|
|
685
|
+
method: "POST",
|
|
686
|
+
path: "/whitelist/import",
|
|
687
|
+
handler: "whitelist.importUsers",
|
|
688
|
+
config: adminPolicies("update")
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
method: "POST",
|
|
692
|
+
path: "/whitelist",
|
|
693
|
+
handler: "whitelist.register",
|
|
694
|
+
config: adminPolicies("update")
|
|
695
|
+
},
|
|
696
|
+
{
|
|
697
|
+
method: "DELETE",
|
|
698
|
+
path: "/whitelist/:id",
|
|
699
|
+
handler: "whitelist.removeEmail",
|
|
700
|
+
config: adminPolicies("update")
|
|
701
|
+
},
|
|
702
|
+
{
|
|
703
|
+
method: "DELETE",
|
|
704
|
+
path: "/whitelist",
|
|
705
|
+
handler: "whitelist.deleteAll",
|
|
706
|
+
config: adminPolicies("update")
|
|
707
|
+
}
|
|
708
|
+
]
|
|
686
709
|
},
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
710
|
+
// API-token-authenticated routes for programmatic whitelist management.
|
|
711
|
+
// Accessible at /strapi-plugin-oidc/... using a Strapi API token
|
|
712
|
+
// (full-access or custom) in the Authorization: Bearer <token> header.
|
|
713
|
+
"content-api": {
|
|
714
|
+
type: "content-api",
|
|
715
|
+
routes: [
|
|
716
|
+
{
|
|
717
|
+
method: "GET",
|
|
718
|
+
path: "/whitelist",
|
|
719
|
+
handler: "whitelist.info"
|
|
720
|
+
},
|
|
721
|
+
{
|
|
722
|
+
method: "POST",
|
|
723
|
+
path: "/whitelist",
|
|
724
|
+
handler: "whitelist.register"
|
|
725
|
+
},
|
|
726
|
+
{
|
|
727
|
+
method: "POST",
|
|
728
|
+
path: "/whitelist/import",
|
|
729
|
+
handler: "whitelist.importUsers"
|
|
730
|
+
},
|
|
731
|
+
{
|
|
732
|
+
method: "DELETE",
|
|
733
|
+
path: "/whitelist/:id",
|
|
734
|
+
handler: "whitelist.removeEmail"
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
method: "DELETE",
|
|
738
|
+
path: "/whitelist",
|
|
739
|
+
handler: "whitelist.deleteAll"
|
|
740
|
+
}
|
|
741
|
+
]
|
|
700
742
|
}
|
|
701
|
-
|
|
743
|
+
};
|
|
702
744
|
const policies = {};
|
|
703
745
|
function renderHtmlTemplate(title, content) {
|
|
704
746
|
return `
|
|
@@ -834,7 +876,7 @@ function oauthService({ strapi: strapi2 }) {
|
|
|
834
876
|
roles: roles2,
|
|
835
877
|
preferedLanguage: locale
|
|
836
878
|
});
|
|
837
|
-
return
|
|
879
|
+
return userService.register({
|
|
838
880
|
registrationToken: createdUser.registrationToken,
|
|
839
881
|
userInfo: {
|
|
840
882
|
firstname: firstname || "unset",
|
|
@@ -855,7 +897,7 @@ function oauthService({ strapi: strapi2 }) {
|
|
|
855
897
|
if (!baseAlias) {
|
|
856
898
|
return baseEmail;
|
|
857
899
|
}
|
|
858
|
-
const alias = baseAlias.replace(
|
|
900
|
+
const alias = baseAlias.replace(/\+/g, "");
|
|
859
901
|
const beforePosition = baseEmail.indexOf("@");
|
|
860
902
|
const origin = baseEmail.substring(0, beforePosition);
|
|
861
903
|
const domain = baseEmail.substring(beforePosition);
|
|
@@ -892,11 +934,9 @@ function oauthService({ strapi: strapi2 }) {
|
|
|
892
934
|
provider: "strapi-plugin-oidc"
|
|
893
935
|
});
|
|
894
936
|
},
|
|
895
|
-
// Sign In Success
|
|
896
937
|
renderSignUpSuccess(jwtToken, user, nonce) {
|
|
897
938
|
const config2 = strapi2.config.get("plugin::strapi-plugin-oidc");
|
|
898
|
-
const
|
|
899
|
-
const isRememberMe = !!REMEMBER_ME;
|
|
939
|
+
const isRememberMe = !!config2["REMEMBER_ME"];
|
|
900
940
|
const content = `
|
|
901
941
|
<noscript>
|
|
902
942
|
<div class="card">
|
|
@@ -922,7 +962,6 @@ function oauthService({ strapi: strapi2 }) {
|
|
|
922
962
|
<\/script>`;
|
|
923
963
|
return renderHtmlTemplate("Authenticating...", content);
|
|
924
964
|
},
|
|
925
|
-
// Sign In Error
|
|
926
965
|
renderSignUpError(message) {
|
|
927
966
|
const safeMessage = String(message).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
928
967
|
const content = `
|
|
@@ -950,8 +989,7 @@ function oauthService({ strapi: strapi2 }) {
|
|
|
950
989
|
const userId = String(user.id);
|
|
951
990
|
const deviceId = node_crypto.randomUUID();
|
|
952
991
|
const config2 = strapi2.config.get("plugin::strapi-plugin-oidc");
|
|
953
|
-
const
|
|
954
|
-
const rememberMe = !!REMEMBER_ME;
|
|
992
|
+
const rememberMe = !!config2["REMEMBER_ME"];
|
|
955
993
|
const { token: refreshToken, absoluteExpiresAt } = await sessionManager(
|
|
956
994
|
"admin"
|
|
957
995
|
).generateRefreshToken(userId, deviceId, {
|