mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-12 09:54:00 +00:00
username, email check for linking
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
getBrandingSettings,
|
||||
getIDPByID,
|
||||
listUsers,
|
||||
PROVIDER_MAPPING,
|
||||
retrieveIDPIntent,
|
||||
} from "@/lib/zitadel";
|
||||
import Alert, { AlertType } from "@/ui/Alert";
|
||||
@@ -12,104 +13,10 @@ 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";
|
||||
|
||||
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 default async function Page({
|
||||
searchParams,
|
||||
params,
|
||||
@@ -151,11 +58,30 @@ export default async function Page({
|
||||
|
||||
// search for potential user via username, then link
|
||||
if (options?.isLinkingAllowed) {
|
||||
const foundUser = await listUsers(idpInformation.userName).then(
|
||||
(response) => {
|
||||
let foundUser;
|
||||
const email =
|
||||
PROVIDER_MAPPING[provider](idpInformation).email?.email;
|
||||
|
||||
if (options.autoLinking === AutoLinkingOption.EMAIL && email) {
|
||||
foundUser = await listUsers({ email }).then((response) => {
|
||||
return response.result ? response.result[0] : null;
|
||||
},
|
||||
);
|
||||
});
|
||||
} else if (options.autoLinking === AutoLinkingOption.USERNAME) {
|
||||
foundUser = await listUsers(
|
||||
options.autoLinking === AutoLinkingOption.USERNAME
|
||||
? { userName: idpInformation.userName }
|
||||
: { email },
|
||||
).then((response) => {
|
||||
return response.result ? response.result[0] : null;
|
||||
});
|
||||
} else {
|
||||
foundUser = await listUsers({
|
||||
userName: idpInformation.userName,
|
||||
email,
|
||||
}).then((response) => {
|
||||
return response.result ? response.result[0] : null;
|
||||
});
|
||||
}
|
||||
|
||||
if (foundUser) {
|
||||
const idpLink = await addIDPLink(
|
||||
@@ -184,6 +110,7 @@ export default async function Page({
|
||||
|
||||
if (idpLink) {
|
||||
return (
|
||||
// TODO: possibily login user now
|
||||
<DynamicTheme branding={branding}>
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
<h1>Account successfully linked</h1>
|
||||
|
||||
@@ -22,6 +22,8 @@ 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";
|
||||
|
||||
const SESSION_LIFETIME_S = 3000;
|
||||
|
||||
@@ -237,40 +239,54 @@ export async function getUserByID(userId: string) {
|
||||
return userService.getUserByID({ userId }, {});
|
||||
}
|
||||
|
||||
export async function listUsers(userName: string, organizationId?: string) {
|
||||
export async function listUsers({
|
||||
userName,
|
||||
email,
|
||||
organizationId,
|
||||
}: {
|
||||
userName?: string;
|
||||
email?: string;
|
||||
organizationId?: string;
|
||||
}) {
|
||||
const queries: PartialMessage<UserSearchQuery>[] = [];
|
||||
|
||||
if (userName) {
|
||||
queries.push({
|
||||
query: {
|
||||
case: "userNameQuery",
|
||||
value: {
|
||||
userName,
|
||||
method: TextQueryMethod.EQUALS,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (organizationId) {
|
||||
queries.push({
|
||||
query: {
|
||||
case: "organizationIdQuery",
|
||||
value: {
|
||||
organizationId,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (email) {
|
||||
queries.push({
|
||||
query: {
|
||||
case: "emailQuery",
|
||||
value: {
|
||||
emailAddress: email,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return userService.listUsers(
|
||||
{
|
||||
queries: organizationId
|
||||
? [
|
||||
{
|
||||
query: {
|
||||
case: "userNameQuery",
|
||||
value: {
|
||||
userName,
|
||||
method: TextQueryMethod.EQUALS,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
query: {
|
||||
case: "organizationIdQuery",
|
||||
value: {
|
||||
organizationId,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
query: {
|
||||
case: "userNameQuery",
|
||||
value: {
|
||||
userName,
|
||||
method: TextQueryMethod.EQUALS,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
queries: queries,
|
||||
},
|
||||
{},
|
||||
);
|
||||
@@ -384,7 +400,7 @@ export function addIDPLink(
|
||||
);
|
||||
}
|
||||
|
||||
const PROVIDER_MAPPING: {
|
||||
export const PROVIDER_MAPPING: {
|
||||
[provider: string]: (
|
||||
rI: IDPInformation,
|
||||
) => PartialMessage<AddHumanUserRequest>;
|
||||
@@ -421,6 +437,37 @@ const PROVIDER_MAPPING: {
|
||||
};
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user