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
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,3 @@
node_modules
lib
yarn-error.log

package-lock.json
yarn.lock
6 changes: 4 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ language: node_js
sudo: false

node_js:
- 'stable'
- '8'
- '6'
- '10'
- '11'
- '12'
- 'stable'

install: yarn install

Expand Down
2 changes: 1 addition & 1 deletion examples/rbac_policy.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ p, alice, data1, read
p, bob, data2, write
p, data2_admin, data2, read
p, data2_admin, data2, write
g, alice, data2_admin
g, alice, data2_admin
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,26 @@
"scripts": {
"precommit": "lint-staged",
"prepublishOnly": "yarn run lint && yarn run test && yarn build",
"build": "rimraf lib && tsc",
"lint": "tslint \"src/**/*.ts\"",
"build": "rimraf lib && tsc -p tsconfig.release.json",
"lint": "tslint -p . -c tslint.json",
"test": "jest"
},
"devDependencies": {
"@types/ip": "^0.0.31",
"@types/jest": "^23.3.1",
"@types/jest": "^24.0.11",
"@types/lodash": "^4.14.113",
"@types/node": "^10.5.3",
"coveralls": "^3.0.2",
"husky": "^0.14.3",
"jest": "^23.4.2",
"jest": "^24.3.1",
"lint-staged": "^7.2.0",
"rimraf": "^2.6.2",
"ts-jest": "22.4.6",
"ts-jest": "^24.0.0",
"tslint": "^5.11.0",
"typescript": "^3.3.3"
"typescript": "^3.4.5"
},
"dependencies": {
"expression-eval": "^1.3.0",
"expression-eval": "^2.0.0",
"ip": "^1.1.5",
"lodash": "^4.17.10"
},
Expand Down
228 changes: 114 additions & 114 deletions src/coreEnforcer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { compile } from 'expression-eval';
import { compileAsync } from 'expression-eval';
import * as _ from 'lodash';

import { DefaultEffector, Effect, Effector } from './effect';
Expand Down Expand Up @@ -143,7 +143,7 @@ export class CoreEnforcer {

this.model.printPolicy();
if (this.autoBuildRoleLinks) {
this.buildRoleLinks();
await this.buildRoleLinks();
}
}

