merge newui branch
This commit is contained in:
234
ui/src/collections/oauth2/oidcOptions.js
Normal file
234
ui/src/collections/oauth2/oidcOptions.js
Normal file
@@ -0,0 +1,234 @@
|
||||
window.app = window.app || {};
|
||||
window.app.oauth2 = window.app.oauth2 || {};
|
||||
|
||||
// note: data is the providerSettingsModal form store
|
||||
window.app.oauth2.oidc = function(providerInfo, namePrefix, data) {
|
||||
const uniqueId = "oidc_" + app.utils.randomString();
|
||||
|
||||
const userInfoOptions = [
|
||||
{ label: "User info URL", value: true },
|
||||
{ label: "ID Token", value: false },
|
||||
];
|
||||
|
||||
const local = store({
|
||||
useUserInfoUrl: false,
|
||||
});
|
||||
|
||||
const watchers = [];
|
||||
|
||||
return t.div(
|
||||
{
|
||||
pbEvent: "oauth2OIDCOptions",
|
||||
className: "oauth2-oidc-options",
|
||||
// init defaults
|
||||
onmount: (el) => {
|
||||
if (typeof data.config.displayName == "undefined") {
|
||||
data.config.displayName = "OIDC";
|
||||
}
|
||||
|
||||
if (typeof data.config.pkce == "undefined") {
|
||||
data.config.pkce = true;
|
||||
}
|
||||
|
||||
if (data.config.userInfoURL || !data.config.extra) {
|
||||
local.useUserInfoUrl = true;
|
||||
}
|
||||
|
||||
// unset the id_token or info url fields based on the toggle state
|
||||
watchers.push(
|
||||
watch(() => local.useUserInfoUrl, (useURL, oldUseURL) => {
|
||||
if (useURL) {
|
||||
// note: null because {} will just result in JSON unmarshal merge with the existing data
|
||||
data.config.extra = null;
|
||||
} else {
|
||||
data.config.userInfoURL = "";
|
||||
// note: fallback to empty object to distinguish from the null state since all id_token fields are optional
|
||||
data.config.extra = data.config.extra || {};
|
||||
}
|
||||
}),
|
||||
);
|
||||
},
|
||||
onunmount: () => {
|
||||
watchers.forEach((w) => w?.unwatch());
|
||||
},
|
||||
},
|
||||
t.div(
|
||||
{ className: "grid" },
|
||||
t.div(
|
||||
{ className: "col-12" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label({ htmlFor: uniqueId + ".displayName" }, "Display name"),
|
||||
t.input({
|
||||
id: uniqueId + ".displayName",
|
||||
name: namePrefix + ".displayName",
|
||||
type: "text",
|
||||
required: true,
|
||||
value: () => data.config.displayName || "",
|
||||
oninput: (e) => data.config.displayName = e.target.value,
|
||||
}),
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-12" },
|
||||
t.p({ className: "txt-bold" }, "Endpoints"),
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label({ htmlFor: uniqueId + ".authURL" }, "Auth URL"),
|
||||
t.input({
|
||||
id: uniqueId + ".authURL",
|
||||
name: namePrefix + ".authURL",
|
||||
type: "url",
|
||||
required: true,
|
||||
value: () => data.config.authURL || "",
|
||||
oninput: (e) => data.config.authURL = e.target.value,
|
||||
}),
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-12" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label({ htmlFor: uniqueId + ".tokenURL" }, "Token URL"),
|
||||
t.input({
|
||||
id: uniqueId + ".tokenURL",
|
||||
name: namePrefix + ".tokenURL",
|
||||
type: "url",
|
||||
required: true,
|
||||
value: () => data.config.tokenURL || "",
|
||||
oninput: (e) => data.config.tokenURL = e.target.value,
|
||||
}),
|
||||
),
|
||||
),
|
||||
// User info
|
||||
t.div(
|
||||
{ className: "col-12" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label({ htmlFor: uniqueId + ".userInfoSelect" }, "Fetch user info from"),
|
||||
app.components.select({
|
||||
id: uniqueId + ".userInfoSelect",
|
||||
required: true,
|
||||
options: userInfoOptions,
|
||||
value: () => local.useUserInfoUrl,
|
||||
onchange: (selectedOpts) => local.useUserInfoUrl = selectedOpts?.[0]?.value,
|
||||
}),
|
||||
),
|
||||
t.div({ className: "oidc-userinfo-options m-t-10" }, () => {
|
||||
if (local.useUserInfoUrl) {
|
||||
return t.div(
|
||||
{ className: "field" },
|
||||
t.label({ htmlFor: uniqueId + ".userInfoURL" }, "User info URL"),
|
||||
t.input({
|
||||
id: uniqueId + ".userInfoURL",
|
||||
name: namePrefix + ".userInfoURL",
|
||||
type: "url",
|
||||
required: true,
|
||||
value: () => data.config.userInfoURL || "",
|
||||
oninput: (e) => data.config.userInfoURL = e.target.value,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return t.div(
|
||||
{ className: "grid sm" },
|
||||
t.div(
|
||||
{ className: "col-12 txt-hint txt-sm" },
|
||||
t.em(
|
||||
null,
|
||||
"Both fields are considered optional because the parsed ",
|
||||
t.code(null, "id_token"),
|
||||
" is a direct result of the TLS code->token exchange server response.",
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-12" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label(
|
||||
{ htmlFor: uniqueId + ".extra.jwksURL" },
|
||||
t.span({ className: "txt" }, "JWKS verification URL"),
|
||||
t.i({
|
||||
ariaHidden: true,
|
||||
className: "ri-information-line link-hint",
|
||||
ariaDescription: app.attrs.tooltip(
|
||||
"URL to the public token verification keys.",
|
||||
),
|
||||
}),
|
||||
),
|
||||
t.input({
|
||||
id: uniqueId + ".extra.jwksURL",
|
||||
name: namePrefix + ".extra.jwksURL",
|
||||
type: "url",
|
||||
value: () => data.config.extra?.jwksURL || "",
|
||||
oninput: (e) => {
|
||||
data.config.extra = data.config.extra || {};
|
||||
data.config.extra.jwksURL = e.target.value;
|
||||
},
|
||||
}),
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-12" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label(
|
||||
{ htmlFor: uniqueId + ".extra.issuers" },
|
||||
t.span({ className: "txt" }, "Issuers"),
|
||||
t.i({
|
||||
ariaHidden: true,
|
||||
className: "ri-information-line link-hint",
|
||||
ariaDescription: app.attrs.tooltip(
|
||||
"Comma separated list of accepted values for the iss token claim validation.",
|
||||
),
|
||||
}),
|
||||
),
|
||||
t.input({
|
||||
id: uniqueId + ".extra.issuers",
|
||||
name: namePrefix + ".extra.issuers",
|
||||
type: "text",
|
||||
value: () => app.utils.joinNonEmpty(data.config.extra?.issuers),
|
||||
oninput: (e) => {
|
||||
const newValue = app.utils.splitNonEmpty(e.target.value, ",");
|
||||
const newStr = app.utils.joinNonEmpty(newValue);
|
||||
const oldStr = app.utils.joinNonEmpty(data.config.extra?.issuers);
|
||||
|
||||
// has an actual change
|
||||
if (oldStr != newStr) {
|
||||
data.config.extra = data.config.extra || {};
|
||||
data.config.extra.issuers = newValue;
|
||||
}
|
||||
},
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-12" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.input({
|
||||
id: uniqueId + ".pkce",
|
||||
name: namePrefix + ".pkce",
|
||||
type: "checkbox",
|
||||
checked: () => data.config.pkce || false,
|
||||
onchange: (e) => data.config.pkce = e.target.checked,
|
||||
}),
|
||||
t.label(
|
||||
{ htmlFor: uniqueId + ".pkce" },
|
||||
t.span({ className: "txt", textContent: "Support PKCE" }),
|
||||
t.i({
|
||||
className: "ri-information-line link-hint",
|
||||
ariaHidden: true,
|
||||
ariaDescription: app.attrs.tooltip(
|
||||
"Usually it should be safe to be always enabled as most providers will just ignore the extra query parameters if they don't support PKCE.",
|
||||
),
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user