Skip to content

Commit

Permalink
feat(rbac): allow editing permission policies (janus-idp#1037)
Browse files Browse the repository at this point in the history
feat(rbac): edit permission policies
  • Loading branch information
debsmita1 authored Jan 12, 2024
1 parent 993da38 commit c10347d
Show file tree
Hide file tree
Showing 33 changed files with 766 additions and 347 deletions.
12 changes: 6 additions & 6 deletions plugins/rbac/dev/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { TestApiProvider } from '@backstage/test-utils';

import {
PermissionPolicy,
Policy,
Role,
RoleBasedPolicy,
} from '@janus-idp/backstage-plugin-rbac-common';
Expand Down Expand Up @@ -71,9 +70,10 @@ class MockRBACApi implements RBACAPI {
return { status: 200 } as Response;
}

async updatePolicy(
_oldPolicy: RoleBasedPolicy,
_newPolicy: RoleBasedPolicy,
async updatePolicies(
_entityReference: string,
_oldPolicies: RoleBasedPolicy[],
_newPolicies: RoleBasedPolicy[],
): Promise<Response> {
return { status: 204 } as Response;
}
Expand All @@ -92,7 +92,7 @@ class MockRBACApi implements RBACAPI {

async deletePolicies(
_entityRef: string,
_policies: Policy[],
_policies: RoleBasedPolicy[],
): Promise<Response> {
return {
ok: true,
Expand All @@ -105,7 +105,7 @@ class MockRBACApi implements RBACAPI {
return { status: 200 } as Response;
}

async createPolicy(_data: any): Promise<Response> {
async createPolicies(_policies: RoleBasedPolicy[]): Promise<Response> {
return { status: 200 } as Response;
}
}
Expand Down
1 change: 1 addition & 0 deletions plugins/rbac/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"@backstage/plugin-permission-react": "^0.4.16",
"@backstage/theme": "^0.4.3",
"@janus-idp/backstage-plugin-rbac-common": "1.2.0",
"@janus-idp/shared-react": "2.3.0",
"@material-ui/core": "^4.9.13",
"@material-ui/icons": "^4.11.3",
"@material-ui/lab": "^4.0.0-alpha.45",
Expand Down
62 changes: 41 additions & 21 deletions plugins/rbac/src/api/RBACBackendClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ import {

import {
PermissionPolicy,
Policy,
Role,
RoleBasedPolicy,
} from '@janus-idp/backstage-plugin-rbac-common';

import { CreateRoleError, MemberEntity } from '../types';
import { MemberEntity, RoleError } from '../types';
import { getKindNamespaceName } from '../utils/rbac-utils';

// @public
Expand All @@ -23,17 +22,21 @@ export type RBACAPI = {
entityReference: string,
) => Promise<RoleBasedPolicy[] | Response>;
deleteRole: (role: string) => Promise<Response>;
deletePolicies: (role: string, policy: Policy[]) => Promise<Response>;
getRole: (role: string) => Promise<Role[] | Response>;
getMembers: () => Promise<MemberEntity[] | Response>;
listPermissions: () => Promise<PermissionPolicy[]>;
createRole: (role: Role) => Promise<CreateRoleError | Response>;
updateRole: (oldRole: Role, newRole: Role) => Promise<Response>;
updatePolicy: (
oldPolicy: RoleBasedPolicy,
newPolicy: RoleBasedPolicy,
) => Promise<Response>;
createPolicy: (data: any) => Promise<Response>;
listPermissions: () => Promise<PermissionPolicy[] | Response>;
createRole: (role: Role) => Promise<RoleError | Response>;
updateRole: (oldRole: Role, newRole: Role) => Promise<RoleError | Response>;
updatePolicies: (
entityReference: string,
oldPolicy: RoleBasedPolicy[],
newPolicy: RoleBasedPolicy[],
) => Promise<RoleError | Response>;
createPolicies: (polices: RoleBasedPolicy[]) => Promise<RoleError | Response>;
deletePolicies: (
entityReference: string,
polices: RoleBasedPolicy[],
) => Promise<RoleError | Response>;
};

export type Options = {
Expand Down Expand Up @@ -176,6 +179,9 @@ export class RBACBackendClient implements RBACAPI {
},
},
);
if (jsonResponse.status !== 200 && jsonResponse.status !== 204) {
return jsonResponse;
}
return jsonResponse.json();
}

Expand Down Expand Up @@ -217,21 +223,27 @@ export class RBACBackendClient implements RBACAPI {
body: JSON.stringify(body),
},
);
if (jsonResponse.status !== 200 && jsonResponse.status !== 201) {
if (
jsonResponse.status !== 200 &&
jsonResponse.status !== 201 &&
jsonResponse.status !== 204
) {
return jsonResponse.json();
}
return jsonResponse;
}

async updatePolicy(oldPolicy: RoleBasedPolicy, newPolicy: RoleBasedPolicy) {
async updatePolicies(
entityReference: string,
oldPolicies: RoleBasedPolicy[],
newPolicies: RoleBasedPolicy[],
) {
const { token: idToken } = await this.identityApi.getCredentials();
const backendUrl = this.configApi.getString('backend.baseUrl');
const { kind, namespace, name } = getKindNamespaceName(
oldPolicy.entityReference as string,
);
const { kind, namespace, name } = getKindNamespaceName(entityReference);
const body = {
oldPolicy,
newPolicy,
oldPolicy: oldPolicies,
newPolicy: newPolicies,
};
const jsonResponse = await fetch(
`${backendUrl}/api/permission/policies/${kind}/${namespace}/${name}`,
Expand All @@ -251,7 +263,7 @@ export class RBACBackendClient implements RBACAPI {
return jsonResponse;
}

async deletePolicies(entityReference: string, policies: Policy[]) {
async deletePolicies(entityReference: string, policies: RoleBasedPolicy[]) {
const { token: idToken } = await this.identityApi.getCredentials();
const backendUrl = this.configApi.getString('backend.baseUrl');
const { kind, namespace, name } = getKindNamespaceName(entityReference);
Expand All @@ -267,10 +279,18 @@ export class RBACBackendClient implements RBACAPI {
method: 'DELETE',
},
);

if (
jsonResponse.status !== 200 &&
jsonResponse.status !== 201 &&
jsonResponse.status !== 204
) {
return jsonResponse.json();
}
return jsonResponse;
}

async createPolicy(data: RoleBasedPolicy[]) {
async createPolicies(policies: RoleBasedPolicy[]) {
const { token: idToken } = await this.identityApi.getCredentials();
const backendUrl = this.configApi.getString('backend.baseUrl');
const jsonResponse = await fetch(`${backendUrl}/api/permission/policies`, {
Expand All @@ -280,7 +300,7 @@ export class RBACBackendClient implements RBACAPI {
Accept: 'application/json',
...(idToken && { Authorization: `Bearer ${idToken}` }),
},
body: JSON.stringify(data),
body: JSON.stringify(policies),
});
if (jsonResponse.status !== 200 && jsonResponse.status !== 201) {
return jsonResponse.json();
Expand Down
24 changes: 14 additions & 10 deletions plugins/rbac/src/components/CreateRole/AddMembersForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,21 @@ export const AddMembersForm = ({
};

const membersOptions: SelectedMember[] = membersData.members
? membersData.members.map((member: MemberEntity, index: number) => ({
label: member.spec?.profile?.displayName ?? member.metadata.name,
description: getDescription(member),
etag:
? membersData.members.map((member: MemberEntity, index: number) => {
const tag =
member.metadata.etag ??
`${member.metadata.name}-${member.kind}-${index}`,
type: member.kind,
namespace: member.metadata.namespace,
members: getMembersCount(member),
ref: stringifyEntityRef(member),
}))
`${member.metadata.name}-${member.kind}-${index}`;
return {
id: tag,
label: member.spec?.profile?.displayName ?? member.metadata.name,
description: getDescription(member),
etag: tag,
type: member.kind,
namespace: member.metadata.namespace,
members: getMembersCount(member),
ref: stringifyEntityRef(member),
};
})
: ([] as SelectedMember[]);

return (
Expand Down
2 changes: 1 addition & 1 deletion plugins/rbac/src/components/CreateRole/CreateRolePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const CreateRolePage = () => {
formTitle: 'Create Role',
nameAndDescriptionTitle: 'Enter name and description of role ',
usersAndGroupsTitle: 'Add users and groups',
permissionPoliciesTitle: '',
permissionPoliciesTitle: 'Add permission policies',
}}
membersData={{
members: Array.isArray(members)
Expand Down
27 changes: 12 additions & 15 deletions plugins/rbac/src/components/CreateRole/EditRolePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { catalogEntityReadPermission } from '@backstage/plugin-catalog-common/alpha';
import { RequirePermission } from '@backstage/plugin-permission-react';

import { usePermissionPolicies } from '../../hooks/usePermissionPolicies';
import { useSelectedMembers } from '../../hooks/useSelectedMembers';
import { RoleForm } from './RoleForm';
import { RoleFormValues } from './types';
Expand All @@ -24,44 +25,40 @@ export const EditRolePage = () => {
roleName ? `${roleKind}:${roleNamespace}/${roleName}` : '',
);

const { data: permissionPolicies } = usePermissionPolicies(
`${roleKind}:${roleNamespace}/${roleName}`,
);

const initialValues: RoleFormValues = {
name: roleName || '',
namespace: roleNamespace || 'default',
kind: roleKind || 'role',
description: '',
selectedMembers,
permissionPoliciesRows: [
{
plugin: '',
permission: '',
policies: [
{ label: 'Create', checked: false },
{ label: 'Read', checked: false },
{ label: 'Update', checked: false },
{ label: 'Delete', checked: false },
],
},
],
permissionPoliciesRows: permissionPolicies,
};
const renderPage = () => {
if (loading) {
return <Progress />;
} else if (roleError?.name) {
return (
<ErrorPage status={roleError.name} statusMessage={roleError.message} />
<ErrorPage
status={roleError?.name}
statusMessage={roleError?.message}
/>
);
}
return (
<>
<Header title="Edit Role" />
<Header title="Edit role" type="RBAC" typeLink="/rbac" />
<Content>
<RoleForm
initialValues={initialValues}
titles={{
formTitle: 'Edit Role',
nameAndDescriptionTitle: 'Edit name and description of role ',
usersAndGroupsTitle: 'Edit users and groups',
permissionPoliciesTitle: '',
permissionPoliciesTitle: 'Edit permission policies',
}}
roleName={
roleName ? `${roleKind}:${roleNamespace}/${roleName}` : ''
Expand Down
Loading

0 comments on commit c10347d

Please sign in to comment.