casbin
Version:
An authorization library that supports access control models like ACL, RBAC, ABAC in Node.JS
200 lines (199 loc) • 6.6 kB
JavaScript
"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.
Object.defineProperty(exports, "__esModule", { value: true });
const log_1 = require("../log");
// RoleManager provides a default implementation for the RoleManager interface
class DefaultRoleManager {
/**
* DefaultRoleManager is the constructor for creating an instance of the
* default RoleManager implementation.
*
* @param maxHierarchyLevel the maximized allowed RBAC hierarchy level.
*/
constructor(maxHierarchyLevel) {
this.allRoles = new Map();
this.maxHierarchyLevel = maxHierarchyLevel;
}
/**
* addLink adds the inheritance link between role: name1 and role: name2.
* aka role: name1 inherits role: name2.
* domain is a prefix to the roles.
*/
addLink(name1, name2, ...domain) {
if (domain.length === 1) {
name1 = domain[0] + '::' + name1;
name2 = domain[0] + '::' + name2;
}
else if (domain.length > 1) {
throw new Error('error: domain should be 1 parameter');
}
const role1 = this.createRole(name1);
const role2 = this.createRole(name2);
role1.addRole(role2);
}
/**
* clear clears all stored data and resets the role manager to the initial state.
*/
clear() {
this.allRoles = new Map();
}
/**
* deleteLink deletes the inheritance link between role: name1 and role: name2.
* aka role: name1 does not inherit role: name2 any more.
* domain is a prefix to the roles.
*/
deleteLink(name1, name2, ...domain) {
if (domain.length === 1) {
name1 = domain[0] + '::' + name1;
name2 = domain[0] + '::' + name2;
}
else if (domain.length > 1) {
throw new Error('error: domain should be 1 parameter');
}
if (!this.hasRole(name1) || !this.hasRole(name2)) {
throw new Error('error: name1 or name2 does not exist');
}
const role1 = this.createRole(name1);
const role2 = this.createRole(name2);
role1.deleteRole(role2);
}
/**
* getRoles gets the roles that a subject inherits.
* domain is a prefix to the roles.
*/
getRoles(name, ...domain) {
if (domain.length === 1) {
name = domain[0] + '::' + name;
}
else if (domain.length > 1) {
throw new Error('error: domain should be 1 parameter');
}
if (!this.hasRole(name)) {
throw new Error('error: name does not exist');
}
let roles = this.createRole(name).getRoles();
if (domain.length === 1) {
roles = roles.map(n => n.substring(domain[0].length + 2, n.length));
}
return roles;
}
/**
* getUsers gets the users that inherits a subject.
* domain is an unreferenced parameter here, may be used in other implementations.
*/
getUsers(name, ...domain) {
if (domain.length === 1) {
name = domain[0] + '::' + name;
}
else if (domain.length > 1) {
throw new Error('error: domain should be 1 parameter');
}
if (!this.hasRole(name)) {
throw new Error('error: name does not exist');
}
let users = [...this.allRoles.values()]
.filter(n => n.hasDirectRole(name))
.map(n => n.name);
if (domain.length === 1) {
users = users.map(n => n.substring(domain[0].length + 2, n.length));
}
return users;
}
/**
* hasLink determines whether role: name1 inherits role: name2.
* domain is a prefix to the roles.
*/
hasLink(name1, name2, ...domain) {
if (domain.length === 1) {
name1 = domain[0] + '::' + name1;
name2 = domain[0] + '::' + name2;
}
else if (domain.length > 1) {
throw new Error('error: domain should be 1 parameter');
}
if (name1 === name2) {
return true;
}
if (!this.hasRole(name1) || !this.hasRole(name2)) {
return false;
}
const role1 = this.createRole(name1);
return role1.hasRole(name2, this.maxHierarchyLevel);
}
/**
* printRoles prints all the roles to log.
*/
printRoles() {
[...this.allRoles.values()].map(n => {
log_1.logPrint(n.toString());
});
}
createRole(name) {
const role = this.allRoles.get(name);
if (role) {
return role;
}
else {
const newRole = new Role(name);
this.allRoles.set(name, newRole);
return newRole;
}
}
hasRole(name) {
return this.allRoles.has(name);
}
}
exports.DefaultRoleManager = DefaultRoleManager;
/**
* Role represents the data structure for a role in RBAC.
*/
class Role {
constructor(name) {
this.name = name;
this.roles = [];
}
addRole(role) {
if (this.roles.some(n => n.name === role.name)) {
return;
}
this.roles.push(role);
}
deleteRole(role) {
this.roles = this.roles.filter(n => n.name !== role.name);
}
hasRole(name, hierarchyLevel) {
if (this.name === name) {
return true;
}
if (hierarchyLevel <= 0) {
return false;
}
for (const role of this.roles) {
if (role.hasRole(name, hierarchyLevel - 1)) {
return true;
}
}
return false;
}
hasDirectRole(name) {
return this.roles.some(n => n.name === name);
}
toString() {
return this.name + this.roles.join(', ');
}
getRoles() {
return this.roles.map(n => n.name);
}
}