diff --git a/server/routers/idp/validateOidcCallback.ts b/server/routers/idp/validateOidcCallback.ts
index 45e9fd7c..1a13c5dd 100644
--- a/server/routers/idp/validateOidcCallback.ts
+++ b/server/routers/idp/validateOidcCallback.ts
@@ -10,6 +10,7 @@ import {
idp,
idpOidcConfig,
idpOrg,
+ orgs,
Role,
roles,
userOrgs,
@@ -214,32 +215,47 @@ export async function validateOidcCallback(
);
if (existingIdp.idp.autoProvision) {
- const idpOrgs = await db
- .select()
- .from(idpOrg)
- .where(eq(idpOrg.idpId, existingIdp.idp.idpId));
+ const allOrgs = await db.select().from(orgs);
const defaultRoleMapping = existingIdp.idp.defaultRoleMapping;
const defaultOrgMapping = existingIdp.idp.defaultOrgMapping;
let userOrgInfo: { orgId: string; roleId: number }[] = [];
- for (const idpOrg of idpOrgs) {
+ for (const org of allOrgs) {
+ const [idpOrgRes] = await db
+ .select()
+ .from(idpOrg)
+ .where(
+ and(
+ eq(idpOrg.idpId, existingIdp.idp.idpId),
+ eq(idpOrg.orgId, org.orgId)
+ )
+ );
+
let roleId: number | undefined = undefined;
- const orgMapping = idpOrg.orgMapping || defaultOrgMapping;
- const hydratedOrgMapping = orgMapping
- ?.split("{{orgId}}")
- .join(idpOrg.orgId);
+ const orgMapping = idpOrgRes?.orgMapping || defaultOrgMapping;
+ const hydratedOrgMapping = hydrateOrgMapping(
+ orgMapping,
+ org.orgId
+ );
if (hydratedOrgMapping) {
+ logger.debug("Hydrated Org Mapping", {
+ hydratedOrgMapping
+ });
const orgId = jmespath.search(claims, hydratedOrgMapping);
- if (!(orgId === true || orgId === idpOrg.orgId)) {
+ logger.debug("Extraced Org ID", { orgId });
+ if (orgId !== true && orgId !== org.orgId) {
+ // user not allowed to access this org
continue;
}
}
- const roleMapping = idpOrg.roleMapping || defaultRoleMapping;
+ const roleMapping =
+ idpOrgRes?.roleMapping || defaultRoleMapping;
if (roleMapping) {
+ logger.debug("Role Mapping", { roleMapping });
const roleName = jmespath.search(claims, roleMapping);
if (!roleName) {
@@ -254,14 +270,14 @@ export async function validateOidcCallback(
.from(roles)
.where(
and(
- eq(roles.orgId, idpOrg.orgId),
+ eq(roles.orgId, org.orgId),
eq(roles.name, roleName)
)
);
if (!roleRes) {
logger.error("Role not found", {
- orgId: idpOrg.orgId,
+ orgId: org.orgId,
roleName
});
continue;
@@ -270,7 +286,7 @@ export async function validateOidcCallback(
roleId = roleRes.roleId;
userOrgInfo.push({
- orgId: idpOrg.orgId,
+ orgId: org.orgId,
roleId
});
}
@@ -443,3 +459,13 @@ export async function validateOidcCallback(
);
}
}
+
+function hydrateOrgMapping(
+ orgMapping: string | null,
+ orgId: string
+): string | undefined {
+ if (!orgMapping) {
+ return undefined;
+ }
+ return orgMapping.split("{{orgId}}").join(orgId);
+}
diff --git a/src/app/admin/idp/[idpId]/general/page.tsx b/src/app/admin/idp/[idpId]/general/page.tsx
index 72f8e2b5..760f590b 100644
--- a/src/app/admin/idp/[idpId]/general/page.tsx
+++ b/src/app/admin/idp/[idpId]/general/page.tsx
@@ -101,7 +101,7 @@ export default function GeneralPage() {
emailPath: data.idpOidcConfig.emailPath,
namePath: data.idpOidcConfig.namePath,
scopes: data.idpOidcConfig.scopes,
- autoProvision: data.idpOidcConfig.autoProvision
+ autoProvision: data.idp.autoProvision
});
}
} catch (e) {
diff --git a/src/app/auth/idp/[idpId]/oidc/callback/ValidateOidcToken.tsx b/src/app/auth/idp/[idpId]/oidc/callback/ValidateOidcToken.tsx
index 1d6ec80e..c946869b 100644
--- a/src/app/auth/idp/[idpId]/oidc/callback/ValidateOidcToken.tsx
+++ b/src/app/auth/idp/[idpId]/oidc/callback/ValidateOidcToken.tsx
@@ -22,7 +22,7 @@ type ValidateOidcTokenParams = {
code: string | undefined;
expectedState: string | undefined;
stateCookie: string | undefined;
- idp: {name: string};
+ idp: { name: string };
};
export default function ValidateOidcToken(props: ValidateOidcTokenParams) {
@@ -64,11 +64,10 @@ export default function ValidateOidcToken(props: ValidateOidcTokenParams) {
await new Promise((resolve) => setTimeout(resolve, 100));
if (redirectUrl.startsWith("http")) {
- window.location.href = res.data.data.redirectUrl; // TODO: validate this to make sure it's safe
+ window.location.href = res.data.data.redirectUrl; // this is validated by the parent using this component
} else {
router.push(res.data.data.redirectUrl);
}
-
} catch (e) {
setError(formatAxiosError(e, "Error validating OIDC token"));
} finally {
@@ -103,8 +102,12 @@ export default function ValidateOidcToken(props: ValidateOidcTokenParams) {
Log in to get started
++ Log in to get started +
diff --git a/src/app/auth/resource/[resourceId]/ResourceAuthPortal.tsx b/src/app/auth/resource/[resourceId]/ResourceAuthPortal.tsx
index 77dd5d51..d7efa59c 100644
--- a/src/app/auth/resource/[resourceId]/ResourceAuthPortal.tsx
+++ b/src/app/auth/resource/[resourceId]/ResourceAuthPortal.tsx
@@ -33,7 +33,7 @@ import { useRouter } from "next/navigation";
import { Alert, AlertDescription } from "@app/components/ui/alert";
import { formatAxiosError } from "@app/lib/api";
import { AxiosResponse } from "axios";
-import LoginForm from "@app/components/LoginForm";
+import LoginForm, { LoginFormIDP } from "@app/components/LoginForm";
import {
AuthWithPasswordResponse,
AuthWithWhitelistResponse
@@ -81,6 +81,7 @@ type ResourceAuthPortalProps = {
id: number;
};
redirect: string;
+ idps?: LoginFormIDP[];
};
export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
@@ -490,6 +491,7 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
className={`${numMethods <= 1 ? "mt-0" : ""}`}
>