mirror of
https://github.com/bitwarden/browser
synced 2026-02-07 12:13:45 +00:00
feat(change-password-component): Change Password Update [18720] - Org invite is seemingly working, found one bug to iron out.
This commit is contained in:
@@ -11,11 +11,14 @@ import {
|
||||
} from "@bitwarden/auth/angular";
|
||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@@ -42,6 +45,7 @@ export class WebLoginComponentService
|
||||
ssoLoginService: SsoLoginServiceAbstraction,
|
||||
private router: Router,
|
||||
private accountService: AccountService,
|
||||
private configService: ConfigService,
|
||||
) {
|
||||
super(
|
||||
cryptoFunctionService,
|
||||
@@ -95,12 +99,25 @@ export class WebLoginComponentService
|
||||
const isPolicyAndAutoEnrollEnabled =
|
||||
resetPasswordPolicy[1] && resetPasswordPolicy[0].autoEnrollEnabled;
|
||||
|
||||
const enforcedPasswordPolicyOptions = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.policyService.masterPasswordPolicyOptions$(userId, policies)),
|
||||
),
|
||||
);
|
||||
let enforcedPasswordPolicyOptions: MasterPasswordPolicyOptions;
|
||||
|
||||
if (
|
||||
await this.configService.getFeatureFlag(FeatureFlag.PM16117_ChangeExistingPasswordRefactor)
|
||||
) {
|
||||
// Properly error if we don't have an org invite with
|
||||
enforcedPasswordPolicyOptions = await firstValueFrom(
|
||||
this.policyService.masterPasswordPolicyOptions$(orgInvite.userId, policies),
|
||||
);
|
||||
} else {
|
||||
enforcedPasswordPolicyOptions = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) =>
|
||||
this.policyService.masterPasswordPolicyOptions$(userId, policies),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
policies,
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
import { Params } from "@angular/router";
|
||||
import { Jsonify } from "type-fest";
|
||||
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
export class OrganizationInvite {
|
||||
email: string;
|
||||
initOrganization: boolean;
|
||||
@@ -12,6 +14,7 @@ export class OrganizationInvite {
|
||||
organizationName: string;
|
||||
organizationUserId: string;
|
||||
token: string;
|
||||
userId: UserId;
|
||||
|
||||
static fromJSON(json: Jsonify<OrganizationInvite>): OrganizationInvite | null {
|
||||
if (json == null) {
|
||||
@@ -35,6 +38,7 @@ export class OrganizationInvite {
|
||||
organizationName: params.organizationName,
|
||||
organizationUserId: params.organizationUserId,
|
||||
token: params.token,
|
||||
userId: params.userId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ import {
|
||||
VaultTimeoutStringType,
|
||||
} from "@bitwarden/common/key-management/vault-timeout";
|
||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import {
|
||||
EnvironmentService,
|
||||
Urls,
|
||||
@@ -312,6 +313,7 @@ const safeProviders: SafeProvider[] = [
|
||||
SsoLoginServiceAbstraction,
|
||||
Router,
|
||||
AccountService,
|
||||
ConfigService,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
|
||||
@@ -487,6 +487,7 @@ const safeProviders: SafeProvider[] = [
|
||||
VaultTimeoutSettingsService,
|
||||
KdfConfigService,
|
||||
TaskSchedulerService,
|
||||
ConfigService,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
|
||||
@@ -18,9 +18,11 @@ import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||
import { ClientType, HttpStatusCode } from "@bitwarden/common/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
@@ -123,6 +125,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
||||
private logService: LogService,
|
||||
private validationService: ValidationService,
|
||||
private loginSuccessHandlerService: LoginSuccessHandlerService,
|
||||
private configService: ConfigService,
|
||||
) {
|
||||
this.clientType = this.platformUtilsService.getClientType();
|
||||
}
|
||||
@@ -226,7 +229,20 @@ export class LoginComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
const credentials = new PasswordLoginCredentials(email, masterPassword);
|
||||
let credentials: PasswordLoginCredentials;
|
||||
|
||||
if (
|
||||
(await this.configService.getFeatureFlag(
|
||||
FeatureFlag.PM16117_ChangeExistingPasswordRefactor,
|
||||
)) &&
|
||||
this.loginComponentService.getOrgPoliciesFromOrgInvite
|
||||
) {
|
||||
const orgPoliciesFromInvite = await this.loginComponentService.getOrgPoliciesFromOrgInvite();
|
||||
const orgPolicies = orgPoliciesFromInvite?.enforcedPasswordPolicyOptions ?? undefined;
|
||||
credentials = new PasswordLoginCredentials(email, masterPassword, undefined, orgPolicies);
|
||||
} else {
|
||||
credentials = new PasswordLoginCredentials(email, masterPassword);
|
||||
}
|
||||
|
||||
try {
|
||||
const authResult = await this.loginStrategyService.logIn(credentials);
|
||||
@@ -312,26 +328,30 @@ export class LoginComponent implements OnInit, OnDestroy {
|
||||
// Determine where to send the user next
|
||||
// The AuthGuard will handle routing to update-temp-password based on state
|
||||
|
||||
// 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 (
|
||||
!(await this.configService.getFeatureFlag(FeatureFlag.PM16117_ChangeExistingPasswordRefactor))
|
||||
) {
|
||||
// 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 (orgPolicies) {
|
||||
// Since we have retrieved the policies, we can go ahead and set them into state for future use
|
||||
// e.g., the update-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);
|
||||
if (orgPolicies) {
|
||||
// Since we have retrieved the policies, we can go ahead and set them into state for future use
|
||||
// e.g., the update-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(["update-password"]);
|
||||
return;
|
||||
const isPasswordChangeRequired = await this.isPasswordChangeRequiredByOrgPolicy(
|
||||
orgPolicies.enforcedPasswordPolicyOptions,
|
||||
);
|
||||
if (isPasswordChangeRequired) {
|
||||
await this.router.navigate(["update-password"]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
} from "@bitwarden/common/key-management/vault-timeout";
|
||||
import { KeysRequest } from "@bitwarden/common/models/request/keys.request";
|
||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
@@ -92,6 +93,7 @@ export abstract class LoginStrategy {
|
||||
protected vaultTimeoutSettingsService: VaultTimeoutSettingsService,
|
||||
protected KdfConfigService: KdfConfigService,
|
||||
protected environmentService: EnvironmentService,
|
||||
protected configService: ConfigService,
|
||||
) {}
|
||||
|
||||
abstract exportCache(): CacheData;
|
||||
|
||||
@@ -12,6 +12,7 @@ import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/ide
|
||||
import { IdentityDeviceVerificationResponse } from "@bitwarden/common/auth/models/response/identity-device-verification.response";
|
||||
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
||||
import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { HashPurpose } from "@bitwarden/common/platform/enums";
|
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||
@@ -75,7 +76,7 @@ export class PasswordLoginStrategy extends LoginStrategy {
|
||||
this.localMasterKeyHash$ = this.cache.pipe(map((state) => state.localMasterKeyHash));
|
||||
}
|
||||
|
||||
override async logIn(credentials: PasswordLoginCredentials) {
|
||||
override async logIn(credentials: PasswordLoginCredentials): Promise<AuthResult> {
|
||||
const { email, masterPassword, twoFactor } = credentials;
|
||||
|
||||
const data = new PasswordLoginStrategyData();
|
||||
@@ -167,11 +168,24 @@ export class PasswordLoginStrategy extends LoginStrategy {
|
||||
}
|
||||
|
||||
// The identity result can contain master password policies for the user's organizations
|
||||
const masterPasswordPolicyOptions =
|
||||
this.getMasterPasswordPolicyOptionsFromResponse(identityResponse);
|
||||
let masterPasswordPolicyOptions;
|
||||
|
||||
if (!masterPasswordPolicyOptions?.enforceOnLogin) {
|
||||
return;
|
||||
if (
|
||||
await this.configService.getFeatureFlag(FeatureFlag.PM16117_ChangeExistingPasswordRefactor)
|
||||
) {
|
||||
masterPasswordPolicyOptions = credentials.masterPasswordPolicies;
|
||||
authResult.orgInviteAndWeakPassword = true;
|
||||
|
||||
if (!masterPasswordPolicyOptions.enforceOnLogin) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
masterPasswordPolicyOptions =
|
||||
this.getMasterPasswordPolicyOptionsFromResponse(identityResponse);
|
||||
|
||||
if (!masterPasswordPolicyOptions?.enforceOnLogin) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is a policy active, evaluate the supplied password before its no longer in memory
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// @ts-strict-ignore
|
||||
import { Jsonify } from "type-fest";
|
||||
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type";
|
||||
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
|
||||
import { WebAuthnLoginAssertionResponseRequest } from "@bitwarden/common/auth/services/webauthn-login/request/webauthn-login-assertion-response.request";
|
||||
@@ -15,6 +16,7 @@ export class PasswordLoginCredentials {
|
||||
public email: string,
|
||||
public masterPassword: string,
|
||||
public twoFactor?: TokenTwoFactorRequest,
|
||||
public masterPasswordPolicies?: MasterPasswordPolicyOptions,
|
||||
) {}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import { VaultTimeoutSettingsService } from "@bitwarden/common/key-management/va
|
||||
import { PreloginRequest } from "@bitwarden/common/models/request/prelogin.request";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -131,6 +132,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
protected vaultTimeoutSettingsService: VaultTimeoutSettingsService,
|
||||
protected kdfConfigService: KdfConfigService,
|
||||
protected taskSchedulerService: TaskSchedulerService,
|
||||
protected configService: ConfigService,
|
||||
) {
|
||||
this.currentAuthnTypeState = this.stateProvider.get(CURRENT_LOGIN_STRATEGY_KEY);
|
||||
this.loginStrategyCacheState = this.stateProvider.get(CACHE_KEY);
|
||||
@@ -400,6 +402,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
this.vaultTimeoutSettingsService,
|
||||
this.kdfConfigService,
|
||||
this.environmentService,
|
||||
this.configService,
|
||||
];
|
||||
|
||||
return source.pipe(
|
||||
|
||||
@@ -18,6 +18,7 @@ export class AuthResult {
|
||||
email: string;
|
||||
requiresEncryptionKeyMigration: boolean;
|
||||
requiresDeviceVerification: boolean;
|
||||
orgInviteAndWeakPassword?: boolean;
|
||||
|
||||
get requiresTwoFactor() {
|
||||
return this.twoFactorProviders != null;
|
||||
|
||||
Reference in New Issue
Block a user