snapshot of https://github.com/casbin/casbin.git (master, 2026-09-15; blobs > 131072B omitted)
This commit is contained in:
733
rbac_api.go
Normal file
733
rbac_api.go
Normal file
@@ -0,0 +1,733 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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 casbin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casbin/v3/rbac"
|
||||
|
||||
"github.com/casbin/casbin/v3/constant"
|
||||
"github.com/casbin/casbin/v3/errors"
|
||||
"github.com/casbin/casbin/v3/util"
|
||||
)
|
||||
|
||||
// GetRolesForUser gets the roles that a user has.
|
||||
func (e *Enforcer) GetRolesForUser(name string, domain ...string) ([]string, error) {
|
||||
rm := e.GetRoleManager()
|
||||
if rm == nil {
|
||||
return nil, fmt.Errorf("role manager is not initialized")
|
||||
}
|
||||
res, err := rm.GetRoles(name, domain...)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// GetUsersForRole gets the users that has a role.
|
||||
func (e *Enforcer) GetUsersForRole(name string, domain ...string) ([]string, error) {
|
||||
rm := e.GetRoleManager()
|
||||
if rm == nil {
|
||||
return nil, fmt.Errorf("role manager is not initialized")
|
||||
}
|
||||
res, err := rm.GetUsers(name, domain...)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// HasRoleForUser determines whether a user has a role.
|
||||
func (e *Enforcer) HasRoleForUser(name string, role string, domain ...string) (bool, error) {
|
||||
roles, err := e.GetRolesForUser(name, domain...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
hasRole := false
|
||||
for _, r := range roles {
|
||||
if r == role {
|
||||
hasRole = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return hasRole, nil
|
||||
}
|
||||
|
||||
// AddRoleForUser adds a role for a user.
|
||||
// Returns false if the user already has the role (aka not affected).
|
||||
func (e *Enforcer) AddRoleForUser(user string, role string, domain ...string) (bool, error) {
|
||||
args := []string{user, role}
|
||||
args = append(args, domain...)
|
||||
return e.AddGroupingPolicy(args)
|
||||
}
|
||||
|
||||
// AddRolesForUser adds roles for a user.
|
||||
// Returns false if the user already has the roles (aka not affected).
|
||||
func (e *Enforcer) AddRolesForUser(user string, roles []string, domain ...string) (bool, error) {
|
||||
var rules [][]string
|
||||
for _, role := range roles {
|
||||
rule := []string{user, role}
|
||||
rule = append(rule, domain...)
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
return e.AddGroupingPolicies(rules)
|
||||
}
|
||||
|
||||
// DeleteRoleForUser deletes a role for a user.
|
||||
// Returns false if the user does not have the role (aka not affected).
|
||||
func (e *Enforcer) DeleteRoleForUser(user string, role string, domain ...string) (bool, error) {
|
||||
args := []string{user, role}
|
||||
args = append(args, domain...)
|
||||
return e.RemoveGroupingPolicy(args)
|
||||
}
|
||||
|
||||
// DeleteRolesForUser deletes all roles for a user.
|
||||
// Returns false if the user does not have any roles (aka not affected).
|
||||
func (e *Enforcer) DeleteRolesForUser(user string, domain ...string) (bool, error) {
|
||||
var args []string
|
||||
if len(domain) == 0 {
|
||||
args = []string{user}
|
||||
} else if len(domain) > 1 {
|
||||
return false, errors.ErrDomainParameter
|
||||
} else {
|
||||
args = []string{user, "", domain[0]}
|
||||
}
|
||||
return e.RemoveFilteredGroupingPolicy(0, args...)
|
||||
}
|
||||
|
||||
// DeleteUser deletes a user.
|
||||
// Returns false if the user does not exist (aka not affected).
|
||||
func (e *Enforcer) DeleteUser(user string) (bool, error) {
|
||||
var err error
|
||||
res1, err := e.RemoveFilteredGroupingPolicy(0, user)
|
||||
if err != nil {
|
||||
return res1, err
|
||||
}
|
||||
|
||||
subIndex, err := e.GetFieldIndex("p", constant.SubjectIndex)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
res2, err := e.RemoveFilteredPolicy(subIndex, user)
|
||||
return res1 || res2, err
|
||||
}
|
||||
|
||||
// DeleteRole deletes a role.
|
||||
// Returns false if the role does not exist (aka not affected).
|
||||
func (e *Enforcer) DeleteRole(role string) (bool, error) {
|
||||
var err error
|
||||
res1, err := e.RemoveFilteredGroupingPolicy(0, role)
|
||||
if err != nil {
|
||||
return res1, err
|
||||
}
|
||||
|
||||
res2, err := e.RemoveFilteredGroupingPolicy(1, role)
|
||||
if err != nil {
|
||||
return res1, err
|
||||
}
|
||||
|
||||
subIndex, err := e.GetFieldIndex("p", constant.SubjectIndex)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
res3, err := e.RemoveFilteredPolicy(subIndex, role)
|
||||
return res1 || res2 || res3, err
|
||||
}
|
||||
|
||||
// DeletePermission deletes a permission.
|
||||
// Returns false if the permission does not exist (aka not affected).
|
||||
func (e *Enforcer) DeletePermission(permission ...string) (bool, error) {
|
||||
return e.RemoveFilteredPolicy(1, permission...)
|
||||
}
|
||||
|
||||
// AddPermissionForUser adds a permission for a user or role.
|
||||
// Returns false if the user or role already has the permission (aka not affected).
|
||||
func (e *Enforcer) AddPermissionForUser(user string, permission ...string) (bool, error) {
|
||||
return e.AddPolicy(util.JoinSlice(user, permission...))
|
||||
}
|
||||
|
||||
// AddPermissionsForUser adds multiple permissions for a user or role.
|
||||
// Returns false if the user or role already has one of the permissions (aka not affected).
|
||||
func (e *Enforcer) AddPermissionsForUser(user string, permissions ...[]string) (bool, error) {
|
||||
var rules [][]string
|
||||
for _, permission := range permissions {
|
||||
rules = append(rules, util.JoinSlice(user, permission...))
|
||||
}
|
||||
return e.AddPolicies(rules)
|
||||
}
|
||||
|
||||
// DeletePermissionForUser deletes a permission for a user or role.
|
||||
// Returns false if the user or role does not have the permission (aka not affected).
|
||||
func (e *Enforcer) DeletePermissionForUser(user string, permission ...string) (bool, error) {
|
||||
return e.RemovePolicy(util.JoinSlice(user, permission...))
|
||||
}
|
||||
|
||||
// DeletePermissionsForUser deletes permissions for a user or role.
|
||||
// Returns false if the user or role does not have any permissions (aka not affected).
|
||||
func (e *Enforcer) DeletePermissionsForUser(user string) (bool, error) {
|
||||
subIndex, err := e.GetFieldIndex("p", constant.SubjectIndex)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return e.RemoveFilteredPolicy(subIndex, user)
|
||||
}
|
||||
|
||||
// GetPermissionsForUser gets permissions for a user or role.
|
||||
func (e *Enforcer) GetPermissionsForUser(user string, domain ...string) ([][]string, error) {
|
||||
return e.GetNamedPermissionsForUser("p", user, domain...)
|
||||
}
|
||||
|
||||
// GetNamedPermissionsForUser gets permissions for a user or role by named policy.
|
||||
func (e *Enforcer) GetNamedPermissionsForUser(ptype string, user string, domain ...string) ([][]string, error) {
|
||||
permission := make([][]string, 0)
|
||||
for pType, assertion := range e.model["p"] {
|
||||
if pType != ptype {
|
||||
continue
|
||||
}
|
||||
args := make([]string, len(assertion.Tokens))
|
||||
subIndex, err := e.GetFieldIndex(ptype, constant.SubjectIndex)
|
||||
if err != nil {
|
||||
subIndex = 0
|
||||
}
|
||||
args[subIndex] = user
|
||||
|
||||
if len(domain) > 0 {
|
||||
var index int
|
||||
index, err = e.GetFieldIndex(ptype, constant.DomainIndex)
|
||||
if err != nil {
|
||||
return permission, err
|
||||
}
|
||||
args[index] = domain[0]
|
||||
}
|
||||
perm, err := e.GetFilteredNamedPolicy(ptype, 0, args...)
|
||||
if err != nil {
|
||||
return permission, err
|
||||
}
|
||||
permission = append(permission, perm...)
|
||||
}
|
||||
return permission, nil
|
||||
}
|
||||
|
||||
// HasPermissionForUser determines whether a user has a permission.
|
||||
func (e *Enforcer) HasPermissionForUser(user string, permission ...string) (bool, error) {
|
||||
return e.HasPolicy(util.JoinSlice(user, permission...))
|
||||
}
|
||||
|
||||
// GetImplicitRolesForUser gets implicit roles that a user has.
|
||||
// Compared to GetRolesForUser(), this function retrieves indirect roles besides direct roles.
|
||||
// For example:
|
||||
// g, alice, role:admin
|
||||
// g, role:admin, role:user
|
||||
//
|
||||
// GetRolesForUser("alice") can only get: ["role:admin"].
|
||||
// But GetImplicitRolesForUser("alice") will get: ["role:admin", "role:user"].
|
||||
func (e *Enforcer) GetImplicitRolesForUser(name string, domain ...string) ([]string, error) {
|
||||
var res []string
|
||||
|
||||
for rm := range e.rmMap {
|
||||
roles, err := e.GetNamedImplicitRolesForUser(rm, name, domain...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, roles...)
|
||||
}
|
||||
|
||||
for crm := range e.condRmMap {
|
||||
roles, err := e.GetNamedImplicitRolesForUser(crm, name, domain...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, roles...)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetNamedImplicitRolesForUser gets implicit roles that a user has by named role definition.
|
||||
// Compared to GetImplicitRolesForUser(), this function retrieves indirect roles besides direct roles.
|
||||
// For example:
|
||||
// g, alice, role:admin
|
||||
// g, role:admin, role:user
|
||||
// g2, alice, role:admin2
|
||||
//
|
||||
// GetImplicitRolesForUser("alice") can only get: ["role:admin", "role:user"].
|
||||
// But GetNamedImplicitRolesForUser("g2", "alice") will get: ["role:admin2"].
|
||||
func (e *Enforcer) GetNamedImplicitRolesForUser(ptype string, name string, domain ...string) ([]string, error) {
|
||||
rm := e.GetNamedRoleManager(ptype)
|
||||
if rm == nil {
|
||||
return nil, fmt.Errorf("role manager %s is not initialized", ptype)
|
||||
}
|
||||
|
||||
// Use the role manager's GetImplicitRoles method which respects maxHierarchyLevel
|
||||
return rm.GetImplicitRoles(name, domain...)
|
||||
}
|
||||
|
||||
// GetImplicitUsersForRole gets implicit users for a role.
|
||||
func (e *Enforcer) GetImplicitUsersForRole(name string, domain ...string) ([]string, error) {
|
||||
res := []string{}
|
||||
var rms []rbac.RoleManager
|
||||
|
||||
for _, rm := range e.rmMap {
|
||||
rms = append(rms, rm)
|
||||
}
|
||||
for _, crm := range e.condRmMap {
|
||||
rms = append(rms, crm)
|
||||
}
|
||||
|
||||
for _, rm := range rms {
|
||||
// Use the role manager's GetImplicitUsers method which respects maxHierarchyLevel
|
||||
users, err := rm.GetImplicitUsers(name, domain...)
|
||||
if err != nil && err.Error() != "error: name does not exist" {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, users...)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetImplicitPermissionsForUser gets implicit permissions for a user or role.
|
||||
// Compared to GetPermissionsForUser(), this function retrieves permissions for inherited roles.
|
||||
// For example:
|
||||
// p, admin, data1, read
|
||||
// p, alice, data2, read
|
||||
// g, alice, admin
|
||||
//
|
||||
// GetPermissionsForUser("alice") can only get: [["alice", "data2", "read"]].
|
||||
// But GetImplicitPermissionsForUser("alice") will get: [["admin", "data1", "read"], ["alice", "data2", "read"]].
|
||||
func (e *Enforcer) GetImplicitPermissionsForUser(user string, domain ...string) ([][]string, error) {
|
||||
return e.GetNamedImplicitPermissionsForUser("p", "g", user, domain...)
|
||||
}
|
||||
|
||||
// GetNamedImplicitPermissionsForUser gets implicit permissions for a user or role by named policy.
|
||||
// Compared to GetNamedPermissionsForUser(), this function retrieves permissions for inherited roles.
|
||||
// For example:
|
||||
// p, admin, data1, read
|
||||
// p2, admin, create
|
||||
// g, alice, admin
|
||||
//
|
||||
// GetImplicitPermissionsForUser("alice") can only get: [["admin", "data1", "read"]], whose policy is default policy "p"
|
||||
// But you can specify the named policy "p2" to get: [["admin", "create"]] by GetNamedImplicitPermissionsForUser("p2","alice").
|
||||
func (e *Enforcer) GetNamedImplicitPermissionsForUser(ptype string, gtype string, user string, domain ...string) ([][]string, error) {
|
||||
permission := make([][]string, 0)
|
||||
rm := e.GetNamedRoleManager(gtype)
|
||||
if rm == nil {
|
||||
return nil, fmt.Errorf("role manager %s is not initialized", gtype)
|
||||
}
|
||||
|
||||
roles, err := e.GetNamedImplicitRolesForUser(gtype, user, domain...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policyRoles := make(map[string]struct{}, len(roles)+1)
|
||||
policyRoles[user] = struct{}{}
|
||||
for _, r := range roles {
|
||||
policyRoles[r] = struct{}{}
|
||||
}
|
||||
|
||||
domainIndex, err := e.GetFieldIndex(ptype, constant.DomainIndex)
|
||||
for _, rule := range e.model["p"][ptype].Policy {
|
||||
if len(domain) == 0 {
|
||||
if _, ok := policyRoles[rule[0]]; ok {
|
||||
permission = append(permission, deepCopyPolicy(rule))
|
||||
}
|
||||
continue
|
||||
}
|
||||
if len(domain) > 1 {
|
||||
return nil, errors.ErrDomainParameter
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d := domain[0]
|
||||
matched := rm.Match(d, rule[domainIndex])
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
if _, ok := policyRoles[rule[0]]; ok {
|
||||
newRule := deepCopyPolicy(rule)
|
||||
newRule[domainIndex] = d
|
||||
permission = append(permission, newRule)
|
||||
}
|
||||
}
|
||||
return permission, nil
|
||||
}
|
||||
|
||||
// GetImplicitUsersForPermission gets implicit users for a permission.
|
||||
// For example:
|
||||
// p, admin, data1, read
|
||||
// p, bob, data1, read
|
||||
// g, alice, admin
|
||||
//
|
||||
// GetImplicitUsersForPermission("data1", "read") will get: ["alice", "bob"].
|
||||
// Note: only users will be returned, roles (2nd arg in "g") will be excluded.
|
||||
func (e *Enforcer) GetImplicitUsersForPermission(permission ...string) ([]string, error) {
|
||||
pSubjects, err := e.GetAllSubjects()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gInherit, err := e.model.GetValuesForFieldInPolicyAllTypes("g", 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gSubjects, err := e.model.GetValuesForFieldInPolicyAllTypes("g", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
subjects := append(pSubjects, gSubjects...)
|
||||
util.ArrayRemoveDuplicates(&subjects)
|
||||
|
||||
subjects = util.SetSubtract(subjects, gInherit)
|
||||
|
||||
res := []string{}
|
||||
for _, user := range subjects {
|
||||
req := util.JoinSliceAny(user, permission...)
|
||||
allowed, err := e.Enforce(req...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if allowed {
|
||||
res = append(res, user)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetDomainsForUser gets all domains.
|
||||
func (e *Enforcer) GetDomainsForUser(user string) ([]string, error) {
|
||||
var domains []string
|
||||
for _, rm := range e.rmMap {
|
||||
domain, err := rm.GetDomains(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domains = append(domains, domain...)
|
||||
}
|
||||
for _, crm := range e.condRmMap {
|
||||
domain, err := crm.GetDomains(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domains = append(domains, domain...)
|
||||
}
|
||||
return domains, nil
|
||||
}
|
||||
|
||||
// GetImplicitResourcesForUser returns all policies that user obtaining in domain.
|
||||
func (e *Enforcer) GetImplicitResourcesForUser(user string, domain ...string) ([][]string, error) {
|
||||
permissions, err := e.GetImplicitPermissionsForUser(user, domain...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := make([][]string, 0)
|
||||
for _, permission := range permissions {
|
||||
if permission[0] == user {
|
||||
res = append(res, permission)
|
||||
continue
|
||||
}
|
||||
resLocal := [][]string{{user}}
|
||||
tokensLength := len(permission)
|
||||
t := make([][]string, 1, tokensLength)
|
||||
for _, token := range permission[1:] {
|
||||
tokens, err := e.GetImplicitUsersForRole(token, domain...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokens = append(tokens, token)
|
||||
t = append(t, tokens)
|
||||
}
|
||||
for i := 1; i < tokensLength; i++ {
|
||||
n := make([][]string, 0)
|
||||
for _, tokens := range t[i] {
|
||||
for _, policy := range resLocal {
|
||||
t := append([]string(nil), policy...)
|
||||
t = append(t, tokens)
|
||||
n = append(n, t)
|
||||
}
|
||||
}
|
||||
resLocal = n
|
||||
}
|
||||
res = append(res, resLocal...)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// deepCopyPolicy returns a deepcopy version of the policy to prevent changing policies through returned slice.
|
||||
func deepCopyPolicy(src []string) []string {
|
||||
newRule := make([]string, len(src))
|
||||
copy(newRule, src)
|
||||
return newRule
|
||||
}
|
||||
|
||||
// GetAllowedObjectConditions returns a string array of object conditions that the user can access.
|
||||
// For example: conditions, err := e.GetAllowedObjectConditions("alice", "read", "r.obj.")
|
||||
// Note:
|
||||
//
|
||||
// 0. prefix: You can customize the prefix of the object conditions, and "r.obj." is commonly used as a prefix.
|
||||
// After removing the prefix, the remaining part is the condition of the object.
|
||||
// If there is an obj policy that does not meet the prefix requirement, an errors.ERR_OBJ_CONDITION will be returned.
|
||||
//
|
||||
// 1. If the 'objectConditions' array is empty, return errors.ERR_EMPTY_CONDITION
|
||||
// This error is returned because some data adapters' ORM return full table data by default
|
||||
// when they receive an empty condition, which tends to behave contrary to expectations.(e.g. GORM)
|
||||
// If you are using an adapter that does not behave like this, you can choose to ignore this error.
|
||||
func (e *Enforcer) GetAllowedObjectConditions(user string, action string, prefix string) ([]string, error) {
|
||||
permissions, err := e.GetImplicitPermissionsForUser(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var objectConditions []string
|
||||
for _, policy := range permissions {
|
||||
// policy {sub, obj, act}
|
||||
if policy[2] == action {
|
||||
if !strings.HasPrefix(policy[1], prefix) {
|
||||
return nil, errors.ErrObjCondition
|
||||
}
|
||||
objectConditions = append(objectConditions, strings.TrimPrefix(policy[1], prefix))
|
||||
}
|
||||
}
|
||||
|
||||
if len(objectConditions) == 0 {
|
||||
return nil, errors.ErrEmptyCondition
|
||||
}
|
||||
|
||||
return objectConditions, nil
|
||||
}
|
||||
|
||||
// removeDuplicatePermissions Convert permissions to string as a hash to deduplicate.
|
||||
func removeDuplicatePermissions(permissions [][]string) [][]string {
|
||||
permissionsSet := make(map[string]bool)
|
||||
res := make([][]string, 0)
|
||||
for _, permission := range permissions {
|
||||
permissionStr := util.ArrayToString(permission)
|
||||
if permissionsSet[permissionStr] {
|
||||
continue
|
||||
}
|
||||
permissionsSet[permissionStr] = true
|
||||
res = append(res, permission)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// GetImplicitUsersForResource return implicit user based on resource.
|
||||
// for example:
|
||||
// p, alice, data1, read
|
||||
// p, bob, data2, write
|
||||
// p, data2_admin, data2, read
|
||||
// p, data2_admin, data2, write
|
||||
// g, alice, data2_admin
|
||||
// GetImplicitUsersForResource("data2") will return [[bob data2 write] [alice data2 read] [alice data2 write]]
|
||||
// GetImplicitUsersForResource("data1") will return [[alice data1 read]]
|
||||
// Note: only users will be returned, roles (2nd arg in "g") will be excluded.
|
||||
func (e *Enforcer) GetImplicitUsersForResource(resource string) ([][]string, error) {
|
||||
return e.GetNamedImplicitUsersForResource("g", resource)
|
||||
}
|
||||
|
||||
// GetNamedImplicitUsersForResource return implicit user based on resource with named policy support.
|
||||
// This function handles resource role relationships through named policies (e.g., g2, g3, etc.).
|
||||
// for example:
|
||||
// p, admin_group, admin_data, *
|
||||
// g, admin, admin_group
|
||||
// g2, app, admin_data
|
||||
// GetNamedImplicitUsersForResource("g2", "app") will return users who have access to admin_data through g2 relationship.
|
||||
func (e *Enforcer) GetNamedImplicitUsersForResource(ptype string, resource string) ([][]string, error) {
|
||||
permissions := make([][]string, 0)
|
||||
subjectIndex, _ := e.GetFieldIndex("p", "sub")
|
||||
objectIndex, _ := e.GetFieldIndex("p", "obj")
|
||||
rm := e.GetRoleManager()
|
||||
if rm == nil {
|
||||
return nil, fmt.Errorf("role manager is not initialized")
|
||||
}
|
||||
|
||||
isRole := make(map[string]bool)
|
||||
roles, err := e.GetAllRoles()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, role := range roles {
|
||||
isRole[role] = true
|
||||
}
|
||||
|
||||
// Get all resource types that the resource can access through ptype (e.g., g2)
|
||||
ptypePolicies, _ := e.GetNamedGroupingPolicy(ptype)
|
||||
resourceAccessibleResourceTypes := make(map[string]bool)
|
||||
|
||||
for _, ptypePolicy := range ptypePolicies {
|
||||
if ptypePolicy[0] == resource { // ptypePolicy[0] is the resource
|
||||
resourceAccessibleResourceTypes[ptypePolicy[1]] = true // ptypePolicy[1] is the resource type it can access
|
||||
}
|
||||
}
|
||||
|
||||
for _, rule := range e.model["p"]["p"].Policy {
|
||||
obj := rule[objectIndex]
|
||||
sub := rule[subjectIndex]
|
||||
|
||||
// Check if this policy is directly for the resource OR for a resource type the resource can access
|
||||
if obj == resource || resourceAccessibleResourceTypes[obj] {
|
||||
if !isRole[sub] {
|
||||
permissions = append(permissions, rule)
|
||||
} else {
|
||||
users, err := rm.GetUsers(sub)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
implicitUserRule := deepCopyPolicy(rule)
|
||||
implicitUserRule[subjectIndex] = user
|
||||
permissions = append(permissions, implicitUserRule)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res := removeDuplicatePermissions(permissions)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetImplicitUsersForResourceByDomain return implicit user based on resource and domain.
|
||||
// Compared to GetImplicitUsersForResource, domain is supported.
|
||||
func (e *Enforcer) GetImplicitUsersForResourceByDomain(resource string, domain string) ([][]string, error) {
|
||||
permissions := make([][]string, 0)
|
||||
subjectIndex, _ := e.GetFieldIndex("p", "sub")
|
||||
objectIndex, _ := e.GetFieldIndex("p", "obj")
|
||||
domIndex, _ := e.GetFieldIndex("p", "dom")
|
||||
rm := e.GetRoleManager()
|
||||
if rm == nil {
|
||||
return nil, fmt.Errorf("role manager is not initialized")
|
||||
}
|
||||
|
||||
isRole := make(map[string]bool)
|
||||
|
||||
if roles, err := e.GetAllRolesByDomain(domain); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
for _, role := range roles {
|
||||
isRole[role] = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, rule := range e.model["p"]["p"].Policy {
|
||||
obj := rule[objectIndex]
|
||||
if obj != resource {
|
||||
continue
|
||||
}
|
||||
|
||||
sub := rule[subjectIndex]
|
||||
|
||||
if !isRole[sub] {
|
||||
permissions = append(permissions, rule)
|
||||
} else {
|
||||
if domain != rule[domIndex] {
|
||||
continue
|
||||
}
|
||||
users, err := rm.GetUsers(sub, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
implicitUserRule := deepCopyPolicy(rule)
|
||||
implicitUserRule[subjectIndex] = user
|
||||
permissions = append(permissions, implicitUserRule)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res := removeDuplicatePermissions(permissions)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetImplicitObjectPatternsForUser returns all object patterns (with wildcards) that a user has for a given domain and action.
|
||||
// For example:
|
||||
// p, admin, chronicle/123, location/*, read
|
||||
// p, user, chronicle/456, location/789, read
|
||||
// g, alice, admin
|
||||
// g, bob, user
|
||||
//
|
||||
// GetImplicitObjectPatternsForUser("alice", "chronicle/123", "read") will return ["location/*"].
|
||||
// GetImplicitObjectPatternsForUser("bob", "chronicle/456", "read") will return ["location/789"].
|
||||
func (e *Enforcer) GetImplicitObjectPatternsForUser(user string, domain string, action string) ([]string, error) {
|
||||
roles, err := e.GetImplicitRolesForUser(user, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
subjects := append([]string{user}, roles...)
|
||||
subjectIndex, _ := e.GetFieldIndex("p", constant.SubjectIndex)
|
||||
domainIndex, _ := e.GetFieldIndex("p", constant.DomainIndex)
|
||||
objectIndex, _ := e.GetFieldIndex("p", constant.ObjectIndex)
|
||||
actionIndex, _ := e.GetFieldIndex("p", constant.ActionIndex)
|
||||
|
||||
patterns := make(map[string]struct{})
|
||||
for _, rule := range e.model["p"]["p"].Policy {
|
||||
sub := rule[subjectIndex]
|
||||
matched := false
|
||||
for _, subject := range subjects {
|
||||
if sub == subject {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
|
||||
if !e.matchDomain(domainIndex, domain, rule) {
|
||||
continue
|
||||
}
|
||||
|
||||
ruleAction := rule[actionIndex]
|
||||
if ruleAction != action && ruleAction != "*" {
|
||||
continue
|
||||
}
|
||||
|
||||
obj := rule[objectIndex]
|
||||
patterns[obj] = struct{}{}
|
||||
}
|
||||
|
||||
result := make([]string, 0, len(patterns))
|
||||
for pattern := range patterns {
|
||||
result = append(result, pattern)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// matchDomain checks if the domain matches the rule domain using pattern matching.
|
||||
func (e *Enforcer) matchDomain(domainIndex int, domain string, rule []string) bool {
|
||||
if domainIndex < 0 || domain == "" {
|
||||
return true
|
||||
}
|
||||
ruleDomain := rule[domainIndex]
|
||||
if ruleDomain == domain {
|
||||
return true
|
||||
}
|
||||
for _, rm := range e.rmMap {
|
||||
if rm.Match(domain, ruleDomain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, crm := range e.condRmMap {
|
||||
if crm.Match(domain, ruleDomain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user