strapi-plugin-oidc 1.0.0
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/LICENSE +21 -0
- package/README.md +88 -0
- package/dist/_chunks/en-AsM8uCFB.mjs +23 -0
- package/dist/_chunks/en-BbQ9XzfO.js +23 -0
- package/dist/_chunks/fr-C8Qw4iPZ.js +4 -0
- package/dist/_chunks/fr-hkSxFuzl.mjs +4 -0
- package/dist/_chunks/index-Bq6bRISt.js +414 -0
- package/dist/_chunks/index-BuS0wmlA.mjs +412 -0
- package/dist/_chunks/index-CHl-03dY.mjs +204 -0
- package/dist/_chunks/index-DR3YYYZL.js +203 -0
- package/dist/_chunks/ja-B2WcMFA2.js +23 -0
- package/dist/_chunks/ja-COdupAQd.mjs +23 -0
- package/dist/admin/en-f0TxVfx7.mjs +41 -0
- package/dist/admin/en-jFPbEFeK.js +41 -0
- package/dist/admin/index-BuuCScSN.mjs +143 -0
- package/dist/admin/index-C0GkDnGG.js +142 -0
- package/dist/admin/index-D_0jCOLk.js +491 -0
- package/dist/admin/index-DwpTg1-J.mjs +489 -0
- package/dist/admin/index.js +4 -0
- package/dist/admin/index.mjs +4 -0
- package/dist/server/index.js +746 -0
- package/dist/server/index.mjs +741 -0
- package/package.json +107 -0
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const axios = require("axios");
|
|
4
|
+
const node_crypto = require("node:crypto");
|
|
5
|
+
const pkceChallenge = require("pkce-challenge");
|
|
6
|
+
const strapiUtils = require("@strapi/utils");
|
|
7
|
+
const generator = require("generate-password");
|
|
8
|
+
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
9
|
+
const axios__default = /* @__PURE__ */ _interopDefault(axios);
|
|
10
|
+
const pkceChallenge__default = /* @__PURE__ */ _interopDefault(pkceChallenge);
|
|
11
|
+
const strapiUtils__default = /* @__PURE__ */ _interopDefault(strapiUtils);
|
|
12
|
+
const generator__default = /* @__PURE__ */ _interopDefault(generator);
|
|
13
|
+
function register$1() {
|
|
14
|
+
}
|
|
15
|
+
async function bootstrap({ strapi: strapi2 }) {
|
|
16
|
+
const actions = [
|
|
17
|
+
{
|
|
18
|
+
section: "plugins",
|
|
19
|
+
displayName: "Read",
|
|
20
|
+
uid: "read",
|
|
21
|
+
pluginName: "strapi-plugin-oidc"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
section: "plugins",
|
|
25
|
+
displayName: "Update",
|
|
26
|
+
uid: "update",
|
|
27
|
+
pluginName: "strapi-plugin-oidc"
|
|
28
|
+
}
|
|
29
|
+
];
|
|
30
|
+
await strapi2.admin.services.permission.actionProvider.registerMany(actions);
|
|
31
|
+
try {
|
|
32
|
+
const oidcRoleCount = await strapi2.query("plugin::strapi-plugin-oidc.roles").count({
|
|
33
|
+
where: { oauth_type: "4" }
|
|
34
|
+
});
|
|
35
|
+
if (oidcRoleCount === 0) {
|
|
36
|
+
const editorRole = await strapi2.query("admin::role").findOne({
|
|
37
|
+
where: { code: "strapi-editor" }
|
|
38
|
+
});
|
|
39
|
+
if (editorRole) {
|
|
40
|
+
await strapi2.query("plugin::strapi-plugin-oidc.roles").create({
|
|
41
|
+
data: {
|
|
42
|
+
oauth_type: "4",
|
|
43
|
+
roles: [editorRole.id.toString()]
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
} catch (err) {
|
|
49
|
+
strapi2.log.warn("Could not initialize default OIDC role:", err.message);
|
|
50
|
+
}
|
|
51
|
+
strapi2.db.lifecycles.subscribe({
|
|
52
|
+
models: ["admin::user"],
|
|
53
|
+
async afterUpdate(event) {
|
|
54
|
+
const { result } = event;
|
|
55
|
+
if (!result?.email) return;
|
|
56
|
+
const query = strapi2.query("plugin::strapi-plugin-oidc.whitelists");
|
|
57
|
+
const whitelistEntry = await query.findOne({ where: { email: result.email } });
|
|
58
|
+
if (!whitelistEntry) return;
|
|
59
|
+
const userWithRoles = await strapi2.query("admin::user").findOne({
|
|
60
|
+
where: { id: result.id },
|
|
61
|
+
populate: ["roles"]
|
|
62
|
+
});
|
|
63
|
+
if (userWithRoles?.roles) {
|
|
64
|
+
const roleIds = userWithRoles.roles.map((r) => r.id.toString());
|
|
65
|
+
await query.update({
|
|
66
|
+
where: { id: whitelistEntry.id },
|
|
67
|
+
data: { roles: roleIds }
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function destroy() {
|
|
74
|
+
}
|
|
75
|
+
const config = {
|
|
76
|
+
default: {
|
|
77
|
+
REMEMBER_ME: false,
|
|
78
|
+
OIDC_REDIRECT_URI: "http://localhost:1337/strapi-plugin-oidc/oidc/callback",
|
|
79
|
+
OIDC_CLIENT_ID: "",
|
|
80
|
+
OIDC_CLIENT_SECRET: "",
|
|
81
|
+
OIDC_SCOPES: "openid profile email",
|
|
82
|
+
OIDC_AUTHORIZATION_ENDPOINT: "",
|
|
83
|
+
OIDC_TOKEN_ENDPOINT: "",
|
|
84
|
+
OIDC_USER_INFO_ENDPOINT: "",
|
|
85
|
+
OIDC_USER_INFO_ENDPOINT_WITH_AUTH_HEADER: false,
|
|
86
|
+
OIDC_GRANT_TYPE: "authorization_code",
|
|
87
|
+
OIDC_FAMILY_NAME_FIELD: "family_name",
|
|
88
|
+
OIDC_GIVEN_NAME_FIELD: "given_name",
|
|
89
|
+
OIDC_LOGOUT_URL: ""
|
|
90
|
+
},
|
|
91
|
+
validator() {
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const info$2 = { "singularName": "roles", "pluralName": "oidc-roles", "collectionName": "oidc-roles", "displayName": "oidc-role", "description": "" };
|
|
95
|
+
const options$1 = { "draftAndPublish": false };
|
|
96
|
+
const pluginOptions$1 = { "content-manager": { "visible": false }, "content-type-builder": { "visible": false } };
|
|
97
|
+
const attributes$1 = { "oauth_type": { "type": "string", "configurable": false, "required": true }, "roles": { "type": "json", "configurable": false } };
|
|
98
|
+
const schema$1 = {
|
|
99
|
+
info: info$2,
|
|
100
|
+
options: options$1,
|
|
101
|
+
pluginOptions: pluginOptions$1,
|
|
102
|
+
attributes: attributes$1
|
|
103
|
+
};
|
|
104
|
+
const roles = {
|
|
105
|
+
schema: schema$1
|
|
106
|
+
};
|
|
107
|
+
const info$1 = { "singularName": "whitelists", "pluralName": "whitelists", "collectionName": "whitelists", "displayName": "whitelist", "description": "" };
|
|
108
|
+
const options = { "draftAndPublish": false };
|
|
109
|
+
const pluginOptions = { "content-manager": { "visible": false }, "content-type-builder": { "visible": false } };
|
|
110
|
+
const attributes = { "email": { "type": "string", "configurable": false, "required": true, "unique": true }, "roles": { "type": "json", "configurable": false } };
|
|
111
|
+
const schema = {
|
|
112
|
+
info: info$1,
|
|
113
|
+
options,
|
|
114
|
+
pluginOptions,
|
|
115
|
+
attributes
|
|
116
|
+
};
|
|
117
|
+
const whitelists = {
|
|
118
|
+
schema
|
|
119
|
+
};
|
|
120
|
+
const contentTypes = {
|
|
121
|
+
roles,
|
|
122
|
+
whitelists
|
|
123
|
+
};
|
|
124
|
+
function configValidation() {
|
|
125
|
+
const config2 = strapi.config.get("plugin::strapi-plugin-oidc");
|
|
126
|
+
if (config2["OIDC_CLIENT_ID"] && config2["OIDC_CLIENT_SECRET"] && config2["OIDC_REDIRECT_URI"] && config2["OIDC_SCOPES"] && config2["OIDC_TOKEN_ENDPOINT"] && config2["OIDC_USER_INFO_ENDPOINT"] && config2["OIDC_GRANT_TYPE"] && config2["OIDC_FAMILY_NAME_FIELD"] && config2["OIDC_GIVEN_NAME_FIELD"] && config2["OIDC_AUTHORIZATION_ENDPOINT"]) {
|
|
127
|
+
return config2;
|
|
128
|
+
}
|
|
129
|
+
throw new Error("OIDC_AUTHORIZATION_ENDPOINT,OIDC_TOKEN_ENDPOINT, OIDC_USER_INFO_ENDPOINT,OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC_REDIRECT_URI, and OIDC_SCOPES are required");
|
|
130
|
+
}
|
|
131
|
+
async function oidcSignIn(ctx) {
|
|
132
|
+
let { state } = ctx.query;
|
|
133
|
+
const { OIDC_CLIENT_ID, OIDC_REDIRECT_URI, OIDC_SCOPES, OIDC_AUTHORIZATION_ENDPOINT } = configValidation();
|
|
134
|
+
const { code_verifier: codeVerifier, code_challenge: codeChallenge } = await pkceChallenge__default.default();
|
|
135
|
+
ctx.session.codeVerifier = codeVerifier;
|
|
136
|
+
if (!state) {
|
|
137
|
+
state = node_crypto.randomBytes(32).toString("base64url");
|
|
138
|
+
}
|
|
139
|
+
ctx.session.oidcState = state;
|
|
140
|
+
const params = new URLSearchParams();
|
|
141
|
+
params.append("response_type", "code");
|
|
142
|
+
params.append("client_id", OIDC_CLIENT_ID);
|
|
143
|
+
params.append("redirect_uri", OIDC_REDIRECT_URI);
|
|
144
|
+
params.append("scope", OIDC_SCOPES);
|
|
145
|
+
params.append("code_challenge", codeChallenge);
|
|
146
|
+
params.append("code_challenge_method", "S256");
|
|
147
|
+
params.append("state", state);
|
|
148
|
+
const authorizationUrl = `${OIDC_AUTHORIZATION_ENDPOINT}?${params.toString()}`;
|
|
149
|
+
ctx.set("Location", authorizationUrl);
|
|
150
|
+
return ctx.send({}, 302);
|
|
151
|
+
}
|
|
152
|
+
async function oidcSignInCallback(ctx) {
|
|
153
|
+
const config2 = configValidation();
|
|
154
|
+
const httpClient = axios__default.default.create();
|
|
155
|
+
const userService = strapi.service("admin::user");
|
|
156
|
+
const oauthService2 = strapi.plugin("strapi-plugin-oidc").service("oauth");
|
|
157
|
+
const roleService2 = strapi.plugin("strapi-plugin-oidc").service("role");
|
|
158
|
+
const whitelistService2 = strapi.plugin("strapi-plugin-oidc").service("whitelist");
|
|
159
|
+
if (!ctx.query.code) {
|
|
160
|
+
return ctx.send(oauthService2.renderSignUpError(`code Not Found`));
|
|
161
|
+
}
|
|
162
|
+
if (!ctx.query.state || ctx.query.state !== ctx.session.oidcState) {
|
|
163
|
+
return ctx.send(oauthService2.renderSignUpError(`Invalid state`));
|
|
164
|
+
}
|
|
165
|
+
const params = new URLSearchParams();
|
|
166
|
+
params.append("code", ctx.query.code);
|
|
167
|
+
params.append("client_id", config2["OIDC_CLIENT_ID"]);
|
|
168
|
+
params.append("client_secret", config2["OIDC_CLIENT_SECRET"]);
|
|
169
|
+
params.append("redirect_uri", config2["OIDC_REDIRECT_URI"]);
|
|
170
|
+
params.append("grant_type", config2["OIDC_GRANT_TYPE"]);
|
|
171
|
+
params.append("code_verifier", ctx.session.codeVerifier);
|
|
172
|
+
try {
|
|
173
|
+
const response = await httpClient.post(config2["OIDC_TOKEN_ENDPOINT"], params, {
|
|
174
|
+
headers: {
|
|
175
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
let userInfoEndpointHeaders = {};
|
|
179
|
+
let userInfoEndpointParameters = `?access_token=${response.data.access_token}`;
|
|
180
|
+
if (config2["OIDC_USER_INFO_ENDPOINT_WITH_AUTH_HEADER"]) {
|
|
181
|
+
userInfoEndpointHeaders = {
|
|
182
|
+
headers: { Authorization: `Bearer ${response.data.access_token}` }
|
|
183
|
+
};
|
|
184
|
+
userInfoEndpointParameters = "";
|
|
185
|
+
}
|
|
186
|
+
const userInfoEndpoint = `${config2["OIDC_USER_INFO_ENDPOINT"]}${userInfoEndpointParameters}`;
|
|
187
|
+
const userResponse = await httpClient.get(
|
|
188
|
+
userInfoEndpoint,
|
|
189
|
+
userInfoEndpointHeaders
|
|
190
|
+
);
|
|
191
|
+
const email = userResponse.data.email;
|
|
192
|
+
const whitelistUser = await whitelistService2.checkWhitelistForEmail(email);
|
|
193
|
+
const dbUser = await userService.findOneByEmail(email);
|
|
194
|
+
let activateUser;
|
|
195
|
+
let jwtToken;
|
|
196
|
+
if (dbUser) {
|
|
197
|
+
activateUser = dbUser;
|
|
198
|
+
jwtToken = await oauthService2.generateToken(dbUser, ctx);
|
|
199
|
+
} else {
|
|
200
|
+
let roles2 = [];
|
|
201
|
+
if (whitelistUser && whitelistUser.roles && whitelistUser.roles.length > 0) {
|
|
202
|
+
roles2 = whitelistUser.roles;
|
|
203
|
+
} else {
|
|
204
|
+
const oidcRoles = await roleService2.oidcRoles();
|
|
205
|
+
roles2 = oidcRoles && oidcRoles["roles"] ? oidcRoles["roles"] : [];
|
|
206
|
+
}
|
|
207
|
+
const defaultLocale = oauthService2.localeFindByHeader(ctx.request.headers);
|
|
208
|
+
activateUser = await oauthService2.createUser(
|
|
209
|
+
email,
|
|
210
|
+
userResponse.data[config2["OIDC_FAMILY_NAME_FIELD"]],
|
|
211
|
+
userResponse.data[config2["OIDC_GIVEN_NAME_FIELD"]],
|
|
212
|
+
defaultLocale,
|
|
213
|
+
roles2
|
|
214
|
+
);
|
|
215
|
+
jwtToken = await oauthService2.generateToken(activateUser, ctx);
|
|
216
|
+
await oauthService2.triggerWebHook(activateUser);
|
|
217
|
+
}
|
|
218
|
+
oauthService2.triggerSignInSuccess(activateUser);
|
|
219
|
+
const nonce = node_crypto.randomUUID();
|
|
220
|
+
const html = oauthService2.renderSignUpSuccess(jwtToken, activateUser, nonce);
|
|
221
|
+
ctx.set("Content-Security-Policy", `script-src 'nonce-${nonce}'`);
|
|
222
|
+
ctx.send(html);
|
|
223
|
+
} catch (e) {
|
|
224
|
+
console.error(e);
|
|
225
|
+
ctx.send(oauthService2.renderSignUpError(e.message));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async function logout(ctx) {
|
|
229
|
+
const config2 = strapi.config.get("plugin::strapi-plugin-oidc");
|
|
230
|
+
const logoutUrl = config2["OIDC_LOGOUT_URL"];
|
|
231
|
+
if (logoutUrl) {
|
|
232
|
+
ctx.redirect(logoutUrl);
|
|
233
|
+
} else {
|
|
234
|
+
const adminPanelUrl = strapi.config.get("admin.url", "/admin");
|
|
235
|
+
ctx.redirect(`${adminPanelUrl}/auth/login`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
const oidc = {
|
|
239
|
+
oidcSignIn,
|
|
240
|
+
oidcSignInCallback,
|
|
241
|
+
logout
|
|
242
|
+
};
|
|
243
|
+
async function find(ctx) {
|
|
244
|
+
const roleService2 = strapi.plugin("strapi-plugin-oidc").service("role");
|
|
245
|
+
const roles2 = await roleService2.find();
|
|
246
|
+
const oidcConstants = roleService2.getOidcRoles();
|
|
247
|
+
for (const oidc2 of oidcConstants) {
|
|
248
|
+
for (const role2 of roles2) {
|
|
249
|
+
if (role2["oauth_type"] === oidc2["oauth_type"]) {
|
|
250
|
+
oidc2["role"] = role2["roles"];
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
ctx.send(oidcConstants);
|
|
255
|
+
}
|
|
256
|
+
async function update(ctx) {
|
|
257
|
+
try {
|
|
258
|
+
const { roles: roles2 } = ctx.request.body;
|
|
259
|
+
const roleService2 = strapi.plugin("strapi-plugin-oidc").service("role");
|
|
260
|
+
await roleService2.update(roles2);
|
|
261
|
+
ctx.send({}, 204);
|
|
262
|
+
} catch (e) {
|
|
263
|
+
console.log(e);
|
|
264
|
+
ctx.send({}, 400);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const role = {
|
|
268
|
+
find,
|
|
269
|
+
update
|
|
270
|
+
};
|
|
271
|
+
async function info(ctx) {
|
|
272
|
+
const whitelistService2 = strapi.plugin("strapi-plugin-oidc").service("whitelist");
|
|
273
|
+
const settings = await whitelistService2.getSettings();
|
|
274
|
+
const whitelistUsers = await whitelistService2.getUsers();
|
|
275
|
+
ctx.body = {
|
|
276
|
+
useWhitelist: settings.useWhitelist,
|
|
277
|
+
enforceOIDC: settings.enforceOIDC || false,
|
|
278
|
+
whitelistUsers
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
async function updateSettings(ctx) {
|
|
282
|
+
const { useWhitelist, enforceOIDC } = ctx.request.body;
|
|
283
|
+
const whitelistService2 = strapi.plugin("strapi-plugin-oidc").service("whitelist");
|
|
284
|
+
await whitelistService2.setSettings({ useWhitelist, enforceOIDC });
|
|
285
|
+
ctx.body = { useWhitelist, enforceOIDC };
|
|
286
|
+
}
|
|
287
|
+
async function publicSettings(ctx) {
|
|
288
|
+
const whitelistService2 = strapi.plugin("strapi-plugin-oidc").service("whitelist");
|
|
289
|
+
const settings = await whitelistService2.getSettings();
|
|
290
|
+
ctx.body = {
|
|
291
|
+
enforceOIDC: settings.enforceOIDC || false
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
async function register(ctx) {
|
|
295
|
+
const { email, roles: roles2 } = ctx.request.body;
|
|
296
|
+
if (!email) {
|
|
297
|
+
ctx.body = {
|
|
298
|
+
message: "Please enter a valid email address"
|
|
299
|
+
};
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const emailList = Array.isArray(email) ? email : email.split(",").map((e) => e.trim()).filter((e) => e);
|
|
303
|
+
const existingUsers = await strapi.query("admin::user").findMany({
|
|
304
|
+
where: { email: { $in: emailList } },
|
|
305
|
+
populate: ["roles"]
|
|
306
|
+
});
|
|
307
|
+
const whitelistService2 = strapi.plugin("strapi-plugin-oidc").service("whitelist");
|
|
308
|
+
let matchedExistingUsersCount = 0;
|
|
309
|
+
for (const singleEmail of emailList) {
|
|
310
|
+
const existingUser = existingUsers.find((u) => u.email === singleEmail);
|
|
311
|
+
let finalRoles = roles2;
|
|
312
|
+
if (existingUser && existingUser.roles) {
|
|
313
|
+
finalRoles = existingUser.roles.map((r) => r.id.toString());
|
|
314
|
+
matchedExistingUsersCount++;
|
|
315
|
+
}
|
|
316
|
+
const alreadyWhitelisted = await strapi.query("plugin::strapi-plugin-oidc.whitelists").findOne({
|
|
317
|
+
where: { email: singleEmail }
|
|
318
|
+
});
|
|
319
|
+
if (!alreadyWhitelisted) {
|
|
320
|
+
await whitelistService2.registerUser(singleEmail, finalRoles);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
ctx.body = { matchedExistingUsersCount };
|
|
324
|
+
}
|
|
325
|
+
async function removeEmail(ctx) {
|
|
326
|
+
const { id } = ctx.params;
|
|
327
|
+
const whitelistService2 = strapi.plugin("strapi-plugin-oidc").service("whitelist");
|
|
328
|
+
await whitelistService2.removeUser(id);
|
|
329
|
+
ctx.body = {};
|
|
330
|
+
}
|
|
331
|
+
async function syncUsers(ctx) {
|
|
332
|
+
const { users } = ctx.request.body;
|
|
333
|
+
const whitelistService2 = strapi.plugin("strapi-plugin-oidc").service("whitelist");
|
|
334
|
+
const currentUsers = await whitelistService2.getUsers();
|
|
335
|
+
let matchedExistingUsersCount = 0;
|
|
336
|
+
const emailsToSync = users.map((u) => u.email);
|
|
337
|
+
const existingStrapiUsers = await strapi.query("admin::user").findMany({
|
|
338
|
+
where: { email: { $in: emailsToSync } },
|
|
339
|
+
populate: ["roles"]
|
|
340
|
+
});
|
|
341
|
+
for (const currUser of currentUsers) {
|
|
342
|
+
if (!users.find((u) => u.email === currUser.email)) {
|
|
343
|
+
await whitelistService2.removeUser(currUser.id);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
for (const user of users) {
|
|
347
|
+
const existingStrapiUser = existingStrapiUsers.find((u) => u.email === user.email);
|
|
348
|
+
let finalRoles = user.roles;
|
|
349
|
+
const currUser = currentUsers.find((u) => u.email === user.email);
|
|
350
|
+
if (!currUser && existingStrapiUser && existingStrapiUser.roles) {
|
|
351
|
+
finalRoles = existingStrapiUser.roles.map((r) => r.id.toString());
|
|
352
|
+
matchedExistingUsersCount++;
|
|
353
|
+
}
|
|
354
|
+
if (currUser) {
|
|
355
|
+
await strapi.query("plugin::strapi-plugin-oidc.whitelists").update({
|
|
356
|
+
where: { id: currUser.id },
|
|
357
|
+
data: { roles: finalRoles }
|
|
358
|
+
});
|
|
359
|
+
} else {
|
|
360
|
+
await whitelistService2.registerUser(user.email, finalRoles);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
ctx.body = { matchedExistingUsersCount };
|
|
364
|
+
}
|
|
365
|
+
const whitelist = {
|
|
366
|
+
info,
|
|
367
|
+
updateSettings,
|
|
368
|
+
publicSettings,
|
|
369
|
+
register,
|
|
370
|
+
removeEmail,
|
|
371
|
+
syncUsers
|
|
372
|
+
};
|
|
373
|
+
const controllers = {
|
|
374
|
+
oidc,
|
|
375
|
+
role,
|
|
376
|
+
whitelist
|
|
377
|
+
};
|
|
378
|
+
const routes = [
|
|
379
|
+
{
|
|
380
|
+
method: "GET",
|
|
381
|
+
path: "/oidc-roles",
|
|
382
|
+
handler: "role.find",
|
|
383
|
+
config: {
|
|
384
|
+
policies: [
|
|
385
|
+
"admin::isAuthenticatedAdmin",
|
|
386
|
+
{ name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.read"] } }
|
|
387
|
+
]
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
method: "PUT",
|
|
392
|
+
path: "/oidc-roles",
|
|
393
|
+
handler: "role.update",
|
|
394
|
+
config: {
|
|
395
|
+
policies: [
|
|
396
|
+
"admin::isAuthenticatedAdmin",
|
|
397
|
+
{ name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.update"] } }
|
|
398
|
+
]
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
method: "GET",
|
|
403
|
+
path: "/oidc",
|
|
404
|
+
handler: "oidc.oidcSignIn",
|
|
405
|
+
config: {
|
|
406
|
+
auth: false
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
method: "GET",
|
|
411
|
+
path: "/oidc/callback",
|
|
412
|
+
handler: "oidc.oidcSignInCallback",
|
|
413
|
+
config: {
|
|
414
|
+
auth: false
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
method: "GET",
|
|
419
|
+
path: "/logout",
|
|
420
|
+
handler: "oidc.logout",
|
|
421
|
+
config: {
|
|
422
|
+
auth: false
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
method: "GET",
|
|
427
|
+
path: "/whitelist",
|
|
428
|
+
handler: "whitelist.info",
|
|
429
|
+
config: {
|
|
430
|
+
policies: [
|
|
431
|
+
"admin::isAuthenticatedAdmin",
|
|
432
|
+
{ name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.read"] } }
|
|
433
|
+
]
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
method: "PUT",
|
|
438
|
+
path: "/whitelist/settings",
|
|
439
|
+
handler: "whitelist.updateSettings",
|
|
440
|
+
config: {
|
|
441
|
+
policies: [
|
|
442
|
+
"admin::isAuthenticatedAdmin",
|
|
443
|
+
{ name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.update"] } }
|
|
444
|
+
]
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
method: "GET",
|
|
449
|
+
path: "/settings/public",
|
|
450
|
+
handler: "whitelist.publicSettings",
|
|
451
|
+
config: {
|
|
452
|
+
auth: false
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
method: "PUT",
|
|
457
|
+
path: "/whitelist/sync",
|
|
458
|
+
handler: "whitelist.syncUsers",
|
|
459
|
+
config: {
|
|
460
|
+
policies: [
|
|
461
|
+
"admin::isAuthenticatedAdmin",
|
|
462
|
+
{ name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.update"] } }
|
|
463
|
+
]
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
method: "POST",
|
|
468
|
+
path: "/whitelist",
|
|
469
|
+
handler: "whitelist.register",
|
|
470
|
+
config: {
|
|
471
|
+
policies: [
|
|
472
|
+
"admin::isAuthenticatedAdmin",
|
|
473
|
+
{ name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.update"] } }
|
|
474
|
+
]
|
|
475
|
+
}
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
method: "DELETE",
|
|
479
|
+
path: "/whitelist/:id",
|
|
480
|
+
handler: "whitelist.removeEmail",
|
|
481
|
+
config: {
|
|
482
|
+
policies: [
|
|
483
|
+
"admin::isAuthenticatedAdmin",
|
|
484
|
+
{ name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.update"] } }
|
|
485
|
+
]
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
];
|
|
489
|
+
const policies = {};
|
|
490
|
+
function oauthService({ strapi: strapi2 }) {
|
|
491
|
+
return {
|
|
492
|
+
async createUser(email, lastname, firstname, locale, roles2 = []) {
|
|
493
|
+
const userService = strapi2.service("admin::user");
|
|
494
|
+
if (/[A-Z]/.test(email)) {
|
|
495
|
+
const dbUser = await userService.findOneByEmail(email.toLocaleLowerCase());
|
|
496
|
+
if (dbUser) {
|
|
497
|
+
return dbUser;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
const createdUser = await userService.create({
|
|
501
|
+
firstname: firstname ? firstname : "unset",
|
|
502
|
+
lastname: lastname ? lastname : "",
|
|
503
|
+
email: email.toLocaleLowerCase(),
|
|
504
|
+
roles: roles2,
|
|
505
|
+
preferedLanguage: locale
|
|
506
|
+
});
|
|
507
|
+
return await userService.register({
|
|
508
|
+
registrationToken: createdUser.registrationToken,
|
|
509
|
+
userInfo: {
|
|
510
|
+
firstname: firstname ? firstname : "unset",
|
|
511
|
+
lastname: lastname ? lastname : "user",
|
|
512
|
+
password: generator__default.default.generate({
|
|
513
|
+
length: 43,
|
|
514
|
+
// 256 bits (https://en.wikipedia.org/wiki/Password_strength#Random_passwords)
|
|
515
|
+
numbers: true,
|
|
516
|
+
lowercase: true,
|
|
517
|
+
uppercase: true,
|
|
518
|
+
exclude: '()+_-=}{[]|:;"/?.><,`~',
|
|
519
|
+
strict: true
|
|
520
|
+
})
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
},
|
|
524
|
+
addGmailAlias(baseEmail, baseAlias) {
|
|
525
|
+
if (!baseAlias) {
|
|
526
|
+
return baseEmail;
|
|
527
|
+
}
|
|
528
|
+
const alias = baseAlias.replace("/+/g", "");
|
|
529
|
+
const beforePosition = baseEmail.indexOf("@");
|
|
530
|
+
const origin = baseEmail.substring(0, beforePosition);
|
|
531
|
+
const domain = baseEmail.substring(beforePosition);
|
|
532
|
+
return `${origin}+${alias}${domain}`;
|
|
533
|
+
},
|
|
534
|
+
localeFindByHeader(headers) {
|
|
535
|
+
if (headers["accept-language"] && headers["accept-language"].includes("ja")) {
|
|
536
|
+
return "ja";
|
|
537
|
+
} else {
|
|
538
|
+
return "en";
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
async triggerWebHook(user) {
|
|
542
|
+
let ENTRY_CREATE;
|
|
543
|
+
const webhookStore = strapi2.serviceMap.get("webhookStore");
|
|
544
|
+
const eventHub = strapi2.serviceMap.get("eventHub");
|
|
545
|
+
if (webhookStore) {
|
|
546
|
+
ENTRY_CREATE = webhookStore.allowedEvents.get("ENTRY_CREATE");
|
|
547
|
+
}
|
|
548
|
+
const modelDef = strapi2.getModel("admin::user");
|
|
549
|
+
const sanitizedEntity = await strapiUtils__default.default.sanitize.sanitizers.defaultSanitizeOutput({
|
|
550
|
+
schema: modelDef,
|
|
551
|
+
getModel: (uid2) => strapi2.getModel(uid2)
|
|
552
|
+
}, user);
|
|
553
|
+
eventHub.emit(ENTRY_CREATE, {
|
|
554
|
+
model: modelDef.modelName,
|
|
555
|
+
entry: sanitizedEntity
|
|
556
|
+
});
|
|
557
|
+
},
|
|
558
|
+
triggerSignInSuccess(user) {
|
|
559
|
+
delete user["password"];
|
|
560
|
+
const eventHub = strapi2.serviceMap.get("eventHub");
|
|
561
|
+
eventHub.emit("admin.auth.success", {
|
|
562
|
+
user,
|
|
563
|
+
provider: "strapi-plugin-oidc"
|
|
564
|
+
});
|
|
565
|
+
},
|
|
566
|
+
// Sign In Success
|
|
567
|
+
renderSignUpSuccess(jwtToken, user, nonce) {
|
|
568
|
+
const config2 = strapi2.config.get("plugin::strapi-plugin-oidc");
|
|
569
|
+
const REMEMBER_ME = config2["REMEMBER_ME"];
|
|
570
|
+
const isRememberMe = !!REMEMBER_ME;
|
|
571
|
+
return `
|
|
572
|
+
<!doctype html>
|
|
573
|
+
<html>
|
|
574
|
+
<head>
|
|
575
|
+
<noscript>
|
|
576
|
+
<h3>JavaScript must be enabled for authentication</h3>
|
|
577
|
+
</noscript>
|
|
578
|
+
<script nonce="${nonce}">
|
|
579
|
+
window.addEventListener('load', function() {
|
|
580
|
+
if(${isRememberMe}){
|
|
581
|
+
localStorage.setItem('jwtToken', '"${jwtToken}"');
|
|
582
|
+
}else{
|
|
583
|
+
document.cookie = 'jwtToken=${encodeURIComponent(jwtToken)}; Path=/';
|
|
584
|
+
}
|
|
585
|
+
localStorage.setItem('isLoggedIn', 'true');
|
|
586
|
+
location.href = '${strapi2.config.admin.url}'
|
|
587
|
+
})
|
|
588
|
+
<\/script>
|
|
589
|
+
</head>
|
|
590
|
+
<body>
|
|
591
|
+
</body>
|
|
592
|
+
</html>`;
|
|
593
|
+
},
|
|
594
|
+
// Sign In Error
|
|
595
|
+
renderSignUpError(message) {
|
|
596
|
+
return `
|
|
597
|
+
<!doctype html>
|
|
598
|
+
<html>
|
|
599
|
+
<head></head>
|
|
600
|
+
<body>
|
|
601
|
+
<h3>Authentication failed</h3>
|
|
602
|
+
<p>${message}</p>
|
|
603
|
+
</body>
|
|
604
|
+
</html>`;
|
|
605
|
+
},
|
|
606
|
+
async generateToken(user, ctx) {
|
|
607
|
+
const sessionManager = strapi2.sessionManager;
|
|
608
|
+
if (!sessionManager) {
|
|
609
|
+
throw new Error("sessionManager is not supported. Please upgrade to Strapi v5.24.1 or later.");
|
|
610
|
+
}
|
|
611
|
+
const userId = String(user.id);
|
|
612
|
+
const deviceId = node_crypto.randomUUID();
|
|
613
|
+
const config2 = strapi2.config.get("plugin::strapi-plugin-oidc");
|
|
614
|
+
const REMEMBER_ME = config2["REMEMBER_ME"];
|
|
615
|
+
const rememberMe = !!REMEMBER_ME;
|
|
616
|
+
const { token: refreshToken } = await sessionManager(
|
|
617
|
+
"admin"
|
|
618
|
+
).generateRefreshToken(userId, deviceId, {
|
|
619
|
+
type: rememberMe ? "refresh" : "session"
|
|
620
|
+
});
|
|
621
|
+
const cookieOptions = {};
|
|
622
|
+
ctx.cookies.set("strapi_admin_refresh", refreshToken, cookieOptions);
|
|
623
|
+
const accessResult = await sessionManager("admin").generateAccessToken(refreshToken);
|
|
624
|
+
if ("error" in accessResult) {
|
|
625
|
+
throw new Error(accessResult.error);
|
|
626
|
+
}
|
|
627
|
+
const { token: accessToken } = accessResult;
|
|
628
|
+
return accessToken;
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
function roleService({ strapi: strapi2 }) {
|
|
633
|
+
return {
|
|
634
|
+
OIDC_TYPE: "4",
|
|
635
|
+
getOidcRoles() {
|
|
636
|
+
return [
|
|
637
|
+
{
|
|
638
|
+
"oauth_type": this.OIDC_TYPE,
|
|
639
|
+
name: "OIDC"
|
|
640
|
+
}
|
|
641
|
+
];
|
|
642
|
+
},
|
|
643
|
+
async oidcRoles() {
|
|
644
|
+
return await strapi2.query("plugin::strapi-plugin-oidc.roles").findOne({
|
|
645
|
+
where: {
|
|
646
|
+
"oauth_type": this.OIDC_TYPE
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
},
|
|
650
|
+
async find() {
|
|
651
|
+
return await strapi2.query("plugin::strapi-plugin-oidc.roles").findMany();
|
|
652
|
+
},
|
|
653
|
+
async update(roles2) {
|
|
654
|
+
const query = strapi2.query("plugin::strapi-plugin-oidc.roles");
|
|
655
|
+
await Promise.all(
|
|
656
|
+
roles2.map(async (role2) => {
|
|
657
|
+
const oidcRole = await query.findOne({ where: { "oauth_type": role2["oauth_type"] } });
|
|
658
|
+
if (oidcRole) {
|
|
659
|
+
await query.update({
|
|
660
|
+
where: { "oauth_type": role2["oauth_type"] },
|
|
661
|
+
data: { roles: role2.role }
|
|
662
|
+
});
|
|
663
|
+
} else {
|
|
664
|
+
await query.create({
|
|
665
|
+
data: {
|
|
666
|
+
"oauth_type": role2["oauth_type"],
|
|
667
|
+
roles: role2.role
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
})
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
function whitelistService({ strapi: strapi2 }) {
|
|
677
|
+
return {
|
|
678
|
+
async getSettings() {
|
|
679
|
+
const pluginStore = strapi2.store({ type: "plugin", name: "strapi-plugin-oidc" });
|
|
680
|
+
let settings = await pluginStore.get({ key: "settings" });
|
|
681
|
+
if (!settings) {
|
|
682
|
+
settings = { useWhitelist: true, enforceOIDC: false };
|
|
683
|
+
await pluginStore.set({ key: "settings", value: settings });
|
|
684
|
+
}
|
|
685
|
+
return settings;
|
|
686
|
+
},
|
|
687
|
+
async setSettings(settings) {
|
|
688
|
+
const pluginStore = strapi2.store({ type: "plugin", name: "strapi-plugin-oidc" });
|
|
689
|
+
await pluginStore.set({ key: "settings", value: settings });
|
|
690
|
+
},
|
|
691
|
+
async getUsers() {
|
|
692
|
+
const query = strapi2.query("plugin::strapi-plugin-oidc.whitelists");
|
|
693
|
+
return await query.findMany();
|
|
694
|
+
},
|
|
695
|
+
async registerUser(email, roles2) {
|
|
696
|
+
const query = strapi2.query("plugin::strapi-plugin-oidc.whitelists");
|
|
697
|
+
await query.create({
|
|
698
|
+
data: {
|
|
699
|
+
email,
|
|
700
|
+
roles: roles2
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
},
|
|
704
|
+
async removeUser(id) {
|
|
705
|
+
const query = strapi2.query("plugin::strapi-plugin-oidc.whitelists");
|
|
706
|
+
await query.delete({
|
|
707
|
+
where: {
|
|
708
|
+
id
|
|
709
|
+
}
|
|
710
|
+
});
|
|
711
|
+
},
|
|
712
|
+
async checkWhitelistForEmail(email) {
|
|
713
|
+
const settings = await this.getSettings();
|
|
714
|
+
if (!settings.useWhitelist) {
|
|
715
|
+
return null;
|
|
716
|
+
}
|
|
717
|
+
const query = strapi2.query("plugin::strapi-plugin-oidc.whitelists");
|
|
718
|
+
const result = await query.findOne({
|
|
719
|
+
where: {
|
|
720
|
+
email
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
if (result === null) {
|
|
724
|
+
throw new Error("Not present in whitelist");
|
|
725
|
+
}
|
|
726
|
+
return result;
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
const services = {
|
|
731
|
+
oauth: oauthService,
|
|
732
|
+
role: roleService,
|
|
733
|
+
whitelist: whitelistService
|
|
734
|
+
};
|
|
735
|
+
const index = {
|
|
736
|
+
register: register$1,
|
|
737
|
+
bootstrap,
|
|
738
|
+
destroy,
|
|
739
|
+
config,
|
|
740
|
+
controllers,
|
|
741
|
+
routes,
|
|
742
|
+
services,
|
|
743
|
+
contentTypes,
|
|
744
|
+
policies
|
|
745
|
+
};
|
|
746
|
+
exports.default = index;
|