mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-12 07:24:51 +00:00
host everywhere
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
import { UserPlusIcon } from "@heroicons/react/24/outline";
|
||||
import { Organization } from "@zitadel/proto/zitadel/org/v2/org_pb";
|
||||
import { getLocale, getTranslations } from "next-intl/server";
|
||||
import { headers } from "next/headers";
|
||||
import Link from "next/link";
|
||||
|
||||
async function loadSessions() {
|
||||
@@ -35,9 +36,15 @@ export default async function Page(props: {
|
||||
const authRequestId = searchParams?.authRequestId;
|
||||
const organization = searchParams?.organization;
|
||||
|
||||
const host = (await headers()).get("host");
|
||||
|
||||
if (!host || typeof host !== "string") {
|
||||
throw new Error("No host found");
|
||||
}
|
||||
|
||||
let defaultOrganization;
|
||||
if (!organization) {
|
||||
const org: Organization | null = await getDefaultOrg();
|
||||
const org: Organization | null = await getDefaultOrg({ host });
|
||||
if (org) {
|
||||
defaultOrganization = org.id;
|
||||
}
|
||||
@@ -45,9 +52,10 @@ export default async function Page(props: {
|
||||
|
||||
let sessions = await loadSessions();
|
||||
|
||||
const branding = await getBrandingSettings(
|
||||
organization ?? defaultOrganization,
|
||||
);
|
||||
const branding = await getBrandingSettings({
|
||||
host,
|
||||
organization: organization ?? defaultOrganization,
|
||||
});
|
||||
|
||||
const params = new URLSearchParams();
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
} from "@/lib/zitadel";
|
||||
import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb";
|
||||
import { getLocale, getTranslations } from "next-intl/server";
|
||||
import { headers } from "next/headers";
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams: Promise<Record<string | number | symbol, string | undefined>>;
|
||||
@@ -27,19 +28,25 @@ export default async function Page(props: {
|
||||
|
||||
const { loginName, authRequestId, organization, sessionId } = searchParams;
|
||||
|
||||
const sessionWithData = sessionId
|
||||
? await loadSessionById(sessionId, organization)
|
||||
: await loadSessionByLoginname(loginName, organization);
|
||||
const host = (await headers()).get("host");
|
||||
|
||||
async function getAuthMethodsAndUser(session?: Session) {
|
||||
if (!host || typeof host !== "string") {
|
||||
throw new Error("No host found");
|
||||
}
|
||||
|
||||
const sessionWithData = sessionId
|
||||
? await loadSessionById(host, sessionId, organization)
|
||||
: await loadSessionByLoginname(host, loginName, organization);
|
||||
|
||||
async function getAuthMethodsAndUser(host: string, session?: Session) {
|
||||
const userId = session?.factors?.user?.id;
|
||||
|
||||
if (!userId) {
|
||||
throw Error("Could not get user id from session");
|
||||
}
|
||||
|
||||
return listAuthenticationMethodTypes(userId).then((methods) => {
|
||||
return getUserByID(userId).then((user) => {
|
||||
return listAuthenticationMethodTypes({ host, userId }).then((methods) => {
|
||||
return getUserByID({ host, userId }).then((user) => {
|
||||
const humanUser =
|
||||
user.user?.type.case === "human" ? user.user?.type.value : undefined;
|
||||
|
||||
@@ -55,6 +62,7 @@ export default async function Page(props: {
|
||||
}
|
||||
|
||||
async function loadSessionByLoginname(
|
||||
host: string,
|
||||
loginName?: string,
|
||||
organization?: string,
|
||||
) {
|
||||
@@ -62,17 +70,22 @@ export default async function Page(props: {
|
||||
loginName,
|
||||
organization,
|
||||
}).then((session) => {
|
||||
return getAuthMethodsAndUser(session);
|
||||
return getAuthMethodsAndUser(host, session);
|
||||
});
|
||||
}
|
||||
|
||||
async function loadSessionById(sessionId: string, organization?: string) {
|
||||
async function loadSessionById(
|
||||
host: string,
|
||||
sessionId: string,
|
||||
organization?: string,
|
||||
) {
|
||||
const recent = await getSessionCookieById({ sessionId, organization });
|
||||
return getSession({
|
||||
host,
|
||||
sessionId: recent.id,
|
||||
sessionToken: recent.token,
|
||||
}).then((sessionResponse) => {
|
||||
return getAuthMethodsAndUser(sessionResponse.session);
|
||||
return getAuthMethodsAndUser(host, sessionResponse.session);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -80,18 +93,21 @@ export default async function Page(props: {
|
||||
return <Alert>{tError("unknownContext")}</Alert>;
|
||||
}
|
||||
|
||||
const branding = await getBrandingSettings(
|
||||
sessionWithData.factors?.user?.organizationId,
|
||||
);
|
||||
const branding = await getBrandingSettings({
|
||||
host,
|
||||
organization: sessionWithData.factors?.user?.organizationId,
|
||||
});
|
||||
|
||||
const loginSettings = await getLoginSettings(
|
||||
sessionWithData.factors?.user?.organizationId,
|
||||
);
|
||||
const loginSettings = await getLoginSettings({
|
||||
host,
|
||||
organization: sessionWithData.factors?.user?.organizationId,
|
||||
});
|
||||
|
||||
const identityProviders = await getActiveIdentityProviders(
|
||||
sessionWithData.factors?.user?.organizationId,
|
||||
true,
|
||||
).then((resp) => {
|
||||
const identityProviders = await getActiveIdentityProviders({
|
||||
host,
|
||||
orgId: sessionWithData.factors?.user?.organizationId,
|
||||
linking_allowed: true,
|
||||
}).then((resp) => {
|
||||
return resp.identityProviders;
|
||||
});
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { DynamicTheme } from "@/components/dynamic-theme";
|
||||
import { getBrandingSettings } from "@/lib/zitadel";
|
||||
import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
|
||||
import { getLocale, getTranslations } from "next-intl/server";
|
||||
import { headers } from "next/headers";
|
||||
|
||||
// This configuration shows the given name in the respective IDP button as fallback
|
||||
const PROVIDER_NAME_MAPPING: {
|
||||
@@ -22,7 +23,13 @@ export default async function Page(props: {
|
||||
|
||||
const { organization } = searchParams;
|
||||
|
||||
const branding = await getBrandingSettings(organization);
|
||||
const host = (await headers()).get("host");
|
||||
|
||||
if (!host || typeof host !== "string") {
|
||||
throw new Error("No host found");
|
||||
}
|
||||
|
||||
const branding = await getBrandingSettings({ host, organization });
|
||||
|
||||
return (
|
||||
<DynamicTheme branding={branding}>
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
AddHumanUserRequestSchema,
|
||||
} from "@zitadel/proto/zitadel/user/v2/user_service_pb";
|
||||
import { getLocale, getTranslations } from "next-intl/server";
|
||||
import { headers } from "next/headers";
|
||||
|
||||
const ORG_SUFFIX_REGEX = /(?<=@)(.+)/;
|
||||
|
||||
@@ -37,13 +38,19 @@ export default async function Page(props: {
|
||||
const { id, token, authRequestId, organization, link } = searchParams;
|
||||
const { provider } = params;
|
||||
|
||||
const branding = await getBrandingSettings(organization);
|
||||
const host = (await headers()).get("host");
|
||||
|
||||
if (!host || typeof host !== "string") {
|
||||
throw new Error("No host found");
|
||||
}
|
||||
|
||||
const branding = await getBrandingSettings({ host, organization });
|
||||
|
||||
if (!provider || !id || !token) {
|
||||
return loginFailed(branding, "IDP context missing");
|
||||
}
|
||||
|
||||
const intent = await retrieveIDPIntent(id, token);
|
||||
const intent = await retrieveIDPIntent({ host, id, token });
|
||||
|
||||
const { idpInformation, userId } = intent;
|
||||
|
||||
@@ -63,7 +70,7 @@ export default async function Page(props: {
|
||||
return loginFailed(branding, "IDP information missing");
|
||||
}
|
||||
|
||||
const idp = await getIDPByID(idpInformation.idpId);
|
||||
const idp = await getIDPByID({ host, id: idpInformation.idpId });
|
||||
const options = idp?.config?.options;
|
||||
|
||||
if (!idp) {
|
||||
@@ -80,14 +87,15 @@ export default async function Page(props: {
|
||||
|
||||
let idpLink;
|
||||
try {
|
||||
idpLink = await addIDPLink(
|
||||
{
|
||||
idpLink = await addIDPLink({
|
||||
host,
|
||||
idp: {
|
||||
id: idpInformation.idpId,
|
||||
userId: idpInformation.userId,
|
||||
userName: idpInformation.userName,
|
||||
},
|
||||
userId,
|
||||
);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return linkingFailed(branding);
|
||||
@@ -111,19 +119,20 @@ export default async function Page(props: {
|
||||
const email = PROVIDER_MAPPING[providerType](idpInformation).email?.email;
|
||||
|
||||
if (options.autoLinking === AutoLinkingOption.EMAIL && email) {
|
||||
foundUser = await listUsers({ email }).then((response) => {
|
||||
foundUser = await listUsers({ host, 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 },
|
||||
? { host, userName: idpInformation.userName }
|
||||
: { host, email },
|
||||
).then((response) => {
|
||||
return response.result ? response.result[0] : null;
|
||||
});
|
||||
} else {
|
||||
foundUser = await listUsers({
|
||||
host,
|
||||
userName: idpInformation.userName,
|
||||
email,
|
||||
}).then((response) => {
|
||||
@@ -134,14 +143,15 @@ export default async function Page(props: {
|
||||
if (foundUser) {
|
||||
let idpLink;
|
||||
try {
|
||||
idpLink = await addIDPLink(
|
||||
{
|
||||
idpLink = await addIDPLink({
|
||||
host,
|
||||
idp: {
|
||||
id: idpInformation.idpId,
|
||||
userId: idpInformation.userId,
|
||||
userName: idpInformation.userName,
|
||||
},
|
||||
foundUser.userId,
|
||||
);
|
||||
userId: foundUser.userId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return linkingFailed(branding);
|
||||
@@ -175,11 +185,14 @@ export default async function Page(props: {
|
||||
const suffix = matched?.[1] ?? "";
|
||||
|
||||
// this just returns orgs where the suffix is set as primary domain
|
||||
const orgs = await getOrgsByDomain(suffix);
|
||||
const orgs = await getOrgsByDomain({ host, domain: suffix });
|
||||
const orgToCheckForDiscovery =
|
||||
orgs.result && orgs.result.length === 1 ? orgs.result[0].id : undefined;
|
||||
|
||||
const orgLoginSettings = await getLoginSettings(orgToCheckForDiscovery);
|
||||
const orgLoginSettings = await getLoginSettings({
|
||||
host,
|
||||
organization: orgToCheckForDiscovery,
|
||||
});
|
||||
if (orgLoginSettings?.allowDomainDiscovery) {
|
||||
orgToRegisterOn = orgToCheckForDiscovery;
|
||||
}
|
||||
@@ -196,7 +209,7 @@ export default async function Page(props: {
|
||||
});
|
||||
}
|
||||
|
||||
const newUser = await addHuman(userData);
|
||||
const newUser = await addHuman({ host, request: userData });
|
||||
|
||||
if (newUser) {
|
||||
return (
|
||||
|
||||
@@ -2,6 +2,7 @@ import { DynamicTheme } from "@/components/dynamic-theme";
|
||||
import { SignInWithIdp } from "@/components/sign-in-with-idp";
|
||||
import { getActiveIdentityProviders, getBrandingSettings } from "@/lib/zitadel";
|
||||
import { getLocale, getTranslations } from "next-intl/server";
|
||||
import { headers } from "next/headers";
|
||||
|
||||
export default async function Page(props: {
|
||||
searchParams: Promise<Record<string | number | symbol, string | undefined>>;
|
||||
@@ -13,13 +14,20 @@ export default async function Page(props: {
|
||||
const authRequestId = searchParams?.authRequestId;
|
||||
const organization = searchParams?.organization;
|
||||
|
||||
const identityProviders = await getActiveIdentityProviders(organization).then(
|
||||
(resp) => {
|
||||
return resp.identityProviders;
|
||||
},
|
||||
);
|
||||
const host = (await headers()).get("host");
|
||||
|
||||
const branding = await getBrandingSettings(organization);
|
||||
if (!host || typeof host !== "string") {
|
||||
throw new Error("No host found");
|
||||
}
|
||||
|
||||
const identityProviders = await getActiveIdentityProviders({
|
||||
host,
|
||||
orgId: organization,
|
||||
}).then((resp) => {
|
||||
return resp.identityProviders;
|
||||
});
|
||||
|
||||
const branding = await getBrandingSettings({ host, organization });
|
||||
|
||||
return (
|
||||
<DynamicTheme branding={branding}>
|
||||
|
||||
@@ -22,6 +22,12 @@ export default async function Page(props: {
|
||||
const t = await getTranslations({ locale, namespace: "otp" });
|
||||
const tError = await getTranslations({ locale, namespace: "error" });
|
||||
|
||||
const host = (await headers()).get("host");
|
||||
|
||||
if (!host || typeof host !== "string") {
|
||||
throw new Error("No host found");
|
||||
}
|
||||
|
||||
const {
|
||||
loginName, // send from password page
|
||||
userId, // send from email link
|
||||
@@ -35,12 +41,17 @@ export default async function Page(props: {
|
||||
const { method } = params;
|
||||
|
||||
const session = sessionId
|
||||
? await loadSessionById(sessionId, organization)
|
||||
? await loadSessionById(host, sessionId, organization)
|
||||
: await loadMostRecentSession({ loginName, organization });
|
||||
|
||||
async function loadSessionById(sessionId: string, organization?: string) {
|
||||
async function loadSessionById(
|
||||
host: string,
|
||||
sessionId: string,
|
||||
organization?: string,
|
||||
) {
|
||||
const recent = await getSessionCookieById({ sessionId, organization });
|
||||
return getSession({
|
||||
host,
|
||||
sessionId: recent.id,
|
||||
sessionToken: recent.token,
|
||||
}).then((response) => {
|
||||
@@ -51,15 +62,15 @@ export default async function Page(props: {
|
||||
}
|
||||
|
||||
// email links do not come with organization, thus we need to use the session's organization
|
||||
const branding = await getBrandingSettings(
|
||||
organization ?? session?.factors?.user?.organizationId,
|
||||
);
|
||||
const branding = await getBrandingSettings({
|
||||
host,
|
||||
organization: organization ?? session?.factors?.user?.organizationId,
|
||||
});
|
||||
|
||||
const loginSettings = await getLoginSettings(
|
||||
organization ?? session?.factors?.user?.organizationId,
|
||||
);
|
||||
|
||||
const host = (await headers()).get("host");
|
||||
const loginSettings = await getLoginSettings({
|
||||
host,
|
||||
organization: organization ?? session?.factors?.user?.organizationId,
|
||||
});
|
||||
|
||||
return (
|
||||
<DynamicTheme branding={branding}>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Client, create, Duration } from "@zitadel/client";
|
||||
import { createServerTransport } from "@zitadel/client/node";
|
||||
import { createSystemServiceClient } from "@zitadel/client/v1";
|
||||
import { makeReqCtx } from "@zitadel/client/v2";
|
||||
import { IdentityProviderService } from "@zitadel/proto/zitadel/idp/v2/idp_service_pb";
|
||||
import { TextQueryMethod } from "@zitadel/proto/zitadel/object/v2/object_pb";
|
||||
@@ -42,6 +44,7 @@ import {
|
||||
VerifyU2FRegistrationRequest,
|
||||
} from "@zitadel/proto/zitadel/user/v2/user_service_pb";
|
||||
import { unstable_cacheLife as cacheLife } from "next/cache";
|
||||
import { systemAPIToken } from "./api";
|
||||
import { createServiceForHost } from "./service";
|
||||
|
||||
const useCache = process.env.DEBUG !== "true";
|
||||
@@ -70,15 +73,15 @@ async function cacheWrapper<T>(callback: Promise<T>) {
|
||||
// const settingsService: Client<typeof SettingsService> =
|
||||
// await createServiceForHost(SettingsService, host);
|
||||
|
||||
// const systemService = async () => {
|
||||
// const systemToken = await systemAPIToken();
|
||||
const systemService = async () => {
|
||||
const systemToken = await systemAPIToken();
|
||||
|
||||
// const transport = createServerTransport(systemToken, {
|
||||
// baseUrl: process.env.ZITADEL_API_URL,
|
||||
// });
|
||||
const transport = createServerTransport(systemToken, {
|
||||
baseUrl: process.env.ZITADEL_API_URL,
|
||||
});
|
||||
|
||||
// return createSystemServiceClient(transport);
|
||||
// };
|
||||
return createSystemServiceClient(transport);
|
||||
};
|
||||
|
||||
export async function getInstanceByHost(host: string) {
|
||||
return (await systemService())
|
||||
@@ -125,16 +128,16 @@ export async function getBrandingSettings({
|
||||
|
||||
export async function getLoginSettings({
|
||||
host,
|
||||
orgId,
|
||||
organization,
|
||||
}: {
|
||||
host: string;
|
||||
orgId?: string;
|
||||
organization?: string;
|
||||
}) {
|
||||
const settingsService: Client<typeof SettingsService> =
|
||||
await createServiceForHost(SettingsService, host);
|
||||
|
||||
const callback = settingsService
|
||||
.getLoginSettings({ ctx: makeReqCtx(orgId) }, {})
|
||||
.getLoginSettings({ ctx: makeReqCtx(organization) }, {})
|
||||
.then((resp) => (resp.settings ? resp.settings : undefined));
|
||||
|
||||
return useCache ? cacheWrapper(callback) : callback;
|
||||
|
||||
Reference in New Issue
Block a user