Expand All @@ -163,7 +163,7 @@ export class CoreEnforcer {

this.model.printPolicy();
if (this.autoBuildRoleLinks) {
this.buildRoleLinks();
await this.buildRoleLinks();
}
return true;
}
Expand Down Expand Up @@ -241,10 +241,10 @@ export class CoreEnforcer {
* buildRoleLinks manually rebuild the
* role inheritance relations.
*/
public buildRoleLinks() {
public async buildRoleLinks(): Promise<void> {
// error intentionally ignored
this.rm.clear();
this.model.buildRoleLinks(this.rm);
await this.model.buildRoleLinks(this.rm);
}

/**
Expand All @@ -255,139 +255,139 @@ export class CoreEnforcer {
* of strings, can be class instances if ABAC is used.
* @return whether to allow the request.
*/
public enforce(...rvals: any[]): boolean {
if (!this.enabled) {
return true;
}

const functions: { [key: string]: any } = {};
this.fm.getFunctions().forEach((value: any, key: string) => {
functions[key] = value;
});
public async enforce(...rvals: any[]): Promise<boolean> {
if (!this.enabled) {
return true;
}

const astMap = this.model.model.get('g');
if (astMap) {
astMap.forEach((value, key) => {
const rm = value.rm;
functions[key] = generateGFunction(rm);
const functions: { [key: string]: any } = {};
this.fm.getFunctions().forEach((value: any, key: string) => {
functions[key] = value;
});
}

// @ts-ignore
const expString = this.model.model.get('m').get('m').value;
if (!expString) {
throw new Error('model is undefined');
}
const astMap = this.model.model.get('g');
if (astMap) {
astMap.forEach((value, key) => {
const rm = value.rm;
functions[key] = generateGFunction(rm);
});
}

const expression = compile(expString);
// @ts-ignore
const expString = this.model.model.get('m').get('m').value;
if (!expString) {
throw new Error('model is undefined');
}

let policyEffects: Effect[];
let matcherResults: number[];
// @ts-ignore
const policyLen = this.model.model.get('p').get('p').policy.length;
if (policyLen !== 0) {
policyEffects = new Array(policyLen);
matcherResults = new Array(policyLen);
const expression = compileAsync(expString);

for (let i = 0; i < policyLen; i++) {
// @ts-ignore
const pvals = this.model.model.get('p').get('p').policy[i];
let policyEffects: Effect[];
let matcherResults: number[];
// @ts-ignore
const policyLen = this.model.model.get('p').get('p').policy.length;
if (policyLen !== 0) {
policyEffects = new Array(policyLen);
matcherResults = new Array(policyLen);

for (let i = 0; i < policyLen; i++) {
// @ts-ignore
const pvals = this.model.model.get('p').get('p').policy[i];

// logPrint('Policy Rule: ', pvals);

const parameters: { [key: string]: any } = {};
// @ts-ignore
this.model.model.get('r').get('r').tokens.forEach((token, j) => {
parameters[token] = rvals[j];
});
// @ts-ignore
this.model.model.get('p').get('p').tokens.forEach((token, j) => {
parameters[token] = pvals[j];
});

const result = await expression({ ...parameters, ...functions });

switch (typeof result) {
case 'boolean':
if (!result) {
policyEffects[i] = Effect.Indeterminate;
continue;
}
break;
case 'number':
if (result === 0) {
policyEffects[i] = Effect.Indeterminate;
continue;
} else {
matcherResults[i] = result;
}
break;
default:
throw new Error('matcher result should be boolean or number');
}

if (_.has(parameters, 'p_eft')) {
const eft = _.get(parameters, 'p_eft');
if (eft === 'allow') {
policyEffects[i] = Effect.Allow;
} else if (eft === 'deny') {
policyEffects[i] = Effect.Deny;
} else {
policyEffects[i] = Effect.Indeterminate;
}
} else {
policyEffects[i] = Effect.Allow;
}

// logPrint('Policy Rule: ', pvals);
// @ts-ignore
if (this.model.model.get('e').get('e').value === 'priority(p_eft) || deny') {
break;
}
}
} else {
policyEffects = new Array(1);
matcherResults = new Array(1);

const parameters: { [key: string]: any } = {};
// @ts-ignore
this.model.model.get('r').get('r').tokens.forEach((token, j) => {
parameters[token] = rvals[j];
});
// @ts-ignore
this.model.model.get('p').get('p').tokens.forEach((token, j) => {
parameters[token] = pvals[j];
this.model.model.get('p').get('p').tokens.forEach((token) => {
parameters[token] = '';
});

const result = expression({ ...parameters, ...functions });
const result = await expression({ ...parameters, ...functions });
// logPrint(`Result: ${result}`);

switch (typeof result) {
case 'boolean':
if (!result) {
policyEffects[i] = Effect.Indeterminate;
continue;
}
break;
case 'number':
if (result === 0) {
policyEffects[i] = Effect.Indeterminate;
continue;
} else {
matcherResults[i] = result;
}
break;
default:
throw new Error('matcher result should be boolean or number');
}

if (_.has(parameters, 'p_eft')) {
const eft = _.get(parameters, 'p_eft');
if (eft === 'allow') {
policyEffects[i] = Effect.Allow;
} else if (eft === 'deny') {
policyEffects[i] = Effect.Deny;
} else {
policyEffects[i] = Effect.Indeterminate;
}
if (result) {
policyEffects[0] = Effect.Allow;
} else {
policyEffects[i] = Effect.Allow;
}

// @ts-ignore
if (this.model.model.get('e').get('e').value === 'priority(p_eft) || deny') {
break;
policyEffects[0] = Effect.Indeterminate;
}
}
} else {
policyEffects = new Array(1);
matcherResults = new Array(1);

const parameters: { [key: string]: any } = {};
// @ts-ignore
this.model.model.get('r').get('r').tokens.forEach((token, j) => {
parameters[token] = rvals[j];
});
// @ts-ignore
this.model.model.get('p').get('p').tokens.forEach((token) => {
parameters[token] = '';
});

const result = expression({ ...parameters, ...functions });
// logPrint(`Result: ${result}`);

if (result) {
policyEffects[0] = Effect.Allow;
} else {
policyEffects[0] = Effect.Indeterminate;
}
}

// logPrint(`Rule Results: ${policyEffects}`);
// logPrint(`Rule Results: ${policyEffects}`);

// @ts-ignore
const res = this.eft.mergeEffects(this.model.model.get('e').get('e').value, policyEffects, matcherResults);

// only generate the request --> result string if the message
// is going to be logged.
if (getLogger().isEnable()) {
let reqStr = 'Request: ';
for (let i = 0; i < rvals.length; i++) {
if (i !== rvals.length - 1) {
reqStr += `${rvals[i]}, `;
} else {
reqStr += rvals[i];
// @ts-ignore
const res = this.eft.mergeEffects(this.model.model.get('e').get('e').value, policyEffects, matcherResults);

// only generate the request --> result string if the message
// is going to be logged.
if (getLogger().isEnable()) {
let reqStr = 'Request: ';
for (let i = 0; i < rvals.length; i++) {
if (i !== rvals.length - 1) {
reqStr += `${rvals[i]}, `;
} else {
reqStr += rvals[i];
}
}
reqStr += ` ---> ${res}`;
logPrint(reqStr);
}
reqStr += ` ---> ${res}`;
logPrint(reqStr);
}

return res;
return res;
}
}
Loading