Skip to content

Commit 80bccd3

Browse files
author
vineet-suri
committed
RFIT-188 code review comments fixed
1 parent 40f6ae5 commit 80bccd3

File tree

8 files changed

+2480
-1384
lines changed

8 files changed

+2480
-1384
lines changed

package-lock.json

Lines changed: 2343 additions & 1282 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@
4545
"!*/__tests__"
4646
],
4747
"peerDependencies": {
48-
"@loopback/boot": "^1.4.4",
49-
"@loopback/context": "^1.20.2",
50-
"@loopback/core": "^1.8.5",
51-
"@loopback/rest": "^1.16.3"
48+
"@loopback/boot": "^1.7.4",
49+
"@loopback/context": "^3.11.2",
50+
"@loopback/core": "^2.10.0",
51+
"@loopback/rest": "^1.26.1"
5252
},
5353
"dependencies": {
5454
"@sourceloop/core": "^1.0.0-alpha.9",
@@ -57,12 +57,12 @@
5757
"lodash": "^4.17.15"
5858
},
5959
"devDependencies": {
60-
"@loopback/boot": "^1.4.4",
61-
"@loopback/build": "^2.0.3",
62-
"@loopback/context": "^3.8.2",
63-
"@loopback/core": "^2.9.5",
64-
"@loopback/rest": "^1.16.3",
65-
"@loopback/testlab": "^1.6.3",
60+
"@loopback/boot": "^1.7.4",
61+
"@loopback/build": "^2.1.0",
62+
"@loopback/context": "^3.11.0",
63+
"@loopback/core": "^2.10.0",
64+
"@loopback/rest": "^1.26.1",
65+
"@loopback/testlab": "^1.10.3",
6666
"@loopback/tslint-config": "^2.1.0",
6767
"@types/lodash": "^4.14.135",
6868
"@types/node": "^10.14.8",

src/component.ts

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1-
import { bind, Binding, Component, ContextTags, CoreBindings, inject, ProviderMap } from '@loopback/core';
2-
import { RestApplication } from '@loopback/rest';
3-
import { AuthorizationBindings } from './keys';
4-
import { AuthorizeActionProvider } from './providers/authorization-action.provider';
5-
import { AuthorizationMetadataProvider } from './providers/authorization-metadata.provider';
6-
import { CasbinAuthorizationProvider } from './providers/casbin-authorization-action.provider';
7-
import { UserPermissionsProvider } from './providers/user-permissions.provider';
8-
import { AuthorizationConfig } from './types';
1+
import {
2+
Binding,
3+
Component,
4+
CoreBindings,
5+
inject,
6+
ProviderMap,
7+
} from '@loopback/core';
8+
import {RestApplication} from '@loopback/rest';
9+
import {AuthorizationBindings} from './keys';
10+
import {AuthorizeActionProvider} from './providers/authorization-action.provider';
11+
import {AuthorizationMetadataProvider} from './providers/authorization-metadata.provider';
12+
import {CasbinAuthorizationProvider} from './providers/casbin-authorization-action.provider';
13+
import {UserPermissionsProvider} from './providers/user-permissions.provider';
14+
import {AuthorizationConfig} from './types';
915

10-
11-
@bind({ tags: { [ContextTags.KEY]: AuthorizationBindings.COMPONENT.key } })
1216
export class AuthorizationComponent implements Component {
1317
providers?: ProviderMap;
14-
bindings1?: Binding[];
18+
bindings?: Binding[];
1519

1620
constructor(
1721
@inject(CoreBindings.APPLICATION_INSTANCE)
@@ -21,24 +25,24 @@ export class AuthorizationComponent implements Component {
2125
) {
2226
this.providers = {
2327
[AuthorizationBindings.AUTHORIZE_ACTION.key]: AuthorizeActionProvider,
24-
[AuthorizationBindings.CASBIN_AUTHORIZE_ACTION.key]: CasbinAuthorizationProvider,
28+
[AuthorizationBindings.CASBIN_AUTHORIZE_ACTION
29+
.key]: CasbinAuthorizationProvider,
2530
[AuthorizationBindings.METADATA.key]: AuthorizationMetadataProvider,
2631
[AuthorizationBindings.USER_PERMISSIONS.key]: UserPermissionsProvider,
2732
};
2833

29-
3034
if (
3135
config &&
3236
config.allowAlwaysPaths &&
3337
config.allowAlwaysPaths.length > 0
3438
) {
35-
this.bindings1 = [
39+
this.bindings = [
3640
Binding.bind(AuthorizationBindings.PATHS_TO_ALLOW_ALWAYS).to(
3741
config.allowAlwaysPaths,
3842
),
3943
];
4044
} else {
41-
this.bindings1 = [
45+
this.bindings = [
4246
Binding.bind(AuthorizationBindings.PATHS_TO_ALLOW_ALWAYS).to([
4347
'/explorer',
4448
]),
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import { MethodDecoratorFactory } from '@loopback/core';
2-
import { AuthorizationMetadata } from '../types';
3-
import { AUTHORIZATION_METADATA_ACCESSOR } from '../keys';
1+
import {MethodDecoratorFactory} from '@loopback/core';
2+
import {AuthorizationMetadata} from '../types';
3+
import {AUTHORIZATION_METADATA_ACCESSOR} from '../keys';
44

55
export function authorize(metadata: AuthorizationMetadata) {
66
return MethodDecoratorFactory.createDecorator<AuthorizationMetadata>(
77
AUTHORIZATION_METADATA_ACCESSOR,
88
{
99
permissions: metadata.permissions || [],
1010
resource: metadata.resource || '',
11-
isCasbinPolicy: metadata.isCasbinPolicy || false
11+
isCasbinPolicy: metadata.isCasbinPolicy || false,
1212
},
1313
);
1414
}

src/keys.ts

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,25 @@
1-
import { BindingKey } from '@loopback/context';
2-
import { MetadataAccessor } from '@loopback/metadata';
1+
import {BindingKey} from '@loopback/context';
2+
import {MetadataAccessor} from '@loopback/metadata';
33
import {
44
AuthorizeFn,
55
AuthorizationMetadata,
66
UserPermissionsFn,
77
AuthorizationConfig,
8-
CasbinEnforcerFn,
98
CasbinAuthorizeFn,
109
CasbinEnforcerConfigGetterFn,
1110
CasbinResourceModifierFn,
1211
} from './types';
13-
import { CoreBindings } from '@loopback/core';
14-
import { AuthorizationComponent } from './component';
1512

1613
/**
1714
* Binding keys used by this component.
1815
*/
1916
export namespace AuthorizationBindings {
20-
21-
export const COMPONENT = BindingKey.create<AuthorizationComponent>(
22-
`${CoreBindings.COMPONENTS}.AuthorizationComponent`,
23-
);
24-
2517
export const AUTHORIZE_ACTION = BindingKey.create<AuthorizeFn>(
2618
'sf.userAuthorization.actions.authorize',
2719
);
2820

2921
export const CASBIN_AUTHORIZE_ACTION = BindingKey.create<CasbinAuthorizeFn>(
30-
'sf.userCasbinAuthorization.actions.authorize',
22+
'sf.userAuthorization.actions.casbin.authorize',
3123
);
3224

3325
export const METADATA = BindingKey.create<AuthorizationMetadata | undefined>(
@@ -38,31 +30,22 @@ export namespace AuthorizationBindings {
3830
'sf.userAuthorization.actions.userPermissions',
3931
);
4032

41-
export const CASBIN_ENFORCER = BindingKey.create<CasbinEnforcerFn<string>>(
42-
'sf.userCasbinAuthorization.casbinenforcer',
43-
);
33+
export const CASBIN_ENFORCER_CONFIG_GETTER = BindingKey.create<
34+
CasbinEnforcerConfigGetterFn
35+
>('sf.userAuthorization.actions.casbin.config');
4436

45-
export const CASBIN_ENFORCER_CONFIG_GETTER = BindingKey.create<CasbinEnforcerConfigGetterFn>(
46-
'sf.userCasbinAuthorization.casbinEnforcerConfigGetter',
47-
);
48-
49-
export const CASBIN_RESOURCE_MODIFIER_FN = BindingKey.create<CasbinResourceModifierFn>(
50-
'sf.userCasbinAuthorization.casbinResourceModifierFn',
51-
);
37+
export const CASBIN_RESOURCE_MODIFIER_FN = BindingKey.create<
38+
CasbinResourceModifierFn
39+
>('sf.userAuthorization.actions.casbin.resourceModifier');
5240

5341
export const CONFIG = BindingKey.create<AuthorizationConfig>(
5442
'sf.userAuthorization.config',
5543
);
5644

5745
export const PATHS_TO_ALLOW_ALWAYS = 'sf.userAuthorization.allowAlways';
58-
59-
60-
export const RESOURCE_ID = BindingKey.create<string>('sf.resourceId');
6146
}
6247

6348
export const AUTHORIZATION_METADATA_ACCESSOR = MetadataAccessor.create<
6449
AuthorizationMetadata,
6550
MethodDecorator
6651
>('sf.userAuthorization.accessor.operationMetadata');
67-
68-

src/providers/casbin-authorization-action.provider.ts

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,86 @@
1-
import { Getter, inject, Provider } from '@loopback/core';
2-
import { IAuthUserWithPermissions } from '@sourceloop/core';
1+
import {Getter, inject, Provider} from '@loopback/core';
2+
import {IAuthUserWithPermissions} from '@sourceloop/core';
33
import * as casbin from 'casbin';
44
import * as fs from 'fs';
55
import * as path from 'path';
6-
import { AuthorizationBindings } from '../keys';
7-
import { AuthorizationMetadata, CasbinAuthorizeFn, CasbinEnforcerConfigGetterFn } from '../types';
6+
import {AuthorizationBindings} from '../keys';
7+
import {
8+
AuthorizationMetadata,
9+
CasbinAuthorizeFn,
10+
CasbinEnforcerConfigGetterFn,
11+
} from '../types';
812
const fsPromises = fs.promises;
913

1014
const DEFAULT_SCOPE = 'execute';
1115

12-
export class CasbinAuthorizationProvider implements Provider<CasbinAuthorizeFn> {
16+
export class CasbinAuthorizationProvider
17+
implements Provider<CasbinAuthorizeFn> {
1318
constructor(
1419
@inject.getter(AuthorizationBindings.METADATA)
1520
private readonly getCasbinMetadata: Getter<AuthorizationMetadata>,
1621
@inject.getter(AuthorizationBindings.CASBIN_ENFORCER_CONFIG_GETTER)
17-
private readonly getCasbinEnforcerConfig: Getter<CasbinEnforcerConfigGetterFn>,
18-
) { }
22+
private readonly getCasbinEnforcerConfig: Getter<
23+
CasbinEnforcerConfigGetterFn
24+
>,
25+
) {}
1926

2027
value(): CasbinAuthorizeFn {
2128
return (response, resource) => this.action(response, resource);
2229
}
2330

24-
async action(user: IAuthUserWithPermissions, resource: string): Promise<boolean> {
31+
async action(
32+
user: IAuthUserWithPermissions,
33+
resource: string,
34+
): Promise<boolean> {
2535
let authDecision = false;
2636
try {
37+
// fetch decorator metadata
2738
const metadata: AuthorizationMetadata = await this.getCasbinMetadata();
2839

40+
if (!metadata.resource) {
41+
return false;
42+
}
43+
2944
const subject = this.getUserName(`${user.id}`);
3045

3146
const object = resource;
3247

33-
const action = metadata.permissions && metadata.permissions.length > 0 ? metadata.permissions[0] : DEFAULT_SCOPE;
48+
const action =
49+
metadata.permissions && metadata.permissions.length > 0
50+
? metadata.permissions[0]
51+
: DEFAULT_SCOPE;
3452

53+
// Fetch casbin config by invoking casbin-config-getter-provider
3554
const fn = await this.getCasbinEnforcerConfig();
3655

37-
const result = await fn(user, metadata.resource);
56+
const casbinConfig = await fn(user, metadata.resource);
3857

3958
let enforcer: casbin.Enforcer;
4059

60+
// If casbin config policy format is being used, create enforcer
4161
if (metadata.isCasbinPolicy) {
42-
enforcer = await casbin.newEnforcer(result.model, result.policy);
43-
} else if (!metadata.isCasbinPolicy && result.allowedRes) {
44-
const policy = this.createCasbinPolicy(result.allowedRes, subject, action);
62+
enforcer = await casbin.newEnforcer(
63+
casbinConfig.model,
64+
casbinConfig.policy,
65+
);
66+
}
67+
// In case casbin policy is coming via provider, use that to initialise enforcer
68+
else if (!metadata.isCasbinPolicy && casbinConfig.allowedRes) {
69+
const policy = this.createCasbinPolicy(
70+
casbinConfig.allowedRes,
71+
subject,
72+
action,
73+
);
4574
const baseDir = path.join(__dirname, '../../src/policy.csv');
4675
await fsPromises.writeFile(baseDir, policy);
4776

48-
enforcer = await casbin.newEnforcer(result.model, baseDir);
77+
enforcer = await casbin.newEnforcer(casbinConfig.model, baseDir);
4978
} else {
5079
return false;
5180
}
5281

53-
authDecision = await enforcer.enforce(
54-
subject,
55-
object,
56-
action,
57-
);
58-
}
59-
60-
catch (err) {
82+
authDecision = await enforcer.enforce(subject, object, action);
83+
} catch (err) {
6184
console.log(err);
6285
}
6386

@@ -71,15 +94,19 @@ export class CasbinAuthorizationProvider implements Provider<CasbinAuthorizeFn>
7194
return `u${id}`;
7295
}
7396

74-
createCasbinPolicy(allowedRes: string[], subject: string, action: string): string {
97+
createCasbinPolicy(
98+
allowedRes: string[],
99+
subject: string,
100+
action: string,
101+
): string {
75102
//Expected format for allowedRes: ['ping', 'ping2', 'ping3'];
76103

77104
let result = '';
78105
allowedRes.forEach(res => {
79106
const policy = `p, ${subject}, ${res}, ${action}
80107
`;
81108
result += policy;
82-
})
109+
});
83110

84111
return result;
85112
}

src/providers/casbin-enforcer-config.provider.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
import { Provider } from '@loopback/context';
1+
import {Provider} from '@loopback/context';
22

3-
import { CasbinEnforcerConfigGetterFn } from '../types';
4-
import { IAuthUserWithPermissions } from '@sourceloop/core';
5-
import { HttpErrors } from '@loopback/rest';
3+
import {CasbinEnforcerConfigGetterFn} from '../types';
4+
import {IAuthUserWithPermissions} from '@sourceloop/core';
5+
import {HttpErrors} from '@loopback/rest';
66

77
export class CasbinEnforcerProvider
88
implements Provider<CasbinEnforcerConfigGetterFn> {
9-
constructor() { }
9+
constructor() {}
1010

1111
value(): CasbinEnforcerConfigGetterFn {
12-
return async (authUser: IAuthUserWithPermissions, resource: string, isCasbinPolicy?: boolean) => {
12+
return async (
13+
authUser: IAuthUserWithPermissions,
14+
resource: string,
15+
isCasbinPolicy?: boolean,
16+
) => {
1317
throw new HttpErrors.NotImplemented(
1418
`CasbinEnforcerConfigGetterFn Provider is not implemented`,
1519
);

0 commit comments

Comments
 (0)