1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

remove single org exemption for admins/owners when auto confirm is enabled (#17050)

This commit is contained in:
Brandon Treston
2025-11-03 09:52:48 -05:00
committed by GitHub
parent 7ac6a67835
commit 63c14af4f8
2 changed files with 88 additions and 7 deletions

View File

@@ -554,6 +554,77 @@ describe("PolicyService", () => {
expect(result).toBe(false);
});
describe("SingleOrg policy exemptions", () => {
it("returns true for SingleOrg policy when AutoConfirm is enabled, even for users who can manage policies", async () => {
singleUserState.nextState(
arrayToRecord([
policyData("policy1", "org6", PolicyType.SingleOrg, true),
policyData("policy2", "org6", PolicyType.AutoConfirm, true),
]),
);
const result = await firstValueFrom(
policyService.policyAppliesToUser$(PolicyType.SingleOrg, userId),
);
expect(result).toBe(true);
});
it("returns false for SingleOrg policy when user can manage policies and AutoConfirm is not enabled", async () => {
singleUserState.nextState(
arrayToRecord([policyData("policy1", "org6", PolicyType.SingleOrg, true)]),
);
const result = await firstValueFrom(
policyService.policyAppliesToUser$(PolicyType.SingleOrg, userId),
);
expect(result).toBe(false);
});
it("returns false for SingleOrg policy when user can manage policies and AutoConfirm is disabled", async () => {
singleUserState.nextState(
arrayToRecord([
policyData("policy1", "org6", PolicyType.SingleOrg, true),
policyData("policy2", "org6", PolicyType.AutoConfirm, false),
]),
);
const result = await firstValueFrom(
policyService.policyAppliesToUser$(PolicyType.SingleOrg, userId),
);
expect(result).toBe(false);
});
it("returns true for SingleOrg policy for regular users when AutoConfirm is not enabled", async () => {
singleUserState.nextState(
arrayToRecord([policyData("policy1", "org1", PolicyType.SingleOrg, true)]),
);
const result = await firstValueFrom(
policyService.policyAppliesToUser$(PolicyType.SingleOrg, userId),
);
expect(result).toBe(true);
});
it("returns true for SingleOrg policy when AutoConfirm is enabled in a different organization", async () => {
singleUserState.nextState(
arrayToRecord([
policyData("policy1", "org6", PolicyType.SingleOrg, true),
policyData("policy2", "org1", PolicyType.AutoConfirm, true),
]),
);
const result = await firstValueFrom(
policyService.policyAppliesToUser$(PolicyType.SingleOrg, userId),
);
expect(result).toBe(false);
});
});
});
describe("combinePoliciesIntoMasterPasswordPolicyOptions", () => {

View File

@@ -40,18 +40,16 @@ export class DefaultPolicyService implements PolicyService {
}
policiesByType$(policyType: PolicyType, userId: UserId) {
const filteredPolicies$ = this.policies$(userId).pipe(
map((policies) => policies.filter((p) => p.type === policyType)),
);
if (!userId) {
throw new Error("No userId provided");
}
const allPolicies$ = this.policies$(userId);
const organizations$ = this.organizationService.organizations$(userId);
return combineLatest([filteredPolicies$, organizations$]).pipe(
return combineLatest([allPolicies$, organizations$]).pipe(
map(([policies, organizations]) => this.enforcedPolicyFilter(policies, organizations)),
map((policies) => policies.filter((p) => p.type === policyType)),
);
}
@@ -77,7 +75,7 @@ export class DefaultPolicyService implements PolicyService {
policy.enabled &&
organization.status >= OrganizationUserStatusType.Accepted &&
organization.usePolicies &&
!this.isExemptFromPolicy(policy.type, organization)
!this.isExemptFromPolicy(policy.type, organization, policies)
);
});
}
@@ -265,7 +263,11 @@ export class DefaultPolicyService implements PolicyService {
* Determines whether an orgUser is exempt from a specific policy because of their role
* Generally orgUsers who can manage policies are exempt from them, but some policies are stricter
*/
private isExemptFromPolicy(policyType: PolicyType, organization: Organization) {
private isExemptFromPolicy(
policyType: PolicyType,
organization: Organization,
allPolicies: Policy[],
) {
switch (policyType) {
case PolicyType.MaximumVaultTimeout:
// Max Vault Timeout applies to everyone except owners
@@ -286,6 +288,14 @@ export class DefaultPolicyService implements PolicyService {
case PolicyType.OrganizationDataOwnership:
// organization data ownership policy applies to everyone except admins and owners
return organization.isAdmin;
case PolicyType.SingleOrg:
// Check if AutoConfirm policy is enabled for this organization
return allPolicies.find(
(p) =>
p.organizationId === organization.id && p.type === PolicyType.AutoConfirm && p.enabled,
)
? false
: organization.canManagePolicies;
default:
return organization.canManagePolicies;
}