UNPKG

casbin

Version:

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

389 lines (388 loc) 15.6 kB
// 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. import { CoreEnforcer } from './coreEnforcer'; import { PolicyOp } from './model'; /** * InternalEnforcer = CoreEnforcer + Internal API. */ export class InternalEnforcer extends CoreEnforcer { /** * addPolicyInternal adds a rule to the current policy. */ async addPolicyInternal(sec, ptype, rule, useWatcher) { if (this.model.hasPolicy(sec, ptype, rule)) { return false; } // Persist when an adapter is configured and autoSave is enabled. if (this.adapter && this.autoSave) { try { await this.adapter.addPolicy(sec, ptype, rule); } catch (e) { if (e instanceof Error && e.message !== 'not implemented') { throw e; } } } if (useWatcher) { if (this.autoNotifyWatcher) { // error intentionally ignored if (this.watcherEx) { this.watcherEx.updateForAddPolicy(sec, ptype, ...rule); } else if (this.watcher) { this.watcher.update(); } } } const ok = this.model.addPolicy(sec, ptype, rule); if (sec === 'g' && ok) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, [rule]); } return ok; } // addPolicies adds rules to the current policy. // removePolicies removes rules from the current policy. async addPoliciesInternal(sec, ptype, rules, useWatcher) { for (const rule of rules) { if (this.model.hasPolicy(sec, ptype, rule)) { return false; } } // Persist when an adapter is configured and autoSave is enabled. if (this.adapter && this.autoSave) { if ('addPolicies' in this.adapter) { try { await this.adapter.addPolicies(sec, ptype, rules); } catch (e) { if (e instanceof Error && e.message !== 'not implemented') { throw e; } } } else { throw new Error('cannot to save policy, the adapter does not implement the BatchAdapter'); } } if (useWatcher) { if (this.autoNotifyWatcher) { // error intentionally ignored if (this.watcherEx) { this.watcherEx.updateForAddPolicies(sec, ptype, ...rules); } else if (this.watcher) { this.watcher.update(); } } } const [ok, effects] = await this.model.addPolicies(sec, ptype, rules); if (sec === 'g' && ok && (effects === null || effects === void 0 ? void 0 : effects.length)) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, effects); } return ok; } /** * addPoliciesInternalEx adds rules to the current policy. * Unlike addPoliciesInternal, this method will filter out rules that already exist * and continue to add the remaining rules instead of returning false immediately. */ async addPoliciesInternalEx(sec, ptype, rules, useWatcher) { // Filter out existing rules const newRules = rules.filter((rule) => !this.model.hasPolicy(sec, ptype, rule)); // If no new rules to add, return false if (newRules.length === 0) { return false; } // Persist when an adapter is configured and autoSave is enabled. if (this.adapter && this.autoSave) { if ('addPolicies' in this.adapter) { try { await this.adapter.addPolicies(sec, ptype, newRules); } catch (e) { if (e instanceof Error && e.message !== 'not implemented') { throw e; } } } else { throw new Error('cannot save policy, the adapter does not implement the BatchAdapter'); } } if (useWatcher) { if (this.autoNotifyWatcher) { // error intentionally ignored if (this.watcherEx) { this.watcherEx.updateForAddPolicies(sec, ptype, ...newRules); } else if (this.watcher) { this.watcher.update(); } } } const [ok, effects] = await this.model.addPolicies(sec, ptype, newRules); if (sec === 'g' && ok && (effects === null || effects === void 0 ? void 0 : effects.length)) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, effects); } return ok; } /** * updatePolicyInternal updates a rule from the current policy. */ async updatePolicyInternal(sec, ptype, oldRule, newRule, useWatcher) { if (!this.model.hasPolicy(sec, ptype, oldRule)) { return false; } // Persist when an adapter is configured and autoSave is enabled. if (this.adapter && this.autoSave) { if ('updatePolicy' in this.adapter) { try { await this.adapter.updatePolicy(sec, ptype, oldRule, newRule); } catch (e) { if (e instanceof Error && e.message !== 'not implemented') { throw e; } } } else { throw new Error('cannot to update policy, the adapter does not implement the UpdatableAdapter'); } } if (useWatcher) { if (this.autoNotifyWatcher) { // In fact I think it should wait for the respond, but they implement add_policy() like this // error intentionally ignored if (this.watcher) { this.watcher.update(); } } } const ok = this.model.updatePolicy(sec, ptype, oldRule, newRule); if (sec === 'g' && ok) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, [oldRule]); await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, [newRule]); } return ok; } /** * removePolicyInternal removes a rule from the current policy. */ async removePolicyInternal(sec, ptype, rule, useWatcher) { if (!this.model.hasPolicy(sec, ptype, rule)) { return false; } // Persist when an adapter is configured and autoSave is enabled. if (this.adapter && this.autoSave) { try { await this.adapter.removePolicy(sec, ptype, rule); } catch (e) { if (e instanceof Error && e.message !== 'not implemented') { throw e; } } } if (useWatcher) { if (this.autoNotifyWatcher) { // error intentionally ignored if (this.watcherEx) { this.watcherEx.updateForRemovePolicy(sec, ptype, ...rule); } else if (this.watcher) { this.watcher.update(); } } } const ok = await this.model.removePolicy(sec, ptype, rule); if (sec === 'g' && ok) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, [rule]); } return ok; } // removePolicies removes rules from the current policy. async removePoliciesInternal(sec, ptype, rules, useWatcher) { for (const rule of rules) { if (!this.model.hasPolicy(sec, ptype, rule)) { return false; } } // Persist when an adapter is configured and autoSave is enabled. if (this.adapter && this.autoSave) { if ('removePolicies' in this.adapter) { try { await this.adapter.removePolicies(sec, ptype, rules); } catch (e) { if (e instanceof Error && e.message !== 'not implemented') { throw e; } } } else { throw new Error('cannot to save policy, the adapter does not implement the BatchAdapter'); } } if (useWatcher) { if (this.autoNotifyWatcher) { // error intentionally ignored if (this.watcherEx) { this.watcherEx.updateForRemovePolicies(sec, ptype, ...rules); } else if (this.watcher) { this.watcher.update(); } } } const [ok, effects] = this.model.removePolicies(sec, ptype, rules); if (sec === 'g' && ok && (effects === null || effects === void 0 ? void 0 : effects.length)) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, effects); } return ok; } /** * removeFilteredPolicyInternal removes rules based on field filters from the current policy. */ async removeFilteredPolicyInternal(sec, ptype, fieldIndex, fieldValues, useWatcher) { // Persist when an adapter is configured and autoSave is enabled. if (this.adapter && this.autoSave) { try { await this.adapter.removeFilteredPolicy(sec, ptype, fieldIndex, ...fieldValues); } catch (e) { if (e instanceof Error && e.message !== 'not implemented') { throw e; } } } if (useWatcher) { if (this.autoNotifyWatcher) { // error intentionally ignored if (this.watcherEx) { this.watcherEx.updateForRemoveFilteredPolicy(sec, ptype, fieldIndex, ...fieldValues); } else if (this.watcher) { this.watcher.update(); } } } const [ok, effects] = this.model.removeFilteredPolicy(sec, ptype, fieldIndex, ...fieldValues); if (sec === 'g' && ok && (effects === null || effects === void 0 ? void 0 : effects.length)) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, effects); } return ok; } /** * get field index in model.fieldMap. */ getFieldIndex(ptype, field) { return this.model.getFieldIndex(ptype, field); } /** * set index of field */ setFieldIndex(ptype, field, index) { var _a; const assertion = (_a = this.model.model.get('p')) === null || _a === void 0 ? void 0 : _a.get(ptype); assertion === null || assertion === void 0 ? void 0 : assertion.fieldIndexMap.set(field, index); } async addPolicyWithoutNotify(sec, ptype, rule) { if (this.model.hasPolicy(sec, ptype, rule)) { return false; } const ok = this.model.addPolicy(sec, ptype, rule); if (sec === 'g' && ok) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, [rule]); } return ok; } async addPoliciesWithoutNotify(sec, ptype, rules) { for (const rule of rules) { if (this.model.hasPolicy(sec, ptype, rule)) { return false; } } const [ok, effects] = await this.model.addPolicies(sec, ptype, rules); if (sec === 'g' && ok && (effects === null || effects === void 0 ? void 0 : effects.length)) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, effects); } return ok; } async addPoliciesWithoutNotifyEx(sec, ptype, rules) { const newRules = rules.filter((rule) => !this.model.hasPolicy(sec, ptype, rule)); if (newRules.length === 0) { return false; } const [ok, effects] = await this.model.addPolicies(sec, ptype, newRules); if (sec === 'g' && ok && (effects === null || effects === void 0 ? void 0 : effects.length)) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, effects); } return ok; } async updatePolicyWithoutNotify(sec, ptype, oldRule, newRule) { if (!this.model.hasPolicy(sec, ptype, oldRule)) { return false; } const ok = this.model.updatePolicy(sec, ptype, oldRule, newRule); if (sec === 'g' && ok) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, [oldRule]); await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, [newRule]); } return ok; } async removePolicyWithoutNotify(sec, ptype, rule) { if (!this.model.hasPolicy(sec, ptype, rule)) { return false; } const ok = await this.model.removePolicy(sec, ptype, rule); if (sec === 'g' && ok) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, [rule]); } return ok; } async removePoliciesWithoutNotify(sec, ptype, rules) { for (const rule of rules) { if (!this.model.hasPolicy(sec, ptype, rule)) { return false; } } const [ok, effects] = this.model.removePolicies(sec, ptype, rules); if (sec === 'g' && ok && (effects === null || effects === void 0 ? void 0 : effects.length)) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, effects); } return ok; } async removeFilteredPolicyWithoutNotify(sec, ptype, fieldIndex, fieldValues) { const [ok, effects] = this.model.removeFilteredPolicy(sec, ptype, fieldIndex, ...fieldValues); if (sec === 'g' && ok && (effects === null || effects === void 0 ? void 0 : effects.length)) { await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, effects); } return ok; } async updatePoliciesWithoutNotify(sec, ptype, oldRules, newRules) { // Mirror the Go updatePoliciesWithoutNotify; reuse the existing internal flow. // Because updatePoliciesInternal isn't implemented yet, fall back to per-item updates. if (oldRules.length !== newRules.length) { throw new Error('the length of oldRules should be equal to the length of newRules'); } for (let i = 0; i < oldRules.length; i++) { const ok = await this.updatePolicyWithoutNotify(sec, ptype, oldRules[i], newRules[i]); if (!ok) { return false; } } return true; } }