242 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2017 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.
 | |
| 
 | |
| package defaultrolemanager
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"sync"
 | |
| 
 | |
| 	"github.com/casbin/casbin/rbac"
 | |
| 	"github.com/casbin/casbin/util"
 | |
| )
 | |
| 
 | |
| // RoleManager provides a default implementation for the RoleManager interface
 | |
| type RoleManager struct {
 | |
| 	allRoles          *sync.Map
 | |
| 	maxHierarchyLevel int
 | |
| }
 | |
| 
 | |
| // NewRoleManager is the constructor for creating an instance of the
 | |
| // default RoleManager implementation.
 | |
| func NewRoleManager(maxHierarchyLevel int) rbac.RoleManager {
 | |
| 	rm := RoleManager{}
 | |
| 	rm.allRoles = &sync.Map{}
 | |
| 	rm.maxHierarchyLevel = maxHierarchyLevel
 | |
| 	return &rm
 | |
| }
 | |
| 
 | |
| func (rm *RoleManager) hasRole(name string) bool {
 | |
| 	_, ok := rm.allRoles.Load(name)
 | |
| 	return ok
 | |
| }
 | |
| 
 | |
| func (rm *RoleManager) createRole(name string) *Role {
 | |
| 	role, _ := rm.allRoles.LoadOrStore(name, newRole(name))
 | |
| 	return role.(*Role)
 | |
| }
 | |
| 
 | |
| // Clear clears all stored data and resets the role manager to the initial state.
 | |
