This commit is contained in:
peintnermax
2024-08-21 14:15:44 +02:00
parent 2379f87a20
commit ab0ac166c9
8 changed files with 167 additions and 194 deletions

View File

@@ -1,4 +1,3 @@
import { ProviderSlug } from "@/lib/demos";
import { getBrandingSettings, PROVIDER_NAME_MAPPING } from "@/lib/zitadel";
import DynamicTheme from "@/ui/DynamicTheme";
@@ -7,7 +6,7 @@ export default async function Page({
params,
}: {
searchParams: Record<string | number | symbol, string | undefined>;
params: { provider: ProviderSlug };
params: { provider: string };
}) {
const { id, token, authRequestId, organization } = searchParams;
const { provider } = params;

View File

@@ -1,4 +1,3 @@
import { ProviderSlug } from "@/lib/demos";
import {
addIDPLink,
createUser,
@@ -11,18 +10,14 @@ import {
import Alert, { AlertType } from "@/ui/Alert";
import DynamicTheme from "@/ui/DynamicTheme";
import IdpSignin from "@/ui/IdpSignin";
import { AddHumanUserRequest } from "@zitadel/proto/zitadel/user/v2/user_service_pb";
import { IDPInformation, IDPLink } from "@zitadel/proto/zitadel/user/v2/idp_pb";
import { AutoLinkingOption } from "@zitadel/proto/zitadel/idp/v2/idp_pb";
import { PartialMessage } from "@zitadel/client";
export default async function Page({
searchParams,
params,
}: {
searchParams: Record<string | number | symbol, string | undefined>;
params: { provider: ProviderSlug };
params: { provider: string };
}) {
const { id, token, authRequestId, organization } = searchParams;
const { provider } = params;

View File

@@ -1,4 +1,4 @@
import { ProviderSlug } from "@/lib/demos";
import { idpTypeToSlug } from "@/lib/idp";
import {
getActiveIdentityProviders,
getLoginSettings,
@@ -7,14 +7,16 @@ import {
startIdentityProviderFlow,
} from "@/lib/zitadel";
import { createSessionForUserIdAndUpdateCookie } from "@/utils/session";
import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
import { NextRequest, NextResponse } from "next/server";
export async function POST(request: NextRequest) {
const body = await request.json();
if (body) {
const { loginName, authRequestId, organization } = body;
return listUsers(loginName, organization).then(async (users) => {
return listUsers({
userName: loginName,
organizationId: organization,
}).then(async (users) => {
if (users.details?.totalResult == BigInt(1) && users.result[0].userId) {
const userId = users.result[0].userId;
return createSessionForUserIdAndUpdateCookie(
@@ -64,28 +66,8 @@ export async function POST(request: NextRequest) {
const host = request.nextUrl.origin;
const identityProviderType = identityProviders[0].type;
let provider: string;
switch (identityProviderType) {
case IdentityProviderType.GITHUB:
provider = "github";
break;
case IdentityProviderType.GOOGLE:
provider = "google";
break;
case IdentityProviderType.AZURE_AD:
provider = "azure";
break;
case IdentityProviderType.SAML:
provider = "saml";
break;
case IdentityProviderType.OIDC:
provider = "oidc";
break;
default:
provider = "oidc";
break;
}
const provider = idpTypeToSlug(identityProviderType);
const params = new URLSearchParams();

View File

@@ -18,6 +18,7 @@ import {
Prompt,
} from "@zitadel/proto/zitadel/oidc/v2/authorization_pb";
import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
import { idpTypeToSlug } from "@/lib/idp";
async function loadSessions(ids: string[]): Promise<Session[]> {
const response = await listSessions(
@@ -168,28 +169,7 @@ export async function GET(request: NextRequest) {
const host = request.nextUrl.origin;
const identityProviderType = identityProviders[0].type;
let provider: string;
switch (identityProviderType) {
case IdentityProviderType.GITHUB:
provider = "github";
break;
case IdentityProviderType.GOOGLE:
provider = "google";
break;
case IdentityProviderType.AZURE_AD:
provider = "azure";
break;
case IdentityProviderType.SAML:
provider = "saml";
break;
case IdentityProviderType.OIDC:
provider = "oidc";
break;
default:
provider = "oidc";
break;
}
let provider = idpTypeToSlug(identityProviderType);
const params = new URLSearchParams();

View File

@@ -4,12 +4,6 @@ export type Item = {
description?: string;
};
export enum ProviderSlug {
GOOGLE = "google",
GITHUB = "github",
AZURE = "microsoft",
}
export const demos: { name: string; items: Item[] }[] = [
{
name: "Login",

125
apps/login/src/lib/idp.ts Normal file
View File

@@ -0,0 +1,125 @@
import { AddHumanUserRequest } from "@zitadel/proto/zitadel/user/v2/user_service_pb";
import { IDPInformation, IDPLink } from "@zitadel/proto/zitadel/user/v2/idp_pb";
import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
import { PartialMessage } from "@zitadel/client";
export function idpTypeToSlug(idpType: IdentityProviderType) {
switch (idpType) {
case IdentityProviderType.GITHUB:
return "github";
case IdentityProviderType.GOOGLE:
return "google";
case IdentityProviderType.AZURE_AD:
return "azure";
case IdentityProviderType.SAML:
return "saml";
case IdentityProviderType.OIDC:
return "oidc";
default:
throw new Error("Unknown identity provider type");
}
}
export const PROVIDER_NAME_MAPPING: {
[provider: string]: string;
} = {
[IdentityProviderType.GOOGLE]: "Google",
[IdentityProviderType.GITHUB]: "GitHub",
[IdentityProviderType.AZURE_AD]: "Microsoft",
};
export const PROVIDER_MAPPING: {
[provider: string]: (
rI: IDPInformation,
) => PartialMessage<AddHumanUserRequest>;
} = {
[IdentityProviderType.GOOGLE]: (idp: IDPInformation) => {
const rawInfo = idp.rawInformation?.toJson() as {
User: {
email: string;
name?: string;
given_name?: string;
family_name?: string;
};
};
const idpLink: PartialMessage<IDPLink> = {
idpId: idp.idpId,
userId: idp.userId,
userName: idp.userName,
};
const req: PartialMessage<AddHumanUserRequest> = {
username: idp.userName,
email: {
email: rawInfo.User?.email,
verification: { case: "isVerified", value: true },
},
// organisation: Organisation | undefined;
profile: {
displayName: rawInfo.User?.name ?? "",
givenName: rawInfo.User?.given_name ?? "",
familyName: rawInfo.User?.family_name ?? "",
},
idpLinks: [idpLink],
};
return req;
},
[IdentityProviderType.AZURE_AD]: (idp: IDPInformation) => {
const rawInfo = idp.rawInformation?.toJson() as {
mail: string;
displayName?: string;
givenName?: string;
surname?: string;
};
const idpLink: PartialMessage<IDPLink> = {
idpId: idp.idpId,
userId: idp.userId,
userName: idp.userName,
};
const req: PartialMessage<AddHumanUserRequest> = {
username: idp.userName,
email: {
email: rawInfo?.mail,
verification: { case: "isVerified", value: true },
},
// organisation: Organisation | undefined;
profile: {
displayName: rawInfo?.displayName ?? "",
givenName: rawInfo?.givenName ?? "",
familyName: rawInfo?.surname ?? "",
},
idpLinks: [idpLink],
};
return req;
},
[IdentityProviderType.GITHUB]: (idp: IDPInformation) => {
const rawInfo = idp.rawInformation?.toJson() as {
email: string;
name: string;
};
const idpLink: PartialMessage<IDPLink> = {
idpId: idp.idpId,
userId: idp.userId,
userName: idp.userName,
};
const req: PartialMessage<AddHumanUserRequest> = {
username: idp.userName,
email: {
email: rawInfo?.email,
verification: { case: "isVerified", value: true },
},
// organisation: Organisation | undefined;
profile: {
displayName: rawInfo?.name ?? "",
givenName: rawInfo?.name ?? "",
familyName: rawInfo?.name ?? "",
},
idpLinks: [idpLink],
};
return req;
},
};

View File

@@ -13,17 +13,16 @@ import { RequestChallenges } from "@zitadel/proto/zitadel/session/v2/challenge_p
import {
RetrieveIdentityProviderIntentRequest,
VerifyU2FRegistrationRequest,
AddHumanUserRequest,
} from "@zitadel/proto/zitadel/user/v2/user_service_pb";
import { IDPInformation, IDPLink } from "@zitadel/proto/zitadel/user/v2/idp_pb";
import { IDPInformation } from "@zitadel/proto/zitadel/user/v2/idp_pb";
import { CreateCallbackRequest } from "@zitadel/proto/zitadel/oidc/v2/oidc_service_pb";
import { TextQueryMethod } from "@zitadel/proto/zitadel/object/v2/object_pb";
import type { RedirectURLs } from "@zitadel/proto/zitadel/user/v2/idp_pb";
import { ProviderSlug } from "./demos";
import { PartialMessage, PlainMessage } from "@zitadel/client";
import VerifyEmailForm from "@/ui/VerifyEmailForm";
import { SearchQuery as UserSearchQuery } from "@zitadel/proto/zitadel/user/v2/query_pb";
import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
import { PROVIDER_MAPPING } from "./idp";
const SESSION_LIFETIME_S = 3000;
@@ -296,14 +295,6 @@ export async function getOrgByDomain(domain: string) {
return managementService.getOrgByDomainGlobal({ domain }, {});
}
export const PROVIDER_NAME_MAPPING: {
[provider: string]: string;
} = {
[ProviderSlug.GOOGLE]: "Google",
[ProviderSlug.GITHUB]: "GitHub",
[ProviderSlug.AZURE]: "Microft",
};
export async function startIdentityProviderFlow({
idpId,
urls,
@@ -400,104 +391,8 @@ export function addIDPLink(
);
}
export const PROVIDER_MAPPING: {
[provider: string]: (
rI: IDPInformation,
) => PartialMessage<AddHumanUserRequest>;
} = {
[ProviderSlug.GOOGLE]: (idp: IDPInformation) => {
const rawInfo = idp.rawInformation?.toJson() as {
User: {
email: string;
name?: string;
given_name?: string;
family_name?: string;
};
};
const idpLink: PartialMessage<IDPLink> = {
idpId: idp.idpId,
userId: idp.userId,
userName: idp.userName,
};
const req: PartialMessage<AddHumanUserRequest> = {
username: idp.userName,
email: {
email: rawInfo.User?.email,
verification: { case: "isVerified", value: true },
},
// organisation: Organisation | undefined;
profile: {
displayName: rawInfo.User?.name ?? "",
givenName: rawInfo.User?.given_name ?? "",
familyName: rawInfo.User?.family_name ?? "",
},
idpLinks: [idpLink],
};
return req;
},
[ProviderSlug.AZURE]: (idp: IDPInformation) => {
const rawInfo = idp.rawInformation?.toJson() as {
mail: string;
displayName?: string;
givenName?: string;
surname?: string;
};
const idpLink: PartialMessage<IDPLink> = {
idpId: idp.idpId,
userId: idp.userId,
userName: idp.userName,
};
const req: PartialMessage<AddHumanUserRequest> = {
username: idp.userName,
email: {
email: rawInfo?.mail,
verification: { case: "isVerified", value: true },
},
// organisation: Organisation | undefined;
profile: {
displayName: rawInfo?.displayName ?? "",
givenName: rawInfo?.givenName ?? "",
familyName: rawInfo?.surname ?? "",
},
idpLinks: [idpLink],
};
return req;
},
[ProviderSlug.GITHUB]: (idp: IDPInformation) => {
const rawInfo = idp.rawInformation?.toJson() as {
email: string;
name: string;
};
const idpLink: PartialMessage<IDPLink> = {
idpId: idp.idpId,
userId: idp.userId,
userName: idp.userName,
};
const req: PartialMessage<AddHumanUserRequest> = {
username: idp.userName,
email: {
email: rawInfo?.email,
verification: { case: "isVerified", value: true },
},
// organisation: Organisation | undefined;
profile: {
displayName: rawInfo?.name ?? "",
givenName: rawInfo?.name ?? "",
familyName: rawInfo?.name ?? "",
},
idpLinks: [idpLink],
};
return req;
},
};
export function createUser(
provider: ProviderSlug,
provider: string,
info: IDPInformation,
): Promise<string> {
const userData = PROVIDER_MAPPING[provider](info);

View File

@@ -1,6 +1,6 @@
"use client";
import { ReactNode, useState } from "react";
import { ReactNode, useState } from "react";
import {
SignInWithGitlab,
SignInWithAzureAD,
@@ -8,10 +8,10 @@ import {
SignInWithGithub,
} from "@zitadel/react";
import { useRouter } from "next/navigation";
import { ProviderSlug } from "@/lib/demos";
import Alert from "./Alert";
import BackButton from "./BackButton";
import { IdentityProvider } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
import { idpTypeToSlug } from "@/lib/idp";
import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
export interface SignInWithIDPProps {
children?: ReactNode;
@@ -36,7 +36,7 @@ export function SignInWithIDP({
const [error, setError] = useState<string>("");
const router = useRouter();
async function startFlow(idpId: string, provider: ProviderSlug) {
async function startFlow(idpId: string, provider: string) {
setLoading(true);
const params = new URLSearchParams();
@@ -78,62 +78,65 @@ export function SignInWithIDP({
{identityProviders &&
identityProviders.map((idp, i) => {
switch (idp.type) {
case 6: // IdentityProviderType.IDENTITY_PROVIDER_TYPE_GITHUB:
case IdentityProviderType.GITHUB:
return (
<SignInWithGithub
key={`idp-${i}`}
onClick={() =>
startFlow(idp.id, ProviderSlug.GITHUB).then(
({ authUrl }) => {
startFlow(
idp.id,
idpTypeToSlug(IdentityProviderType.GITHUB),
).then(({ authUrl }) => {
router.push(authUrl);
},
)
})
}
></SignInWithGithub>
);
case 7: // IdentityProviderType.IDENTITY_PROVIDER_TYPE_GITHUB_ES:
case IdentityProviderType.GITHUB_ES:
return (
<SignInWithGithub
key={`idp-${i}`}
onClick={() => alert("TODO: unimplemented")}
></SignInWithGithub>
);
case 5: // IdentityProviderType.IDENTITY_PROVIDER_TYPE_AZURE_AD:
case IdentityProviderType.AZURE_AD:
return (
<SignInWithAzureAD
key={`idp-${i}`}
onClick={() =>
startFlow(idp.id, ProviderSlug.AZURE).then(
({ authUrl }) => {
startFlow(
idp.id,
idpTypeToSlug(IdentityProviderType.AZURE_AD),
).then(({ authUrl }) => {
router.push(authUrl);
},
)
})
}
></SignInWithAzureAD>
);
case 10: // IdentityProviderType.IDENTITY_PROVIDER_TYPE_GOOGLE:
case IdentityProviderType.GOOGLE:
return (
<SignInWithGoogle
key={`idp-${i}`}
e2e="google"
name={idp.name}
onClick={() =>
startFlow(idp.id, ProviderSlug.GOOGLE).then(
({ authUrl }) => {
startFlow(
idp.id,
idpTypeToSlug(IdentityProviderType.GOOGLE),
).then(({ authUrl }) => {
router.push(authUrl);
},
)
})
}
></SignInWithGoogle>
);
case 8: // IdentityProviderType.IDENTITY_PROVIDER_TYPE_GITLAB:
case IdentityProviderType.GITLAB:
return (
<SignInWithGitlab
key={`idp-${i}`}
onClick={() => alert("TODO: unimplemented")}
></SignInWithGitlab>
);
case 9: //IdentityProviderType.IDENTITY_PROVIDER_TYPE_GITLAB_SELF_HOSTED:
case IdentityProviderType.GITLAB_SELF_HOSTED:
return (
<SignInWithGitlab
key={`idp-${i}`}