Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions src/providers/casbin-authorization-action.provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {Getter, inject, Provider} from '@loopback/core';
import {Request} from '@loopback/express';
import {HttpErrors} from '@loopback/rest';
import * as casbin from 'casbin';

import {AuthorizationBindings} from '../keys';
import {
AuthorizationMetadata,
Expand Down Expand Up @@ -63,15 +62,7 @@ export class CasbinAuthorizationProvider
}
const subject = this.getUserName(`${user.id}`);

let desiredPermissions;

if (metadata.permissions && metadata.permissions.length > 0) {
desiredPermissions = metadata.permissions;
} else {
throw new HttpErrors.Unauthorized(
`Permissions are missing in the decorator.`,
);
}
const desiredPermissions = this.getDesiredPermissions(metadata);

// Fetch casbin config by invoking casbin-config-getter-provider
const casbinConfig = await this.getCasbinEnforcerConfig(
Expand All @@ -90,7 +81,7 @@ export class CasbinAuthorizationProvider
);
}
// In case casbin policy is coming via provider, use that to initialise enforcer
else if (!metadata.isCasbinPolicy && casbinConfig.allowedRes) {
else if (casbinConfig.allowedRes) {
const policy = this.createCasbinPolicy(
casbinConfig.allowedRes,
subject,
Expand Down Expand Up @@ -124,6 +115,16 @@ export class CasbinAuthorizationProvider
return `u${id}`;
}

getDesiredPermissions(metadata: AuthorizationMetadata): Array<string> {
if (metadata.permissions && metadata.permissions.length > 0) {
return metadata.permissions;
} else {
throw new HttpErrors.Unauthorized(
`Permissions are missing in the decorator.`,
);
}
}

// Create casbin policy for user based on ResourcePermission data provided by extension client
createCasbinPolicy(
resPermObj: ResourcePermissionObject[],
Expand Down
6 changes: 1 addition & 5 deletions src/providers/casbin-enforcer-config.provider.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import {Provider} from '@loopback/context';

import {CasbinEnforcerConfigGetterFn, IAuthUserWithPermissions} from '../types';
import {HttpErrors} from '@loopback/rest';
import {CasbinEnforcerConfigGetterFn, IAuthUserWithPermissions} from '../types';

export class CasbinEnforcerProvider
implements Provider<CasbinEnforcerConfigGetterFn>
{
constructor() {
//This is intentional
}

value(): CasbinEnforcerConfigGetterFn {
return async (
authUser: IAuthUserWithPermissions,
Expand Down
4 changes: 0 additions & 4 deletions src/providers/user-permissions.provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ import {UserPermission, UserPermissionsFn} from '../types';
export class UserPermissionsProvider
implements Provider<UserPermissionsFn<string>>
{
constructor() {
//This is intentional
}

value(): UserPermissionsFn<string> {
return (userPermissions, rolePermissions) =>
this.action(userPermissions, rolePermissions);
Expand Down
68 changes: 35 additions & 33 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,29 @@ import {FileAdapter, Model} from 'casbin';
import PostgresAdapter from 'casbin-pg-adapter';

/**
* Authorize action method interface
* Authorize action method type
*
* @param userPermissions - Array of permission keys granted to the user
* This is actually a union of permissions picked up based on role
* attached to the user and allowed permissions at specific user level
*/
export interface AuthorizeFn {
// userPermissions - Array of permission keys granted to the user
// This is actually a union of permissions picked up based on role
// attached to the user and allowed permissions at specific user level
(userPermissions: string[], request?: Request): Promise<boolean>;
}
export type AuthorizeFn = (
userPermissions: string[],
request?: Request,
) => Promise<boolean>;

/**
* Casbin authorize action method interface
* Casbin authorize action method type
* @param user - User object corresponding to the logged in user
* @param resVal - value of the resource for which authorisation is being sought
*
*/
export interface CasbinAuthorizeFn {
// user - User object corresponding to the logged in user
// resVal - value of the resource for which authorisation is being sought
(
user: IAuthUserWithPermissions,
resVal: string,
request: Request,
): Promise<boolean>;
}
export type CasbinAuthorizeFn = (
user: IAuthUserWithPermissions,
resVal: string,
request: Request,
) => Promise<boolean>;

export type PermissionObject = {
[controller: string]: {
[method: string]: string[];
Expand Down Expand Up @@ -82,40 +84,40 @@ export interface UserPermission<T> {
}

/**
* User permissions manipulation method interface.
* User permissions manipulation method type.
*
* This is where we can add our business logic to read and
* union permissions associated to user via role with
* those associated directly to the user.
*
*/
export interface UserPermissionsFn<T> {
(userPermissions: UserPermission<T>[], rolePermissions: T[]): T[];
}
export type UserPermissionsFn<T> = (
userPermissions: UserPermission<T>[],
rolePermissions: T[],
) => T[];

/**
* Casbin enforcer getter method interface
* Casbin enforcer getter method type
*
* This method provides the Casbin config
* required to initialise a Casbin enforcer
*/
export interface CasbinEnforcerConfigGetterFn {
(
authUser: IAuthUserWithPermissions,
resource: string,
isCasbinPolicy?: boolean,
): Promise<CasbinConfig>;
}
export type CasbinEnforcerConfigGetterFn = (
authUser: IAuthUserWithPermissions,
resource: string,
isCasbinPolicy?: boolean,
) => Promise<CasbinConfig>;

/**
* Casbin resource value modifier method interface
* Casbin resource value modifier method type
*
* This method can help modify the resource value
* for integration with casbin, as per business logic
*/
export interface CasbinResourceModifierFn {
(pathParams: string[], req: Request): Promise<string>;
}
export type CasbinResourceModifierFn = (
pathParams: string[],
req: Request,
) => Promise<string>;

/**
* Casbin config object
Expand Down