From 7ffa983469ff61b0f9ce718f17567879cc64542b Mon Sep 17 00:00:00 2001 From: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> Date: Mon, 18 Dec 2023 11:28:15 -0500 Subject: [PATCH] Auth/PM-1658 - Dynamic Org Invite Link to accelerate users through org invite accept process (#6702) * PM-1658 - Update Accept Organization component to take new org invite qParams into acct for accelerating the user through the org invite accept process. * PM-1658 - Update trial initiation and register form comps to respect fromOrgInvite when email is populated to make the populated email read only so users in the org invite process dont change it. * PM-1658 - Per PR feedback, we could simplify the logic by only sending the org sso identifier if it was required to be used. * PM-1658 - Accept Comp - should send existing user email as qParam to get it to autofill properly. Previous "autofill" was due to using remember email when creating an account before testing the existing user inv flow. --- .../app/auth/accept-organization.component.ts | 47 +++++++++++++++++++ .../register-form.component.html | 8 +++- .../register-form/register-form.component.ts | 1 + .../trial-initiation.component.html | 1 + .../trial-initiation.component.ts | 2 + 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/auth/accept-organization.component.ts b/apps/web/src/app/auth/accept-organization.component.ts index ae965c3faf..fd38e2546a 100644 --- a/apps/web/src/app/auth/accept-organization.component.ts +++ b/apps/web/src/app/auth/accept-organization.component.ts @@ -84,6 +84,10 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent { async unauthedHandler(qParams: Params): Promise { await this.prepareOrganizationInvitation(qParams); + + // In certain scenarios, we want to accelerate the user through the accept org invite process + // For example, if the user has a BW account already, we want them to be taken to login instead of creation. + await this.accelerateInviteAcceptIfPossible(qParams); } private async acceptInitOrganizationFlow(qParams: Params): Promise { @@ -186,4 +190,47 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent { } await this.stateService.setOrganizationInvitation(qParams); } + + private async accelerateInviteAcceptIfPossible(qParams: Params): Promise { + // Extract the query params we need to make routing acceleration decisions + const orgSsoIdentifier = qParams.orgSsoIdentifier; + const orgUserHasExistingUser = this.stringToNullOrBool(qParams.orgUserHasExistingUser); + + // if orgUserHasExistingUser is null, short circuit for backwards compatibility w/ older servers + if (orgUserHasExistingUser == null) { + return; + } + + // if user exists, send user to login + if (orgUserHasExistingUser) { + this.router.navigate(["/login"], { + queryParams: { email: qParams.email }, + }); + return; + } + + // no user exists; so either sign in via SSO and JIT provision one or simply register. + + if (orgSsoIdentifier) { + // We only send sso org identifier if the org has SSO enabled and the SSO policy required. + this.router.navigate(["/sso"], { + queryParams: { email: qParams.email, identifier: orgSsoIdentifier }, + }); + return; + } + + // if SSO is disabled OR if sso is enabled but the SSO login required policy is not enabled + // then send user to create account + this.router.navigate(["/register"], { + queryParams: { email: qParams.email, fromOrgInvite: true }, + }); + return; + } + + private stringToNullOrBool(s: string | undefined): boolean | null { + if (s === undefined) { + return null; + } + return s.toLowerCase() === "true"; + } } diff --git a/apps/web/src/app/auth/register-form/register-form.component.html b/apps/web/src/app/auth/register-form/register-form.component.html index 481140a7d2..a646d5e9a7 100644 --- a/apps/web/src/app/auth/register-form/register-form.component.html +++ b/apps/web/src/app/auth/register-form/register-form.component.html @@ -11,7 +11,13 @@
{{ "emailAddress" | i18n }} - + {{ "emailAddressDesc" | i18n }}
diff --git a/apps/web/src/app/auth/register-form/register-form.component.ts b/apps/web/src/app/auth/register-form/register-form.component.ts index 1b6a9e46a5..e4254b94ce 100644 --- a/apps/web/src/app/auth/register-form/register-form.component.ts +++ b/apps/web/src/app/auth/register-form/register-form.component.ts @@ -25,6 +25,7 @@ import { DialogService } from "@bitwarden/components"; }) export class RegisterFormComponent extends BaseRegisterComponent { @Input() queryParamEmail: string; + @Input() queryParamFromOrgInvite: boolean; @Input() enforcedPolicyOptions: MasterPasswordPolicyOptions; @Input() referenceDataValue: ReferenceEventRequest; diff --git a/apps/web/src/app/auth/trial-initiation/trial-initiation.component.html b/apps/web/src/app/auth/trial-initiation/trial-initiation.component.html index 7324bf97ef..e2d774bcf7 100644 --- a/apps/web/src/app/auth/trial-initiation/trial-initiation.component.html +++ b/apps/web/src/app/auth/trial-initiation/trial-initiation.component.html @@ -6,6 +6,7 @@ > diff --git a/apps/web/src/app/auth/trial-initiation/trial-initiation.component.ts b/apps/web/src/app/auth/trial-initiation/trial-initiation.component.ts index aacf4a049c..002e1687e0 100644 --- a/apps/web/src/app/auth/trial-initiation/trial-initiation.component.ts +++ b/apps/web/src/app/auth/trial-initiation/trial-initiation.component.ts @@ -52,6 +52,7 @@ enum ValidLayoutParams { }) export class TrialInitiationComponent implements OnInit, OnDestroy { email = ""; + fromOrgInvite = false; org = ""; orgInfoSubLabel = ""; orgId = ""; @@ -127,6 +128,7 @@ export class TrialInitiationComponent implements OnInit, OnDestroy { this.referenceData = new ReferenceEventRequest(); if (qParams.email != null && qParams.email.indexOf("@") > -1) { this.email = qParams.email; + this.fromOrgInvite = qParams.fromOrgInvite === "true"; } this.referenceDataId = qParams.reference;