1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-11 05:43:41 +00:00

fix(change-password-prompt) [Auth/PM-22356] Scope org invite email to submitted email (#15783)

Adds a check to make sure that the email on the Org Invite matches the email submitted in the form. If it matches, only then do we apply the org invite to get the MP policies. But if the emails do not match, it means the user attempting to login is no longer the user who originally clicked the emailed org invite link. Therefore, we clear the Org Invite + Deep Link and allow the user to login as normal.
This commit is contained in:
rr-bw
2025-08-07 08:19:35 -07:00
committed by GitHub
parent 1ffe8e433f
commit 46046ca1fa
4 changed files with 88 additions and 46 deletions

View File

@@ -23,7 +23,7 @@ export abstract class LoginComponentService {
* Gets the organization policies if there is an organization invite.
* - Used by: Web
*/
getOrgPoliciesFromOrgInvite?: () => Promise<PasswordPolicies | null>;
getOrgPoliciesFromOrgInvite?: (email: string) => Promise<PasswordPolicies | null>;
/**
* Indicates whether login with passkey is supported on the given client

View File

@@ -80,6 +80,7 @@ export class LoginComponent implements OnInit, OnDestroy {
clientType: ClientType;
ClientType = ClientType;
orgPoliciesFromInvite: PasswordPolicies | null = null;
LoginUiState = LoginUiState;
isKnownDevice = false;
loginUiState: LoginUiState = LoginUiState.EMAIL_ENTRY;
@@ -232,11 +233,12 @@ export class LoginComponent implements OnInit, OnDestroy {
// Try to retrieve any org policies from an org invite now so we can send it to the
// login strategies. Since it is optional and we only want to be doing this on the
// web we will only send in content in the right context.
const orgPoliciesFromInvite = this.loginComponentService.getOrgPoliciesFromOrgInvite
? await this.loginComponentService.getOrgPoliciesFromOrgInvite()
this.orgPoliciesFromInvite = this.loginComponentService.getOrgPoliciesFromOrgInvite
? await this.loginComponentService.getOrgPoliciesFromOrgInvite(email)
: null;
const orgMasterPasswordPolicyOptions = orgPoliciesFromInvite?.enforcedPasswordPolicyOptions;
const orgMasterPasswordPolicyOptions =
this.orgPoliciesFromInvite?.enforcedPasswordPolicyOptions;
const credentials = new PasswordLoginCredentials(
email,
@@ -327,25 +329,18 @@ export class LoginComponent implements OnInit, OnDestroy {
// TODO: PM-18269 - evaluate if we can combine this with the
// password evaluation done in the password login strategy.
// If there's an existing org invite, use it to get the org's password policies
// so we can evaluate the MP against the org policies
if (this.loginComponentService.getOrgPoliciesFromOrgInvite) {
const orgPolicies: PasswordPolicies | null =
await this.loginComponentService.getOrgPoliciesFromOrgInvite();
if (this.orgPoliciesFromInvite) {
// Since we have retrieved the policies, we can go ahead and set them into state for future use
// e.g., the change-password page currently only references state for policy data and
// doesn't fallback to pulling them from the server like it should if they are null.
await this.setPoliciesIntoState(authResult.userId, this.orgPoliciesFromInvite.policies);
if (orgPolicies) {
// Since we have retrieved the policies, we can go ahead and set them into state for future use
// e.g., the change-password page currently only references state for policy data and
// doesn't fallback to pulling them from the server like it should if they are null.
await this.setPoliciesIntoState(authResult.userId, orgPolicies.policies);
const isPasswordChangeRequired = await this.isPasswordChangeRequiredByOrgPolicy(
orgPolicies.enforcedPasswordPolicyOptions,
);
if (isPasswordChangeRequired) {
await this.router.navigate(["change-password"]);
return;
}
const isPasswordChangeRequired = await this.isPasswordChangeRequiredByOrgPolicy(
this.orgPoliciesFromInvite.enforcedPasswordPolicyOptions,
);
if (isPasswordChangeRequired) {
await this.router.navigate(["change-password"]);
return;
}
}