1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-22 03:03:43 +00:00
Files
browser/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy.service.spec.ts
2025-05-09 00:36:07 +02:00

362 lines
12 KiB
TypeScript

// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { mock } from "jest-mock-extended";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { CsprngArray } from "@bitwarden/common/types/csprng";
import { OrgKey } from "@bitwarden/common/types/key";
import { KeyService } from "@bitwarden/key-management";
import {
GroupAccessPolicyView,
ServiceAccountAccessPolicyView,
UserAccessPolicyView,
} from "../../models/view/access-policies/access-policy.view";
import { ProjectPeopleAccessPoliciesView } from "../../models/view/access-policies/project-people-access-policies.view";
import { ProjectServiceAccountsAccessPoliciesView } from "../../models/view/access-policies/project-service-accounts-access-policies.view";
import {
GrantedProjectPolicyPermissionDetailsView,
ServiceAccountGrantedPoliciesView,
} from "../../models/view/access-policies/service-account-granted-policies.view";
import { ServiceAccountPeopleAccessPoliciesView } from "../../models/view/access-policies/service-account-people-access-policies.view";
import { AccessPolicyService } from "./access-policy.service";
import { PeopleAccessPoliciesRequest } from "./models/requests/people-access-policies.request";
import { ProjectServiceAccountsAccessPoliciesRequest } from "./models/requests/project-service-accounts-access-policies.request";
import { ServiceAccountGrantedPoliciesRequest } from "./models/requests/service-account-granted-policies.request";
import { trackEmissions } from "@bitwarden/common/../spec";
describe("AccessPolicyService", () => {
let sut: AccessPolicyService;
const keyService = mock<KeyService>();
const apiService = mock<ApiService>();
const encryptService = mock<EncryptService>();
beforeEach(() => {
jest.resetAllMocks();
sut = new AccessPolicyService(keyService, apiService, encryptService);
});
it("instantiates", () => {
expect(sut).not.toBeFalsy();
});
describe("putProjectPeopleAccessPolicies", () => {
it("emits the updated policies", async () => {
const userAccessPolicyView1 = createUserAccessPolicyView(false, true);
const userAccessPolicyView2 = createUserAccessPolicyView(true, false);
const groupAccessPolicyView1 = createGroupAccessPolicyView(false, true);
const groupAccessPolicyView2 = createGroupAccessPolicyView(true, false);
const view = {
userAccessPolicies: [userAccessPolicyView1, userAccessPolicyView2],
groupAccessPolicies: [groupAccessPolicyView1, groupAccessPolicyView2],
} as ProjectPeopleAccessPoliciesView;
apiService.send.mockResolvedValue(toProjectPeopleAccessPoliciesResponseRaw(view));
const emissions = trackEmissions(sut.accessPolicy$);
const expectedRequest = toPeopleAccessPoliciesRequest(view);
const projectId = Utils.newGuid();
const result = await sut.putProjectPeopleAccessPolicies(projectId, view);
expect(result).toEqual(view);
expect(apiService.send).toHaveBeenCalledWith(
"PUT",
"/projects/" + projectId + "/access-policies/people",
expectedRequest,
true,
true,
);
expect(emissions).toEqual([view]);
});
});
describe("putServiceAccountPeopleAccessPolicies", () => {
it("emits the updated policies", async () => {
const userAccessPolicyView1 = createUserAccessPolicyView(false, true);
const userAccessPolicyView2 = createUserAccessPolicyView(true, false);
const groupAccessPolicyView1 = createGroupAccessPolicyView(false, true);
const groupAccessPolicyView2 = createGroupAccessPolicyView(true, false);
const view = {
userAccessPolicies: [userAccessPolicyView1, userAccessPolicyView2],
groupAccessPolicies: [groupAccessPolicyView1, groupAccessPolicyView2],
} as ServiceAccountPeopleAccessPoliciesView;
apiService.send.mockResolvedValue(toServiceAccountPeopleAccessPoliciesResponseRaw(view));
const emissions = trackEmissions(sut.accessPolicy$);
const expectedRequest = toPeopleAccessPoliciesRequest(view);
const projectId = Utils.newGuid();
const result = await sut.putServiceAccountPeopleAccessPolicies(projectId, view);
expect(result).toEqual(view);
expect(apiService.send).toHaveBeenCalledWith(
"PUT",
"/service-accounts/" + projectId + "/access-policies/people",
expectedRequest,
true,
true,
);
expect(emissions).toEqual([view]);
});
});
describe("putServiceAccountGrantedPolicies", () => {
it("emits the updated policies", async () => {
const policyPermissionDetailsView1 = createGrantedProjectPolicyPermissionDetailsView(
false,
false,
);
const policyPermissionDetailsView2 = createGrantedProjectPolicyPermissionDetailsView(
false,
true,
);
const policyPermissionDetailsView3 = createGrantedProjectPolicyPermissionDetailsView(
true,
true,
);
const view = {
grantedProjectPolicies: [
policyPermissionDetailsView1,
policyPermissionDetailsView2,
policyPermissionDetailsView3,
],
} as ServiceAccountGrantedPoliciesView;
apiService.send.mockResolvedValue(toServiceAccountGrantedPoliciesResponseRaw(view));
const emissions = trackEmissions(sut.accessPolicy$);
const expectedRequest = toServiceAccountGrantedPoliciesRequest(view);
const mockRandomBytes = new Uint8Array(64) as CsprngArray;
const mockOrgKey = new SymmetricCryptoKey(mockRandomBytes) as OrgKey;
keyService.getOrgKey.mockResolvedValue(mockOrgKey);
encryptService.decryptString.mockImplementation((c) => Promise.resolve(c.encryptedString));
const organizationId = Utils.newGuid();
const serviceAccountId = Utils.newGuid();
const result = await sut.putServiceAccountGrantedPolicies(
organizationId,
serviceAccountId,
view,
);
expect(result).toEqual(view);
expect(apiService.send).toHaveBeenCalledWith(
"PUT",
"/service-accounts/" + serviceAccountId + "/granted-policies",
expectedRequest,
true,
true,
);
expect(emissions).toEqual([view]);
});
});
describe("putProjectServiceAccountsAccessPolicies", () => {
it("emits the updated policies", async () => {
const accessPolicyView1 = createServiceAccountAccessPolicyView(false);
const accessPolicyView2 = createServiceAccountAccessPolicyView(true);
const view = {
serviceAccountAccessPolicies: [accessPolicyView1, accessPolicyView2],
} as ProjectServiceAccountsAccessPoliciesView;
apiService.send.mockResolvedValue(toProjectServiceAccountsAccessPoliciesResponseRaw(view));
const emissions = trackEmissions(sut.accessPolicy$);
const expectedRequest = toProjectServiceAccountsAccessPoliciesRequest(view);
const mockRandomBytes = new Uint8Array(64) as CsprngArray;
const mockOrgKey = new SymmetricCryptoKey(mockRandomBytes) as OrgKey;
keyService.getOrgKey.mockResolvedValue(mockOrgKey);
encryptService.decryptString.mockImplementation((c) => Promise.resolve(c.encryptedString));
const organizationId = Utils.newGuid();
const projectId = Utils.newGuid();
const result = await sut.putProjectServiceAccountsAccessPolicies(
organizationId,
projectId,
view,
);
expect(result).toEqual(view);
expect(apiService.send).toHaveBeenCalledWith(
"PUT",
"/projects/" + projectId + "/access-policies/service-accounts",
expectedRequest,
true,
true,
);
expect(emissions).toEqual([view]);
});
});
});
function createUserAccessPolicyView(isWrite: boolean, currentUser: boolean): UserAccessPolicyView {
const id = Utils.newGuid();
return {
organizationUserId: id,
organizationUserName: "Example organization user name " + id,
read: true,
write: isWrite,
currentUser: currentUser,
};
}
function createGroupAccessPolicyView(
isWrite: boolean,
currentUserInGroup: boolean,
): GroupAccessPolicyView {
const id = Utils.newGuid();
return {
groupId: id,
groupName: "Example group name " + id,
currentUserInGroup: currentUserInGroup,
read: true,
write: isWrite,
};
}
function createServiceAccountAccessPolicyView(isWrite: boolean): ServiceAccountAccessPolicyView {
const id = Utils.newGuid();
return {
serviceAccountId: id,
serviceAccountName: "Example service account name " + id,
read: true,
write: isWrite,
};
}
function createGrantedProjectPolicyPermissionDetailsView(
isWrite: boolean,
hasPermissions: boolean,
): GrantedProjectPolicyPermissionDetailsView {
const id = Utils.newGuid();
return {
accessPolicy: {
grantedProjectId: id,
grantedProjectName: "Example project name " + id,
read: true,
write: isWrite,
},
hasPermission: hasPermissions,
};
}
function toPeopleAccessPoliciesRequest(
view: ProjectPeopleAccessPoliciesView | ServiceAccountPeopleAccessPoliciesView,
): PeopleAccessPoliciesRequest {
return {
userAccessPolicyRequests: view.userAccessPolicies.map((ap) => ({
granteeId: ap.organizationUserId,
read: ap.read,
write: ap.write,
})),
groupAccessPolicyRequests: view.groupAccessPolicies.map((ap) => ({
granteeId: ap.groupId,
read: ap.read,
write: ap.write,
})),
};
}
function toServiceAccountGrantedPoliciesRequest(
view: ServiceAccountGrantedPoliciesView,
): ServiceAccountGrantedPoliciesRequest {
return {
projectGrantedPolicyRequests: view.grantedProjectPolicies.map((ap) => ({
grantedId: ap.accessPolicy.grantedProjectId,
read: ap.accessPolicy.read,
write: ap.accessPolicy.write,
})),
};
}
function toProjectServiceAccountsAccessPoliciesRequest(
view: ProjectServiceAccountsAccessPoliciesView,
): ProjectServiceAccountsAccessPoliciesRequest {
return {
serviceAccountAccessPolicyRequests: view.serviceAccountAccessPolicies.map((ap) => {
return {
granteeId: ap.serviceAccountId,
read: ap.read,
write: ap.write,
};
}),
};
}
function toProjectPeopleAccessPoliciesResponseRaw(view: ProjectPeopleAccessPoliciesView) {
return {
userAccessPolicies: view.userAccessPolicies.map((ap) => ({
organizationUserId: ap.organizationUserId,
organizationUserName: ap.organizationUserName,
currentUser: ap.currentUser,
read: ap.read,
write: ap.write,
})),
groupAccessPolicies: view.groupAccessPolicies.map((ap) => ({
groupId: ap.groupId,
groupName: ap.groupName,
currentUserInGroup: ap.currentUserInGroup,
read: ap.read,
write: ap.write,
})),
};
}
function toServiceAccountPeopleAccessPoliciesResponseRaw(
view: ServiceAccountPeopleAccessPoliciesView,
) {
return {
userAccessPolicies: view.userAccessPolicies.map((ap) => ({
organizationUserId: ap.organizationUserId,
organizationUserName: ap.organizationUserName,
currentUser: ap.currentUser,
read: ap.read,
write: ap.write,
})),
groupAccessPolicies: view.groupAccessPolicies.map((ap) => ({
groupId: ap.groupId,
groupName: ap.groupName,
currentUserInGroup: ap.currentUserInGroup,
read: ap.read,
write: ap.write,
})),
};
}
function toServiceAccountGrantedPoliciesResponseRaw(view: ServiceAccountGrantedPoliciesView) {
return {
grantedProjectPolicies: view.grantedProjectPolicies.map((ap) => ({
accessPolicy: {
grantedProjectId: ap.accessPolicy.grantedProjectId,
grantedProjectName: ap.accessPolicy.grantedProjectName,
read: ap.accessPolicy.read,
write: ap.accessPolicy.write,
},
hasPermission: ap.hasPermission,
})),
};
}
function toProjectServiceAccountsAccessPoliciesResponseRaw(
view: ProjectServiceAccountsAccessPoliciesView,
) {
return {
serviceAccountAccessPolicies: view.serviceAccountAccessPolicies.map((ap) => ({
serviceAccountId: ap.serviceAccountId,
serviceAccountName: ap.serviceAccountName,
currentUser: true,
read: ap.read,
write: ap.write,
})),
};
}