diff --git a/acceptance/docker-compose.yaml b/acceptance/docker-compose.yaml index de699038..240d9155 100644 --- a/acceptance/docker-compose.yaml +++ b/acceptance/docker-compose.yaml @@ -1,7 +1,7 @@ services: zitadel: user: "${ZITADEL_DEV_UID}" - image: "${ZITADEL_IMAGE:-ghcr.io/zitadel/zitadel:v2.65.0}" + image: "${ZITADEL_IMAGE:-ghcr.io/zitadel/zitadel:v2.67.2}" command: 'start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled --config /zitadel.yaml --steps /zitadel.yaml' ports: - "8080:8080" @@ -22,7 +22,7 @@ services: - POSTGRES_HOST_AUTH_METHOD=trust command: postgres -c shared_preload_libraries=pg_stat_statements -c pg_stat_statements.track=all -c shared_buffers=1GB -c work_mem=16MB -c effective_io_concurrency=100 -c wal_level=minimal -c archive_mode=off -c max_wal_senders=0 healthcheck: - test: [ "CMD-SHELL", "pg_isready" ] + test: ["CMD-SHELL", "pg_isready"] interval: "10s" timeout: "30s" retries: 5 diff --git a/apps/login/readme.md b/apps/login/readme.md index a411b996..fd6ba6f4 100644 --- a/apps/login/readme.md +++ b/apps/login/readme.md @@ -395,6 +395,5 @@ Timebased features like the multifactor init prompt or password expiry, are not - Password Expiry Settings - Login Settings: multifactor init prompt - forceMFA on login settings is not checked for IDPs -- disablePhone / disableEmail from loginSettings will be implemented right after https://github.com/zitadel/zitadel/issues/9016 is merged Also note that IDP logins are considered as valid MFA. An additional MFA check will be implemented in future if enforced. diff --git a/apps/login/src/app/(login)/loginname/page.tsx b/apps/login/src/app/(login)/loginname/page.tsx index 44601e18..5400f64b 100644 --- a/apps/login/src/app/(login)/loginname/page.tsx +++ b/apps/login/src/app/(login)/loginname/page.tsx @@ -20,6 +20,7 @@ export default async function Page(props: { const loginName = searchParams?.loginName; const authRequestId = searchParams?.authRequestId; const organization = searchParams?.organization; + const suffix = searchParams?.suffix; const submit: boolean = searchParams?.submit === "true"; let defaultOrganization; @@ -34,6 +35,8 @@ export default async function Page(props: { organization ?? defaultOrganization, ); + const contextLoginSettings = await getLoginSettings(organization); + const identityProviders = await getActiveIdentityProviders( organization ?? defaultOrganization, ).then((resp) => { @@ -54,6 +57,8 @@ export default async function Page(props: { loginName={loginName} authRequestId={authRequestId} organization={organization} // stick to "organization" as we still want to do user discovery based on the searchParams not the default organization, later the organization is determined by the found user + loginSettings={contextLoginSettings} + suffix={suffix} submit={submit} allowRegister={!!loginSettings?.allowRegister} > diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index e9632651..f5741bb3 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -300,6 +300,7 @@ export async function GET(request: NextRequest) { const { authRequest } = await getAuthRequest({ authRequestId }); let organization = ""; + let suffix = ""; let idpId = ""; if (authRequest?.scope) { @@ -326,6 +327,7 @@ export async function GET(request: NextRequest) { const orgs = await getOrgsByDomain(orgDomain); if (orgs.result && orgs.result.length === 1) { organization = orgs.result[0].id ?? ""; + suffix = orgDomain; } } } @@ -448,6 +450,9 @@ export async function GET(request: NextRequest) { if (organization) { loginNameUrl.searchParams.set("organization", organization); } + if (suffix) { + loginNameUrl.searchParams.set("suffix", suffix); + } return NextResponse.redirect(loginNameUrl); } else if (authRequest.prompt.includes(Prompt.NONE)) { /** diff --git a/apps/login/src/components/input.tsx b/apps/login/src/components/input.tsx index 0cb9e584..de19156b 100644 --- a/apps/login/src/components/input.tsx +++ b/apps/login/src/components/input.tsx @@ -15,6 +15,7 @@ export type TextInputProps = DetailedHTMLProps< HTMLInputElement > & { label: string; + suffix?: string; placeholder?: string; defaultValue?: string; error?: string | ReactNode; @@ -45,6 +46,7 @@ export const TextInput = forwardRef( label, placeholder, defaultValue, + suffix, required = false, error, disabled, @@ -56,7 +58,7 @@ export const TextInput = forwardRef( ref, ) => { return ( -