@camstack/addon-auth 1.2.130 → 1.2.132
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/dist/{hub-browser-origin-B1o5vmQX.mjs → dist-DbaYwR-N.mjs} +2664 -525
- package/dist/{hub-browser-origin-C-u2l9VC.js → dist-DjCeMP9o.js} +2665 -526
- package/dist/hub-browser-origin-DohQUFPz.js +16 -0
- package/dist/hub-browser-origin-LBBO5r05.mjs +11 -0
- package/dist/magic-link/auth-magic-link.addon.js +132 -33
- package/dist/magic-link/auth-magic-link.addon.mjs +124 -25
- package/dist/oidc/auth-oidc.addon.js +213 -44
- package/dist/oidc/auth-oidc.addon.mjs +205 -36
- package/dist/webauthn/_stub.js +1 -1
- package/dist/webauthn/{_virtual_mf-localSharedImportMap___mfe_internal__addon_auth_webauthn_widgets-v7lvfZM3.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_auth_webauthn_widgets-Cy2WCjhX.mjs} +3 -3
- package/dist/webauthn/_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DBsbNmPW.mjs +26 -0
- package/dist/webauthn/auth-webauthn.addon.js +13 -12
- package/dist/webauthn/auth-webauthn.addon.mjs +2 -1
- package/dist/webauthn/{hostInit-DEFeGgRf.mjs → hostInit-3W0iPRJ_.mjs} +3 -3
- package/dist/webauthn/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/webauthn/_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Bifweq9M.mjs +0 -26
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-Cek0wNdY.js");
|
|
6
|
-
const
|
|
6
|
+
const require_dist = require("../dist-DjCeMP9o.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
9
9
|
//#region ../../node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
@@ -705,6 +705,82 @@ function createRemoteJWKSet(url, options) {
|
|
|
705
705
|
});
|
|
706
706
|
}
|
|
707
707
|
//#endregion
|
|
708
|
+
//#region src/oidc/request-origin.ts
|
|
709
|
+
/** host[:port] — a DNS name, IPv4 or bracketed IPv6. No userinfo, path or spaces. */
|
|
710
|
+
var AUTHORITY_RE = /^(?:[a-z0-9.-]+|\[[0-9a-f:.]+\])(?::\d{1,5})?$/i;
|
|
711
|
+
/** Same grammar as the hub's `parseForwardedPrefix` (spa-mount.ts). */
|
|
712
|
+
var PREFIX_RE = /^\/[A-Za-z0-9_\-.]+(?:\/[A-Za-z0-9_\-.]+)*$/;
|
|
713
|
+
var MAX_PREFIX_LENGTH = 512;
|
|
714
|
+
/** First value of a possibly comma-joined forwarded header (the client-most proxy). */
|
|
715
|
+
function firstValue(value) {
|
|
716
|
+
if (value === void 0) return null;
|
|
717
|
+
const first = value.split(",")[0]?.trim() ?? "";
|
|
718
|
+
return first.length === 0 ? null : first;
|
|
719
|
+
}
|
|
720
|
+
/** `scheme://host[:port]` normalised by WHATWG URL, or `null` if it is not an http(s) origin. */
|
|
721
|
+
function normalizeOrigin(value) {
|
|
722
|
+
try {
|
|
723
|
+
const url = new URL(value);
|
|
724
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") return null;
|
|
725
|
+
if (url.username !== "" || url.password !== "") return null;
|
|
726
|
+
return url.origin;
|
|
727
|
+
} catch {
|
|
728
|
+
return null;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
/** The mount prefix the relay named (no trailing slash), or `''`. Invalid = absent. */
|
|
732
|
+
function requestMountPrefix(headers) {
|
|
733
|
+
const raw = headers["x-forwarded-prefix"];
|
|
734
|
+
if (raw === void 0 || raw.length === 0 || raw.length > MAX_PREFIX_LENGTH) return "";
|
|
735
|
+
const trimmed = raw.endsWith("/") ? raw.slice(0, -1) : raw;
|
|
736
|
+
if (trimmed === "" || !PREFIX_RE.test(trimmed)) return "";
|
|
737
|
+
if (trimmed.split("/").some((segment) => segment === ".." || segment === ".")) return "";
|
|
738
|
+
return trimmed;
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* The origins the request CLAIMS, most specific first: the proxy's
|
|
742
|
+
* `X-Forwarded-Host` over `Host`; the named `X-Forwarded-Proto`, or https
|
|
743
|
+
* then http when none is named (the hub terminates TLS itself on 4443).
|
|
744
|
+
*/
|
|
745
|
+
function claimedRequestOrigins(headers) {
|
|
746
|
+
const authority = firstValue(headers["x-forwarded-host"]) ?? firstValue(headers["host"]);
|
|
747
|
+
if (authority === null || !AUTHORITY_RE.test(authority)) return [];
|
|
748
|
+
const proto = firstValue(headers["x-forwarded-proto"])?.toLowerCase() ?? null;
|
|
749
|
+
const schemes = proto === "https" || proto === "http" ? [proto] : proto === null ? ["https", "http"] : [];
|
|
750
|
+
const out = [];
|
|
751
|
+
for (const scheme of schemes) {
|
|
752
|
+
const origin = normalizeOrigin(`${scheme}://${authority}`);
|
|
753
|
+
if (origin !== null) out.push(origin);
|
|
754
|
+
}
|
|
755
|
+
return out;
|
|
756
|
+
}
|
|
757
|
+
/** Every origin the hub advertises itself at, normalised. Never the app link, never loopback. */
|
|
758
|
+
function advertisedHubOrigins(book) {
|
|
759
|
+
const candidates = [];
|
|
760
|
+
for (const row of book.rows) {
|
|
761
|
+
if (row.kind === "app-link" || row.kind === "loopback") continue;
|
|
762
|
+
candidates.push(row.baseUrl);
|
|
763
|
+
}
|
|
764
|
+
const { publicEndpoint, internal, appConnections } = book.roles;
|
|
765
|
+
if (publicEndpoint.resolved !== null) candidates.push(publicEndpoint.resolved);
|
|
766
|
+
if (internal.resolved !== null) candidates.push(internal.resolved);
|
|
767
|
+
candidates.push(...appConnections.resolved);
|
|
768
|
+
const out = /* @__PURE__ */ new Set();
|
|
769
|
+
for (const candidate of candidates) {
|
|
770
|
+
const origin = normalizeOrigin(candidate);
|
|
771
|
+
if (origin !== null) out.add(origin);
|
|
772
|
+
}
|
|
773
|
+
return out;
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* The origin to send the browser back to: the first claimed origin that is in
|
|
777
|
+
* `allowed`, or `null` (the caller then uses its default address).
|
|
778
|
+
*/
|
|
779
|
+
function pickRequestOrigin(headers, allowed) {
|
|
780
|
+
for (const origin of claimedRequestOrigins(headers)) if (allowed.has(origin)) return origin;
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
//#endregion
|
|
708
784
|
//#region src/oidc/auth-oidc.addon.ts
|
|
709
785
|
/**
|
|
710
786
|
* Generic OpenID Connect (OIDC) authentication provider.
|
|
@@ -733,9 +809,14 @@ function createRemoteJWKSet(url, options) {
|
|
|
733
809
|
* — the hub verifies it with the same `jwtSecret` and only then mints
|
|
734
810
|
* the user session JWT.
|
|
735
811
|
*
|
|
812
|
+
* Identity mapping is EXPLICIT LINKING only (D782): the bridge names the
|
|
813
|
+
* identity `oidc:<instance>:<sub>`; the hub signs in the user that identity
|
|
814
|
+
* was linked to, and refuses an unlinked one. A flow started by a signed-in
|
|
815
|
+
* user's "Link" button carries the hub's opaque `?link=` handle through the
|
|
816
|
+
* pending state into the bridge (`linkIntent`); the hub resolves it.
|
|
817
|
+
*
|
|
736
818
|
* TODO (next session):
|
|
737
819
|
* - RP-initiated logout (`end_session_endpoint` 302 with id_token_hint).
|
|
738
|
-
* - Groups → scope mapping via id_token `groups` claim.
|
|
739
820
|
* - Refresh token rotation (offline_access).
|
|
740
821
|
* - Persist state + nonce + PKCE across restart (multi-replica).
|
|
741
822
|
*/
|
|
@@ -748,12 +829,38 @@ var DEFAULT_PROVIDER = {
|
|
|
748
829
|
clientSecret: "",
|
|
749
830
|
redirectUri: "",
|
|
750
831
|
scopes: "openid profile email",
|
|
751
|
-
usernameClaim: "preferred_username"
|
|
752
|
-
defaultRole: "viewer"
|
|
832
|
+
usernameClaim: "preferred_username"
|
|
753
833
|
};
|
|
754
834
|
var DEFAULT_CONFIG = { providers: [] };
|
|
755
835
|
var STATE_TTL_MS = 5 * 6e4;
|
|
756
|
-
|
|
836
|
+
/**
|
|
837
|
+
* Shape of a hub link-intent handle (`?link=` on /start). Opaque to this
|
|
838
|
+
* addon — the hub resolves it, single-use, at the SSO finish. Validated only
|
|
839
|
+
* so a junk value is refused here rather than carried into a signed bridge.
|
|
840
|
+
*/
|
|
841
|
+
var LINK_INTENT_PATTERN = /^[A-Za-z0-9_-]{16,128}$/;
|
|
842
|
+
/**
|
|
843
|
+
* An instance id appears in URLs and in the identity `oidc:<id>:<sub>`; a `:`
|
|
844
|
+
* would make two identities read the same, so ids are slugs. A configured row
|
|
845
|
+
* whose id is not one is skipped.
|
|
846
|
+
*/
|
|
847
|
+
var INSTANCE_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
848
|
+
/** Bound on in-flight logins: `/start` is public, so a flood must not grow the map. */
|
|
849
|
+
var MAX_PENDING_STATES = 1e3;
|
|
850
|
+
/**
|
|
851
|
+
* Origin + mount prefix of a pinned `redirect_uri`: the part before the
|
|
852
|
+
* callback path when it ends with it, else just its origin.
|
|
853
|
+
*/
|
|
854
|
+
function returnBaseOf(redirectUri, callbackPath) {
|
|
855
|
+
try {
|
|
856
|
+
const url = new URL(redirectUri);
|
|
857
|
+
const prefix = url.pathname.endsWith(callbackPath) ? url.pathname.slice(0, -callbackPath.length) : "";
|
|
858
|
+
return `${url.origin}${prefix.replace(/\/+$/, "")}`;
|
|
859
|
+
} catch {
|
|
860
|
+
return "";
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
var AuthOidcAddon = class extends require_dist.BaseAddon {
|
|
757
864
|
/** Per-provider runtime state, keyed by `provider.id`. */
|
|
758
865
|
instances = /* @__PURE__ */ new Map();
|
|
759
866
|
/** Pending OAuth states across ALL providers. The pending entry
|
|
@@ -779,7 +886,7 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
779
886
|
return this.handleCallback(code, state);
|
|
780
887
|
}
|
|
781
888
|
};
|
|
782
|
-
const routeProvider =
|
|
889
|
+
const routeProvider = require_dist.buildAddonRouteProvider("auth-oidc", [{
|
|
783
890
|
method: "GET",
|
|
784
891
|
path: "/:providerId/start",
|
|
785
892
|
access: "public",
|
|
@@ -796,15 +903,15 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
796
903
|
this.ctx.logger.info("OIDC auth provider initialized", { meta: { providers: [...this.instances.keys()] } });
|
|
797
904
|
return [
|
|
798
905
|
{
|
|
799
|
-
capability:
|
|
906
|
+
capability: require_dist.authProviderCapability,
|
|
800
907
|
provider: authProvider
|
|
801
908
|
},
|
|
802
909
|
{
|
|
803
|
-
capability:
|
|
910
|
+
capability: require_dist.addonRoutesCapability,
|
|
804
911
|
provider: routeProvider
|
|
805
912
|
},
|
|
806
913
|
{
|
|
807
|
-
capability:
|
|
914
|
+
capability: require_dist.loginMethodCapability,
|
|
808
915
|
provider: loginMethodProvider
|
|
809
916
|
}
|
|
810
917
|
];
|
|
@@ -822,9 +929,10 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
822
929
|
kind: "redirect",
|
|
823
930
|
id: `auth-oidc/${id}`,
|
|
824
931
|
label: inst.config.displayName || DEFAULT_PROVIDER.displayName,
|
|
825
|
-
icon: inst.config.icon
|
|
932
|
+
icon: require_dist.isDisplayIconKey(inst.config.icon) ? inst.config.icon : DEFAULT_PROVIDER.icon,
|
|
826
933
|
startUrl: `/addon/auth-oidc/${id}/start`,
|
|
827
|
-
stage: "primary"
|
|
934
|
+
stage: "primary",
|
|
935
|
+
linkable: true
|
|
828
936
|
});
|
|
829
937
|
}
|
|
830
938
|
return out;
|
|
@@ -857,11 +965,11 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
857
965
|
default: "OpenID Connect"
|
|
858
966
|
},
|
|
859
967
|
{
|
|
860
|
-
type: "
|
|
968
|
+
type: "icon",
|
|
861
969
|
key: "icon",
|
|
862
970
|
label: "Icon",
|
|
863
|
-
description: "
|
|
864
|
-
default:
|
|
971
|
+
description: "Shown on the login button.",
|
|
972
|
+
default: DEFAULT_PROVIDER.icon
|
|
865
973
|
},
|
|
866
974
|
{
|
|
867
975
|
type: "text",
|
|
@@ -877,7 +985,7 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
877
985
|
default: ""
|
|
878
986
|
},
|
|
879
987
|
{
|
|
880
|
-
type: "
|
|
988
|
+
type: "password",
|
|
881
989
|
key: "clientSecret",
|
|
882
990
|
label: "Client Secret",
|
|
883
991
|
default: ""
|
|
@@ -886,7 +994,7 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
886
994
|
type: "text",
|
|
887
995
|
key: "redirectUri",
|
|
888
996
|
label: "Redirect URI override",
|
|
889
|
-
description: "Optional.
|
|
997
|
+
description: "Optional — leave empty. Empty: a sign-in returns to the hub address it was started from (LAN, mesh or public, as listed on the Network page), so register one callback per address you sign in from at the IdP. Set: it PINS that one callback — every sign-in returns to its address, wherever it started.",
|
|
890
998
|
default: ""
|
|
891
999
|
},
|
|
892
1000
|
{
|
|
@@ -915,20 +1023,6 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
915
1023
|
label: "sub (user id)"
|
|
916
1024
|
}
|
|
917
1025
|
]
|
|
918
|
-
},
|
|
919
|
-
{
|
|
920
|
-
type: "select",
|
|
921
|
-
key: "defaultRole",
|
|
922
|
-
label: "Default role",
|
|
923
|
-
description: "Role assigned to first-time SSO users.",
|
|
924
|
-
default: "viewer",
|
|
925
|
-
options: [{
|
|
926
|
-
value: "viewer",
|
|
927
|
-
label: "Viewer"
|
|
928
|
-
}, {
|
|
929
|
-
value: "admin",
|
|
930
|
-
label: "Admin"
|
|
931
|
-
}]
|
|
932
1026
|
}
|
|
933
1027
|
]
|
|
934
1028
|
})]
|
|
@@ -942,7 +1036,10 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
942
1036
|
...DEFAULT_PROVIDER,
|
|
943
1037
|
...raw
|
|
944
1038
|
};
|
|
945
|
-
if (!merged.id || !merged.id
|
|
1039
|
+
if (!merged.id || !INSTANCE_ID_PATTERN.test(merged.id)) {
|
|
1040
|
+
if (merged.id) this.ctx.logger.warn("OIDC: provider instance skipped — id must be a lowercase slug", { meta: { id: merged.id } });
|
|
1041
|
+
continue;
|
|
1042
|
+
}
|
|
946
1043
|
this.instances.set(merged.id, {
|
|
947
1044
|
config: merged,
|
|
948
1045
|
discovery: null,
|
|
@@ -975,28 +1072,75 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
975
1072
|
}
|
|
976
1073
|
return doc;
|
|
977
1074
|
}
|
|
978
|
-
|
|
1075
|
+
/** The hub's Network-page address book, or `null` when `local-network` is unreachable. */
|
|
1076
|
+
async addressBook() {
|
|
1077
|
+
try {
|
|
1078
|
+
return await this.ctx.api.localNetwork.getAddresses.query({ scheme: "https" });
|
|
1079
|
+
} catch (err) {
|
|
1080
|
+
this.ctx.logger.warn("OIDC: hub addresses unavailable from local-network", { meta: { error: require_dist.errMsg(err) } });
|
|
1081
|
+
return null;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* The `redirect_uri` of one sign-in, and the base the browser returns to
|
|
1086
|
+
* after the callback (D791). Precedence:
|
|
1087
|
+
*
|
|
1088
|
+
* 1. The instance's "Redirect URI override", when set: it PINS one origin —
|
|
1089
|
+
* every sign-in returns there, wherever it started.
|
|
1090
|
+
* 2. The origin the `/start` request was made at (Host / X-Forwarded-Host /
|
|
1091
|
+
* -Proto + mount prefix), ONLY when the hub advertises that origin
|
|
1092
|
+
* (`request-origin.ts`) — a forged Host never reaches the IdP.
|
|
1093
|
+
* 3. The Network page's public endpoint (`roles.publicEndpoint`), else the
|
|
1094
|
+
* development default.
|
|
1095
|
+
*/
|
|
1096
|
+
async resolveRedirect(providerId, headers) {
|
|
979
1097
|
const inst = this.instances.get(providerId);
|
|
980
1098
|
if (!inst) throw new Error(`OIDC: no provider configured with id "${providerId}"`);
|
|
1099
|
+
const callbackPath = `/addon/auth-oidc/${providerId}/callback`;
|
|
981
1100
|
const configured = inst.config.redirectUri?.trim();
|
|
982
|
-
if (configured) return
|
|
983
|
-
|
|
1101
|
+
if (configured) return {
|
|
1102
|
+
redirectUri: configured,
|
|
1103
|
+
returnBase: returnBaseOf(configured, callbackPath)
|
|
1104
|
+
};
|
|
1105
|
+
const book = await this.addressBook();
|
|
1106
|
+
const fromRequest = headers !== null && book !== null ? pickRequestOrigin(headers, advertisedHubOrigins(book)) : null;
|
|
1107
|
+
if (fromRequest !== null) {
|
|
1108
|
+
const base = `${fromRequest}${requestMountPrefix(headers ?? {})}`;
|
|
1109
|
+
return {
|
|
1110
|
+
redirectUri: `${base}${callbackPath}`,
|
|
1111
|
+
returnBase: base
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
const fallback = (book !== null ? normalizeOrigin(book.roles.publicEndpoint.resolved ?? "") : null) ?? "https://localhost:4443";
|
|
1115
|
+
return {
|
|
1116
|
+
redirectUri: `${fallback}${callbackPath}`,
|
|
1117
|
+
returnBase: fallback
|
|
1118
|
+
};
|
|
984
1119
|
}
|
|
985
|
-
async buildLoginUrl(providerId, state) {
|
|
1120
|
+
async buildLoginUrl(providerId, state, options = {}) {
|
|
1121
|
+
const { linkIntent } = options;
|
|
986
1122
|
const inst = this.instances.get(providerId);
|
|
987
1123
|
if (!inst) throw new Error(`OIDC: no provider configured with id "${providerId}"`);
|
|
988
1124
|
const doc = await this.getDiscovery(providerId);
|
|
989
1125
|
const codeVerifier = node_crypto.randomBytes(32).toString("base64url");
|
|
990
1126
|
const codeChallenge = node_crypto.createHash("sha256").update(codeVerifier).digest("base64url");
|
|
991
1127
|
const nonce = node_crypto.randomBytes(16).toString("base64url");
|
|
992
|
-
const redirectUri = await this.
|
|
1128
|
+
const { redirectUri, returnBase } = await this.resolveRedirect(providerId, options.headers ?? null);
|
|
993
1129
|
this.pruneExpiredStates();
|
|
1130
|
+
while (this.pendingStates.size >= MAX_PENDING_STATES) {
|
|
1131
|
+
const oldest = this.pendingStates.keys().next();
|
|
1132
|
+
if (oldest.done) break;
|
|
1133
|
+
this.pendingStates.delete(oldest.value);
|
|
1134
|
+
}
|
|
994
1135
|
this.pendingStates.set(state, {
|
|
995
1136
|
codeVerifier,
|
|
996
1137
|
nonce,
|
|
997
1138
|
providerId,
|
|
998
1139
|
redirectUri,
|
|
999
|
-
|
|
1140
|
+
returnBase,
|
|
1141
|
+
popup: options.popup === true,
|
|
1142
|
+
createdAt: Date.now(),
|
|
1143
|
+
...linkIntent !== void 0 ? { linkIntent } : {}
|
|
1000
1144
|
});
|
|
1001
1145
|
const params = new URLSearchParams({
|
|
1002
1146
|
response_type: "code",
|
|
@@ -1051,7 +1195,7 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
1051
1195
|
audience: inst.config.clientId
|
|
1052
1196
|
})).payload;
|
|
1053
1197
|
} catch (err) {
|
|
1054
|
-
throw new Error(`OIDC id_token verification failed: ${
|
|
1198
|
+
throw new Error(`OIDC id_token verification failed: ${require_dist.errMsg(err)}`, { cause: err });
|
|
1055
1199
|
}
|
|
1056
1200
|
if (typeof payload["nonce"] !== "string" || payload["nonce"] !== pending.nonce) throw new Error("OIDC id_token nonce mismatch — possible replay attack");
|
|
1057
1201
|
const sub = typeof payload.sub === "string" ? payload.sub : null;
|
|
@@ -1066,7 +1210,12 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
1066
1210
|
username: String(username),
|
|
1067
1211
|
...emailClaim ? { email: emailClaim } : {},
|
|
1068
1212
|
...nameClaim ? { displayName: nameClaim } : {},
|
|
1069
|
-
isAdmin:
|
|
1213
|
+
isAdmin: false,
|
|
1214
|
+
...pending.linkIntent !== void 0 ? { linkIntent: pending.linkIntent } : {},
|
|
1215
|
+
issuer: doc.issuer,
|
|
1216
|
+
providerId,
|
|
1217
|
+
returnBase: pending.returnBase,
|
|
1218
|
+
popup: pending.popup
|
|
1070
1219
|
};
|
|
1071
1220
|
}
|
|
1072
1221
|
validateLocalSessionToken(_token) {
|
|
@@ -1079,9 +1228,20 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
1079
1228
|
reply.send({ error: `Unknown OIDC provider: ${providerId}` });
|
|
1080
1229
|
return;
|
|
1081
1230
|
}
|
|
1231
|
+
const linkParam = req.query["link"];
|
|
1232
|
+
if (linkParam !== void 0 && !LINK_INTENT_PATTERN.test(linkParam)) {
|
|
1233
|
+
reply.code(400);
|
|
1234
|
+
reply.send({ error: "Malformed link request" });
|
|
1235
|
+
return;
|
|
1236
|
+
}
|
|
1237
|
+
const popupParam = req.query["popup"];
|
|
1082
1238
|
const state = node_crypto.randomBytes(16).toString("base64url");
|
|
1083
1239
|
try {
|
|
1084
|
-
const url = await this.buildLoginUrl(providerId, state
|
|
1240
|
+
const url = await this.buildLoginUrl(providerId, state, {
|
|
1241
|
+
...linkParam !== void 0 ? { linkIntent: linkParam } : {},
|
|
1242
|
+
headers: req.headers,
|
|
1243
|
+
popup: popupParam === "1"
|
|
1244
|
+
});
|
|
1085
1245
|
reply.code(302);
|
|
1086
1246
|
reply.header("Location", url);
|
|
1087
1247
|
reply.send("");
|
|
@@ -1089,7 +1249,7 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
1089
1249
|
reply.code(500);
|
|
1090
1250
|
reply.send({
|
|
1091
1251
|
error: "OIDC start failed",
|
|
1092
|
-
message:
|
|
1252
|
+
message: require_dist.errMsg(err)
|
|
1093
1253
|
});
|
|
1094
1254
|
}
|
|
1095
1255
|
}
|
|
@@ -1120,22 +1280,31 @@ var AuthOidcAddon = class extends require_hub_browser_origin.BaseAddon {
|
|
|
1120
1280
|
}
|
|
1121
1281
|
try {
|
|
1122
1282
|
const result = await this.handleCallback(code, state);
|
|
1283
|
+
if (result.providerId !== providerId) {
|
|
1284
|
+
reply.code(400);
|
|
1285
|
+
reply.send({ error: "OIDC callback does not match the provider the login started at" });
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1123
1288
|
const { token: bridgeToken } = await this.ctx.api.ssoBridge.signBridgeToken.query({ claims: {
|
|
1124
1289
|
userId: result.userId,
|
|
1125
1290
|
username: result.username,
|
|
1126
1291
|
isAdmin: result.isAdmin,
|
|
1127
1292
|
provider: `auth-oidc/${providerId}`,
|
|
1128
1293
|
...result.email ? { email: result.email } : {},
|
|
1129
|
-
...result.displayName ? { displayName: result.displayName } : {}
|
|
1294
|
+
...result.displayName ? { displayName: result.displayName } : {},
|
|
1295
|
+
...result.linkIntent !== void 0 ? { linkIntent: result.linkIntent } : {},
|
|
1296
|
+
issuer: result.issuer
|
|
1130
1297
|
} });
|
|
1298
|
+
const finish = new URLSearchParams({ bridge: bridgeToken });
|
|
1299
|
+
if (result.popup) finish.set("popup", "1");
|
|
1131
1300
|
reply.code(302);
|
|
1132
|
-
reply.header("Location",
|
|
1301
|
+
reply.header("Location", `${result.returnBase}/api/auth/sso/finish?${finish.toString()}`);
|
|
1133
1302
|
reply.send("");
|
|
1134
1303
|
} catch (err) {
|
|
1135
1304
|
reply.code(500);
|
|
1136
1305
|
reply.send({
|
|
1137
1306
|
error: "OIDC callback failed",
|
|
1138
|
-
message:
|
|
1307
|
+
message: require_dist.errMsg(err)
|
|
1139
1308
|
});
|
|
1140
1309
|
}
|
|
1141
1310
|
}
|