| func (rm *RoleManager) Clear() error {
 | |
| 	rm.allRoles = &sync.Map{}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // AddLink adds the inheritance link between role: name1 and role: name2.
 | |
| // aka role: name1 inherits role: name2.
 | |
| // domain is a prefix to the roles.
 | |
| func (rm *RoleManager) AddLink(name1 string, name2 string, domain ...string) error {
 | |
| 	if len(domain) == 1 {
 | |
| 		name1 = domain[0] + "::" + name1
 | |
| 		name2 = domain[0] + "::" + name2
 | |
| 	} else if len(domain) > 1 {
 | |
| 		return errors.New("error: domain should be 1 parameter")
 | |
| 	}
 | |
| 
 | |
| 	role1 := rm.createRole(name1)
 | |
| 	role2 := rm.createRole(name2)
 | |
| 	role1.addRole(role2)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // 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.
 | |
| func (rm *RoleManager) DeleteLink(name1 string, name2 string, domain ...string) error {
 | |
| 	if len(domain) == 1 {
 | |
| 		name1 = domain[0] + "::" + name1
 | |
| 		name2 = domain[0] + "::" + name2
 | |
| 	} else if len(domain) > 1 {
 | |
| 		return errors.New("error: domain should be 1 parameter")
 | |
| 	}
 | |
| 
 | |
| 	if !rm.hasRole(name1) || !rm.hasRole(name2) {
 | |
| 		return errors.New("error: name1 or name2 does not exist")
 | |
| 	}
 | |
| 
 | |
| 	role1 := rm.createRole(name1)
 | |
| 	role2 := rm.createRole(name2)
 | |
| 	role1.deleteRole(role2)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // HasLink determines whether role: name1 inherits role: name2.
 | |
| // domain is a prefix to the roles.
 | |
| func (rm *RoleManager) HasLink(name1 string, name2 string, domain ...string) (bool, error) {
 | |
| 	if len(domain) == 1 {
 | |
| 		name1 = domain[0] + "::" + name1
 | |
| 		name2 = domain[0] + "::" + name2
 | |
| 	} else if len(domain) > 1 {
 | |
| 		return false, errors.New("error: domain should be 1 parameter")
 | |
| 	}
 | |
| 
 | |
| 	if name1 == name2 {
 | |
| 		return true, nil
 | |
| 	}
 | |
| 
 | |
| 	if !rm.hasRole(name1) || !rm.hasRole(name2) {
 | |
| 		return false, nil
 | |
| 	}
 | |
| 
 | |
| 	role1 := rm.createRole(name1)
 | |
| 	return role1.hasRole(name2, rm.maxHierarchyLevel), nil
 | |
| }
 | |
| 
 | |
| // GetRoles gets the roles that a subject inherits.
 | |
| // domain is a prefix to the roles.
 | |
| func (rm *RoleManager) GetRoles(name string, domain ...string) ([]string, error) {
 | |
| 	if len(domain) == 1 {
 | |
| 		name = domain[0] + "::" + name
 | |
| 	} else if len(domain) > 1 {
 | |
| 		return nil, errors.New("error: domain should be 1 parameter")
 | |
| 	}
 | |
| 
 | |
| 	if !rm.hasRole(name) {
 | |
| 		return nil, errors.New("error: name does not exist")
 | |
| 	}
 | |
| 
 | |
| 	roles := rm.createRole(name).getRoles()
 | |
| 	if len(domain) == 1 {
 | |
| 		for i := range roles {
 | |
| 			roles[i] = roles[i][len(domain[0])+2:]
 | |
| 		}
 | |
| 	}
 | |
| 	return roles, nil
 | |
| }
 | |
| 
 | |
| // GetUsers gets the users that inherits a subject.
 | |
| // domain is an unreferenced parameter here, may be used in other implementations.
 | |
| func (rm *RoleManager) GetUsers(name string, domain ...string) ([]string, error) {
 | |
| 	if !rm.hasRole(name) {
 | |
| 		return nil, errors.New("error: name does not exist")
 | |
| 	}
 | |
| 
 | |
| 	names := []string{}
 | |
| 	rm.allRoles.Range(func(_, value interface{}) bool {
 | |
| 		role := value.(*Role)
 | |
| 		if role.hasDirectRole(name) {
 | |
| 			names = append(names, role.name)
 | |
| 		}
 | |
| 		return true
 | |
| 	})
 | |
| 	return names, nil
 | |
| }
 | |
| 
 | |
| // PrintRoles prints all the roles to log.
 | |
| func (rm *RoleManager) PrintRoles() error {
 | |
| 	rm.allRoles.Range(func(_, value interface{}) bool {
 | |
| 		util.LogPrint(value.(*Role).toString())
 | |
| 		return true
 | |
| 	})
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Role represents the data structure for a role in RBAC.
 | |
| type Role struct {
 | |
| 	name  string
 | |
| 	roles []*Role
 | |
| }
 | |
| 
 | |
| func newRole(name string) *Role {
 | |
| 	r := Role{}
 | |
| 	r.name = name
 | |
| 	return &r
 | |
| }
 | |
| 
 | |
| func (r *Role) addRole(role *Role) {
 | |
| 	for _, rr := range r.roles {
 | |
| 		if rr.name == role.name {
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	r.roles = append(r.roles, role)
 | |
| }
 | |
| 
 | |
| func (r *Role) deleteRole(role *Role) {
 | |
| 	for i, rr := range r.roles {
 | |
| 		if rr.name == role.name {
 | |
| 			r.roles = append(r.roles[:i], r.roles[i+1:]...)
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (r *Role) hasRole(name string, hierarchyLevel int) bool {
 | |
| 	if r.name == name {
 | |
| 		return true
 | |
| 	}
 | |
| 
 | |
| 	if hierarchyLevel <= 0 {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	for _, role := range r.roles {
 | |
| 		if role.hasRole(name, hierarchyLevel-1) {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func (r *Role) hasDirectRole(name string) bool {
 | |
| 	for _, role := range r.roles {
 | |
| 		if role.name == name {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func (r *Role) toString() string {
 | |
| 	names := ""
 | |
| 	for i, role := range r.roles {
 | |
| 		if i == 0 {
 | |
| 			names += role.name
 | |
| 		} else {
 | |
| 			names += ", " + role.name
 | |
| 		}
 | |
| 	}
 | |
| 	return r.name + " < " + names
 | |
| }
 | |
| 
 | |
| func (r *Role) getRoles() []string {
 | |
| 	names := []string{}
 | |
| 	for _, role := range r.roles {
 | |
| 		names = append(names, role.name)
 | |
| 	}
 | |
| 	return names
 | |
| }
 |