mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-23 00:08:23 +00:00
org discovery on idp callback
This commit is contained in:
@@ -3,17 +3,27 @@ import { DynamicTheme } from "@/components/dynamic-theme";
|
|||||||
import { IdpSignin } from "@/components/idp-signin";
|
import { IdpSignin } from "@/components/idp-signin";
|
||||||
import { idpTypeToIdentityProviderType, PROVIDER_MAPPING } from "@/lib/idp";
|
import { idpTypeToIdentityProviderType, PROVIDER_MAPPING } from "@/lib/idp";
|
||||||
import {
|
import {
|
||||||
|
addHuman,
|
||||||
addIDPLink,
|
addIDPLink,
|
||||||
createUser,
|
|
||||||
getBrandingSettings,
|
getBrandingSettings,
|
||||||
getIDPByID,
|
getIDPByID,
|
||||||
|
getLoginSettings,
|
||||||
|
getOrgsByDomain,
|
||||||
listUsers,
|
listUsers,
|
||||||
retrieveIDPIntent,
|
retrieveIDPIntent,
|
||||||
} from "@/lib/zitadel";
|
} from "@/lib/zitadel";
|
||||||
|
import { create } from "@zitadel/client";
|
||||||
import { AutoLinkingOption } from "@zitadel/proto/zitadel/idp/v2/idp_pb";
|
import { AutoLinkingOption } from "@zitadel/proto/zitadel/idp/v2/idp_pb";
|
||||||
|
import { OrganizationSchema } from "@zitadel/proto/zitadel/object/v2/object_pb";
|
||||||
import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb";
|
import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb";
|
||||||
|
import {
|
||||||
|
AddHumanUserRequest,
|
||||||
|
AddHumanUserRequestSchema,
|
||||||
|
} from "@zitadel/proto/zitadel/user/v2/user_service_pb";
|
||||||
import { getLocale, getTranslations } from "next-intl/server";
|
import { getLocale, getTranslations } from "next-intl/server";
|
||||||
|
|
||||||
|
const ORG_SUFFIX_REGEX = /(?<=@)(.+)/;
|
||||||
|
|
||||||
async function loginFailed(branding?: BrandingSettings, error: string = "") {
|
async function loginFailed(branding?: BrandingSettings, error: string = "") {
|
||||||
const locale = getLocale();
|
const locale = getLocale();
|
||||||
const t = await getTranslations({ locale, namespace: "idp" });
|
const t = await getTranslations({ locale, namespace: "idp" });
|
||||||
@@ -192,7 +202,42 @@ export default async function Page(props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options?.isCreationAllowed && options.isAutoCreation) {
|
if (options?.isCreationAllowed && options.isAutoCreation) {
|
||||||
const newUser = await createUser(providerType, idpInformation);
|
let orgToRegisterOn: string | undefined = organization;
|
||||||
|
|
||||||
|
let userData: AddHumanUserRequest =
|
||||||
|
PROVIDER_MAPPING[providerType](idpInformation);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!orgToRegisterOn &&
|
||||||
|
userData.username && // username or email?
|
||||||
|
ORG_SUFFIX_REGEX.test(userData.username)
|
||||||
|
) {
|
||||||
|
const matched = ORG_SUFFIX_REGEX.exec(userData.username);
|
||||||
|
const suffix = matched?.[1] ?? "";
|
||||||
|
|
||||||
|
// this just returns orgs where the suffix is set as primary domain
|
||||||
|
const orgs = await getOrgsByDomain(suffix);
|
||||||
|
const orgToCheckForDiscovery =
|
||||||
|
orgs.result && orgs.result.length === 1 ? orgs.result[0].id : undefined;
|
||||||
|
|
||||||
|
const orgLoginSettings = await getLoginSettings(orgToCheckForDiscovery);
|
||||||
|
if (orgLoginSettings?.allowDomainDiscovery) {
|
||||||
|
orgToRegisterOn = orgToCheckForDiscovery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orgToRegisterOn) {
|
||||||
|
const organizationSchema = create(OrganizationSchema, {
|
||||||
|
org: { case: "orgId", value: orgToRegisterOn },
|
||||||
|
});
|
||||||
|
|
||||||
|
userData = create(AddHumanUserRequestSchema, {
|
||||||
|
...userData,
|
||||||
|
organization: organizationSchema,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const newUser = await addHuman(userData);
|
||||||
|
|
||||||
if (newUser) {
|
if (newUser) {
|
||||||
return (
|
return (
|
||||||
|
@@ -61,7 +61,7 @@ export default async function Page(props: {
|
|||||||
<SignInWithIdp
|
<SignInWithIdp
|
||||||
identityProviders={identityProviders}
|
identityProviders={identityProviders}
|
||||||
authRequestId={authRequestId}
|
authRequestId={authRequestId}
|
||||||
organization={organization ?? defaultOrganization} // use the organization from the searchParams here otherwise fallback to the default organization
|
organization={organization}
|
||||||
></SignInWithIdp>
|
></SignInWithIdp>
|
||||||
)}
|
)}
|
||||||
</UsernameForm>
|
</UsernameForm>
|
||||||
|
@@ -10,8 +10,8 @@ import {
|
|||||||
import { createServerTransport } from "@zitadel/node";
|
import { createServerTransport } from "@zitadel/node";
|
||||||
import { RequestChallenges } from "@zitadel/proto/zitadel/session/v2/challenge_pb";
|
import { RequestChallenges } from "@zitadel/proto/zitadel/session/v2/challenge_pb";
|
||||||
import { Checks } from "@zitadel/proto/zitadel/session/v2/session_service_pb";
|
import { Checks } from "@zitadel/proto/zitadel/session/v2/session_service_pb";
|
||||||
import { IDPInformation } from "@zitadel/proto/zitadel/user/v2/idp_pb";
|
|
||||||
import {
|
import {
|
||||||
|
AddHumanUserRequest,
|
||||||
RetrieveIdentityProviderIntentRequest,
|
RetrieveIdentityProviderIntentRequest,
|
||||||
SetPasswordRequest,
|
SetPasswordRequest,
|
||||||
SetPasswordRequestSchema,
|
SetPasswordRequestSchema,
|
||||||
@@ -23,7 +23,6 @@ import { create, Duration } from "@zitadel/client";
|
|||||||
import { TextQueryMethod } from "@zitadel/proto/zitadel/object/v2/object_pb";
|
import { TextQueryMethod } from "@zitadel/proto/zitadel/object/v2/object_pb";
|
||||||
import { CreateCallbackRequest } from "@zitadel/proto/zitadel/oidc/v2/oidc_service_pb";
|
import { CreateCallbackRequest } from "@zitadel/proto/zitadel/oidc/v2/oidc_service_pb";
|
||||||
import { Organization } from "@zitadel/proto/zitadel/org/v2/org_pb";
|
import { Organization } from "@zitadel/proto/zitadel/org/v2/org_pb";
|
||||||
import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
|
|
||||||
import type { RedirectURLsJson } from "@zitadel/proto/zitadel/user/v2/idp_pb";
|
import type { RedirectURLsJson } from "@zitadel/proto/zitadel/user/v2/idp_pb";
|
||||||
import {
|
import {
|
||||||
NotificationType,
|
NotificationType,
|
||||||
@@ -39,7 +38,6 @@ import {
|
|||||||
UserState,
|
UserState,
|
||||||
} from "@zitadel/proto/zitadel/user/v2/user_pb";
|
} from "@zitadel/proto/zitadel/user/v2/user_pb";
|
||||||
import { unstable_cacheLife as cacheLife } from "next/cache";
|
import { unstable_cacheLife as cacheLife } from "next/cache";
|
||||||
import { PROVIDER_MAPPING } from "./idp";
|
|
||||||
|
|
||||||
const transport = createServerTransport(
|
const transport = createServerTransport(
|
||||||
process.env.ZITADEL_SERVICE_USER_TOKEN!,
|
process.env.ZITADEL_SERVICE_USER_TOKEN!,
|
||||||
@@ -249,6 +247,10 @@ export async function addHumanUser({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function addHuman(request: AddHumanUserRequest) {
|
||||||
|
return userService.addHumanUser(request);
|
||||||
|
}
|
||||||
|
|
||||||
export async function verifyTOTPRegistration(code: string, userId: string) {
|
export async function verifyTOTPRegistration(code: string, userId: string) {
|
||||||
return userService.verifyTOTPRegistration({ code, userId }, {});
|
return userService.verifyTOTPRegistration({ code, userId }, {});
|
||||||
}
|
}
|
||||||
@@ -487,14 +489,6 @@ export function addIDPLink(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createUser(
|
|
||||||
provider: IdentityProviderType,
|
|
||||||
info: IDPInformation,
|
|
||||||
) {
|
|
||||||
const userData = PROVIDER_MAPPING[provider](info);
|
|
||||||
return userService.addHumanUser(userData, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param userId the id of the user where the email should be set
|
* @param userId the id of the user where the email should be set
|
||||||
|
Reference in New Issue
Block a user