mirror of
https://github.com/bitwarden/browser
synced 2025-12-20 02:03:39 +00:00
[PM-17776] New Device - SSO Check (#13177)
* refactor SSO policy check to check for SSO users that have `ssoBound` true on any of their organizations
* Revert "refactor SSO policy check to check for SSO users that have `ssoBound` true on any of their organizations"
This reverts commit 419c26fbbc.
* update new device verification guard to check for master password usage
* add sso check for new device verification guard
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { TestBed } from "@angular/core/testing";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationUserType } from "@bitwarden/common/admin-console/enums";
|
||||
|
||||
import { VaultProfileService } from "./vault-profile.service";
|
||||
|
||||
@@ -13,6 +14,12 @@ describe("VaultProfileService", () => {
|
||||
creationDate: hardcodedDateString,
|
||||
twoFactorEnabled: true,
|
||||
id: "new-user-id",
|
||||
organizations: [
|
||||
{
|
||||
ssoBound: true,
|
||||
type: OrganizationUserType.Admin,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -91,4 +98,64 @@ describe("VaultProfileService", () => {
|
||||
expect(getProfile).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("getUserSSOBound", () => {
|
||||
it("calls `getProfile` when stored ssoBound property is not stored", async () => {
|
||||
expect(service["userIsSsoBound"]).toBeNull();
|
||||
|
||||
const userIsSsoBound = await service.getUserSSOBound(userId);
|
||||
|
||||
expect(userIsSsoBound).toBe(true);
|
||||
expect(getProfile).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls `getProfile` when stored profile id does not match", async () => {
|
||||
service["userIsSsoBound"] = false;
|
||||
service["userId"] = "old-user-id";
|
||||
|
||||
const userIsSsoBound = await service.getUserSSOBound(userId);
|
||||
|
||||
expect(userIsSsoBound).toBe(true);
|
||||
expect(getProfile).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not call `getProfile` when ssoBound property is already stored", async () => {
|
||||
service["userIsSsoBound"] = false;
|
||||
|
||||
const userIsSsoBound = await service.getUserSSOBound(userId);
|
||||
|
||||
expect(userIsSsoBound).toBe(false);
|
||||
expect(getProfile).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("getUserSSOBoundAdminOwner", () => {
|
||||
it("calls `getProfile` when stored userIsSsoBoundAdminOwner property is not stored", async () => {
|
||||
expect(service["userIsSsoBoundAdminOwner"]).toBeNull();
|
||||
|
||||
const userIsSsoBoundAdminOwner = await service.getUserSSOBoundAdminOwner(userId);
|
||||
|
||||
expect(userIsSsoBoundAdminOwner).toBe(true);
|
||||
expect(getProfile).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls `getProfile` when stored profile id does not match", async () => {
|
||||
service["userIsSsoBoundAdminOwner"] = false;
|
||||
service["userId"] = "old-user-id";
|
||||
|
||||
const userIsSsoBoundAdminOwner = await service.getUserSSOBoundAdminOwner(userId);
|
||||
|
||||
expect(userIsSsoBoundAdminOwner).toBe(true);
|
||||
expect(getProfile).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not call `getProfile` when userIsSsoBoundAdminOwner property is already stored", async () => {
|
||||
service["userIsSsoBoundAdminOwner"] = false;
|
||||
|
||||
const userIsSsoBoundAdminOwner = await service.getUserSSOBoundAdminOwner(userId);
|
||||
|
||||
expect(userIsSsoBoundAdminOwner).toBe(false);
|
||||
expect(getProfile).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Injectable, inject } from "@angular/core";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationUserType } from "@bitwarden/common/admin-console/enums";
|
||||
import { ProfileResponse } from "@bitwarden/common/models/response/profile.response";
|
||||
|
||||
@Injectable({
|
||||
@@ -24,6 +25,12 @@ export class VaultProfileService {
|
||||
/** True when 2FA is enabled on the profile. */
|
||||
private profile2FAEnabled: boolean | null = null;
|
||||
|
||||
/** True when ssoBound is true for any of the users organizations */
|
||||
private userIsSsoBound: boolean | null = null;
|
||||
|
||||
/** True when the user is an admin or owner of the ssoBound organization */
|
||||
private userIsSsoBoundAdminOwner: boolean | null = null;
|
||||
|
||||
/**
|
||||
* Returns the creation date of the profile.
|
||||
* Note: `Date`s are mutable in JS, creating a new
|
||||
@@ -52,12 +59,43 @@ export class VaultProfileService {
|
||||
return profile.twoFactorEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the user logs in with SSO for any organization.
|
||||
*/
|
||||
async getUserSSOBound(userId: string): Promise<boolean> {
|
||||
if (this.userIsSsoBound !== null && userId === this.userId) {
|
||||
return Promise.resolve(this.userIsSsoBound);
|
||||
}
|
||||
|
||||
await this.fetchAndCacheProfile();
|
||||
|
||||
return !!this.userIsSsoBound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when the user is an Admin or Owner of an organization with `ssoBound` true.
|
||||
*/
|
||||
async getUserSSOBoundAdminOwner(userId: string): Promise<boolean> {
|
||||
if (this.userIsSsoBoundAdminOwner !== null && userId === this.userId) {
|
||||
return Promise.resolve(this.userIsSsoBoundAdminOwner);
|
||||
}
|
||||
|
||||
await this.fetchAndCacheProfile();
|
||||
|
||||
return !!this.userIsSsoBoundAdminOwner;
|
||||
}
|
||||
|
||||
private async fetchAndCacheProfile(): Promise<ProfileResponse> {
|
||||
const profile = await this.apiService.getProfile();
|
||||
|
||||
this.userId = profile.id;
|
||||
this.profileCreatedDate = profile.creationDate;
|
||||
this.profile2FAEnabled = profile.twoFactorEnabled;
|
||||
const ssoBoundOrg = profile.organizations.find((org) => org.ssoBound);
|
||||
this.userIsSsoBound = !!ssoBoundOrg;
|
||||
this.userIsSsoBoundAdminOwner =
|
||||
ssoBoundOrg?.type === OrganizationUserType.Admin ||
|
||||
ssoBoundOrg?.type === OrganizationUserType.Owner;
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user