casbin / pycasbin

An authorization library that supports access control models like ACL, RBAC, ABAC in Python
https://casbin.org
Apache License 2.0
1.4k stars 194 forks source link

[Bug] Error When Calling `get_implicit_permissions_for_user` #352

Open zhou93 opened 4 months ago

zhou93 commented 4 months ago

Error When Calling get_implicit_permissions_for_user

In the above scenario, calling the function get_implicit_permissions_for_user results in an error.

From the code, we can see:

def get_named_implicit_permissions_for_user(self, ptype, user, domain="", filter_policy_dom=True):
    """
    gets implicit permissions for a user or role by named policy.
    Compared to get_permissions_for_user(), this function retrieves permissions for inherited roles.
    For example:
    p, admin, data1, read
    p, alice, data2, read
    g, alice, admin

    get_permissions_for_user("alice") can only get: [["alice", "data2", "read"]].
    But get_implicit_permissions_for_user("alice") will get: [["admin", "data1", "read"], ["alice", "data2", "read"]].

    For given domain policies are filtered by corresponding domain matching function of DomainManager
    Inherited roles can be matched by domain. For domain neutral policies set:
        filter_policy_dom = False

    filter_policy_dom: bool - For given *domain*, policies will be filtered by domain as well. Default = True
    """
    roles = self.get_implicit_roles_for_user(user, domain)

    roles.insert(0, user)

    res = []

    # policy domain should be matched by domain_match_fn of DomainManager
    domain_matching_func = self.get_role_manager().domain_matching_func
    if domain and domain_matching_func != None:
        domain = partial(domain_matching_func, domain)

    for role in roles:
        permissions = self.get_named_permissions_for_user_in_domain(
            ptype, role, domain if filter_policy_dom else ""
        )
        res.extend(permissions)

    return res

This function calls get_role_manager, which is defined as follows:

def get_role_manager(self):
    """gets the current role manager."""
    return self.rm_map["g"]

At this point, rm_map does not contain g, because g is in cond_rm_map.

Originally posted by @zhou93 in https://github.com/casbin/pycasbin/issues/350#issuecomment-2188033094

casbin-bot commented 4 months ago

@techoner @Nekotoxin

zhou93 commented 4 months ago

Additionally, functions like get_implicit_roles_for_user do not return the correct results when g is defined with conditions. Is this the expected behavior?

For example:

def get_implicit_roles_for_user(self, name, domain=""):
    """
    gets implicit roles that a user has.
    Compared to get_roles_for_user(), this function retrieves indirect roles besides direct roles.
    For example:
    g, alice, role:admin
    g, role:admin, role:user

    get_roles_for_user("alice") can only get: ["role:admin"].
    But get_implicit_roles_for_user("alice") will get: ["role:admin", "role:user"].
    """
    res = []
    queue = [name]

    while queue:
        name = queue.pop(0)

        for rm in self.rm_map.values():
            roles = rm.get_roles(name, domain)
            for r in roles:
                if r not in res:
                    res.append(r)
                    queue.append(r)

    return res

In the above function, it only retrieves roles from rm_map and does not check cond_rm_map. I expect that the roles assigned under conditions should also be retrieved.

hsluoyz commented 4 months ago

@leeqvip