UNPKG

casbin

Version:

An authorization library that supports access control models like ACL, RBAC, ABAC in Node.JS

389 lines (388 loc) 13.3 kB
"use strict"; // Copyright 2018 The Casbin Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.newModelFromString = exports.newModelFromFile = exports.newModel = exports.Model = exports.requiredSections = exports.PolicyOp = exports.sectionNameMap = void 0; const util = require("../util"); const config_1 = require("../config"); const assertion_1 = require("./assertion"); const log_1 = require("../log"); exports.sectionNameMap = { r: 'request_definition', p: 'policy_definition', g: 'role_definition', e: 'policy_effect', m: 'matchers' }; var PolicyOp; (function (PolicyOp) { PolicyOp[PolicyOp["PolicyAdd"] = 0] = "PolicyAdd"; PolicyOp[PolicyOp["PolicyRemove"] = 1] = "PolicyRemove"; })(PolicyOp = exports.PolicyOp || (exports.PolicyOp = {})); exports.requiredSections = ['r', 'p', 'e', 'm']; class Model { /** * constructor is the constructor for Model. */ constructor() { this.model = new Map(); } loadAssertion(cfg, sec, key) { const secName = exports.sectionNameMap[sec]; const value = cfg.getString(`${secName}::${key}`); return this.addDef(sec, key, value); } getKeySuffix(i) { if (i === 1) { return ''; } return i.toString(); } loadSection(cfg, sec) { let i = 1; for (;;) { if (!this.loadAssertion(cfg, sec, sec + this.getKeySuffix(i))) { break; } else { i++; } } } // addDef adds an assertion to the model. addDef(sec, key, value) { if (value === '') { return false; } const ast = new assertion_1.Assertion(); ast.key = key; ast.value = value; if (sec === 'r' || sec === 'p') { const tokens = value.split(',').map(n => n.trim()); for (let i = 0; i < tokens.length; i++) { tokens[i] = key + '_' + tokens[i]; } ast.tokens = tokens; } else if (sec === 'm') { const stringArguments = value.match(/\"(.*?)\"/g) || []; stringArguments.forEach((n, index) => { value = value.replace(n, `$<${index}>`); }); value = util.escapeAssertion(value); stringArguments.forEach((n, index) => { value = value.replace(`$<${index}>`, n); }); ast.value = value; } else { ast.value = util.escapeAssertion(value); } const nodeMap = this.model.get(sec); if (nodeMap) { nodeMap.set(key, ast); } else { const assertionMap = new Map(); assertionMap.set(key, ast); this.model.set(sec, assertionMap); } return true; } // loadModel loads the model from model CONF file. loadModel(path) { const cfg = config_1.Config.newConfig(path); this.loadModelFromConfig(cfg); } // loadModelFromText loads the model from the text. loadModelFromText(text) { const cfg = config_1.Config.newConfigFromText(text); this.loadModelFromConfig(cfg); } loadModelFromConfig(cfg) { for (const s in exports.sectionNameMap) { this.loadSection(cfg, s); } const ms = []; exports.requiredSections.forEach(n => { if (!this.hasSection(n)) { ms.push(exports.sectionNameMap[n]); } }); if (ms.length > 0) { throw new Error(`missing required sections: ${ms.join(',')}`); } } hasSection(sec) { return this.model.get(sec) !== undefined; } // printModel prints the model to the log. printModel() { log_1.logPrint('Model:'); this.model.forEach((value, key) => { value.forEach((ast, astKey) => { log_1.logPrint(`${key}.${astKey}: ${ast.value}`); }); }); } // buildIncrementalRoleLinks provides incremental build the role inheritance relations. buildIncrementalRoleLinks(rm, op, sec, ptype, rules) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { if (sec === 'g') { yield ((_b = (_a = this.model .get(sec)) === null || _a === void 0 ? void 0 : _a.get(ptype)) === null || _b === void 0 ? void 0 : _b.buildIncrementalRoleLinks(rm, op, rules)); } }); } // buildRoleLinks initializes the roles in RBAC. buildRoleLinks(rm) { return __awaiter(this, void 0, void 0, function* () { const astMap = this.model.get('g'); if (!astMap) { return; } for (const value of astMap.values()) { yield value.buildRoleLinks(rm); } }); } // clearPolicy clears all current policy. clearPolicy() { this.model.forEach((value, key) => { if (key === 'p' || key === 'g') { value.forEach(ast => { ast.policy = []; }); } }); } // getPolicy gets all rules in a policy. getPolicy(sec, key) { var _a; const policy = []; const ast = (_a = this.model.get(sec)) === null || _a === void 0 ? void 0 : _a.get(key); if (ast) { policy.push(...ast.policy); } return policy; } // hasPolicy determines whether a model has the specified policy rule. hasPolicy(sec, key, rule) { var _a; const ast = (_a = this.model.get(sec)) === null || _a === void 0 ? void 0 : _a.get(key); if (!ast) { return false; } return ast.policy.some((n) => util.arrayEquals(n, rule)); } // addPolicy adds a policy rule to the model. addPolicy(sec, key, rule) { var _a; if (!this.hasPolicy(sec, key, rule)) { const ast = (_a = this.model.get(sec)) === null || _a === void 0 ? void 0 : _a.get(key); if (!ast) { return false; } ast.policy.push(rule); return true; } return false; } // addPolicies adds policy rules to the model. addPolicies(sec, ptype, rules) { var _a; const ast = (_a = this.model.get(sec)) === null || _a === void 0 ? void 0 : _a.get(ptype); if (!ast) { return [false, []]; } for (const rule of rules) { if (this.hasPolicy(sec, ptype, rule)) { return [false, []]; } } ast.policy = ast.policy.concat(rules); return [true, rules]; } // removePolicy removes a policy rule from the model. removePolicy(sec, key, rule) { var _a; if (this.hasPolicy(sec, key, rule)) { const ast = (_a = this.model.get(sec)) === null || _a === void 0 ? void 0 : _a.get(key); if (!ast) { return false; } ast.policy = ast.policy.filter(r => !util.arrayEquals(rule, r)); return true; } return false; } // removePolicies removes policy rules from the model. removePolicies(sec, ptype, rules) { var _a; const effects = []; const ast = (_a = this.model.get(sec)) === null || _a === void 0 ? void 0 : _a.get(ptype); if (!ast) { return [false, []]; } for (const rule of rules) { if (!this.hasPolicy(sec, ptype, rule)) { return [false, []]; } } for (const rule of rules) { ast.policy = ast.policy.filter((r) => { const equals = util.arrayEquals(rule, r); if (equals) { effects.push(r); } return !equals; }); } return [true, effects]; } // getFilteredPolicy gets rules based on field filters from a policy. getFilteredPolicy(sec, key, fieldIndex, ...fieldValues) { var _a; const res = []; const ast = (_a = this.model.get(sec)) === null || _a === void 0 ? void 0 : _a.get(key); if (!ast) { return res; } for (const rule of ast.policy) { let matched = true; for (let i = 0; i < fieldValues.length; i++) { const fieldValue = fieldValues[i]; if (fieldValue !== '' && rule[fieldIndex + i] !== fieldValue) { matched = false; break; } } if (matched) { res.push(rule); } } return res; } // removeFilteredPolicy removes policy rules based on field filters from the model. removeFilteredPolicy(sec, key, fieldIndex, ...fieldValues) { var _a; const res = []; const effects = []; let bool = false; const ast = (_a = this.model.get(sec)) === null || _a === void 0 ? void 0 : _a.get(key); if (!ast) { return [false, []]; } for (const rule of ast.policy) { let matched = true; for (let i = 0; i < fieldValues.length; i++) { const fieldValue = fieldValues[i]; if (fieldValue !== '' && rule[fieldIndex + i] !== fieldValue) { matched = false; break; } } if (matched) { bool = true; effects.push(rule); } else { res.push(rule); } } ast.policy = res; return [bool, effects]; } // getValuesForFieldInPolicy gets all values for a field for all rules in a policy, duplicated values are removed. getValuesForFieldInPolicy(sec, key, fieldIndex) { var _a; const values = []; const ast = (_a = this.model.get(sec)) === null || _a === void 0 ? void 0 : _a.get(key); if (!ast) { return values; } return util.arrayRemoveDuplicates(ast.policy.map((n) => n[fieldIndex])); } // getValuesForFieldInPolicyAllTypes gets all values for a field for all rules in a policy of all ptypes, duplicated values are removed. getValuesForFieldInPolicyAllTypes(sec, fieldIndex) { const values = []; const ast = this.model.get(sec); if (!ast) { return values; } for (const ptype of ast.keys()) { values.push(...this.getValuesForFieldInPolicy(sec, ptype, fieldIndex)); } return util.arrayRemoveDuplicates(values); } // printPolicy prints the policy to log. printPolicy() { log_1.logPrint('Policy:'); this.model.forEach((map, key) => { if (key === 'p' || key === 'g') { map.forEach(ast => { log_1.logPrint(`key, : ${ast.value}, : , ${ast.policy}`); }); } }); } } exports.Model = Model; /** * newModel creates a model. */ function newModel(...text) { const m = new Model(); if (text.length === 2) { if (text[0] !== '') { m.loadModel(text[0]); } } else if (text.length === 1) { m.loadModelFromText(text[0]); } else if (text.length !== 0) { throw new Error('Invalid parameters for model.'); } return m; } exports.newModel = newModel; /** * newModelFromFile creates a model from a .CONF file. */ function newModelFromFile(path) { const m = new Model(); m.loadModel(path); return m; } exports.newModelFromFile = newModelFromFile; /** * newModelFromString creates a model from a string which contains model text. */ function newModelFromString(text) { const m = new Model(); m.loadModelFromText(text); return m; } exports.newModelFromString = newModelFromString;