php-casbin/laravel-authz

array_combine error with different request and policy definitions

Closed this issue · 13 comments

Hello everyone!
I'm implementing role-based access control in my Laravel application using php-casbin/laravel-authz. I'm encountering an error when trying to enforce policies using a custom model where request and policy definitions have different numbers of parameters.
My model configuration:


[request_definition]
r = sub, obj, act, dom

[policy_definition]
p = sub, obj, act, eft, dom

[role_definition]
g = _, _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act

The error I'm getting is:
array_combine(): Argument #1 ($keys) and argument #2 ($values) must have the same number of elements

This occurs in CoreEnforcer.php:761 when calling enforce(). I'm using a guarded enforcer like this:

$enforcer = Enforcer::guard('controller');
$hasPermission = $enforcer->enforce($role, $controller, $method, $domain);

This is a practical working example.

related issue #127

Hello @leeqvip,
could you please review this issue?

@swarakaka This is probably not a problem with php-casbin itself.
Can you debug and see if laravel-authz has problems loading policies? Can you getPolicy() and print it?

Yes, all the policies are successfully returning. even for the user.

$policies = collect($enforcer->getPolicy());
Log::info("policies: ", [$policies->all()]);

[2024-12-12 16:35:21] local.INFO: policies: [[["admin","Brand","name","read","allow","system"],["admin","Brand","name","write","allow","system"],["admin","Brand","name","update","allow","system"],["admin","Brand","name","delete","allow","system"],["admin","User","username","read","allow","system"],["admin","User","username","write","allow","system"],["admin","User","username","update","allow","system"],["admin","User","username","delete","allow","system"],["admin","User","email","read","allow","system"],["admin","User","email","write","allow","system"],["admin","User","email","update","allow","system"],["admin","User","email","delete","allow","system"],["admin","User","password","read","allow","system"],["admin","User","password","write","allow","system"],["admin","User","password","update","allow","system"],["admin","User","password","delete","allow","system"],["admin","User","tenant","read","allow","system"],["admin","User","tenant","write","allow","system"],["admin","User","tenant","update","allow","system"],["admin","User","tenant","delete","allow","system"],["admin","Role","name","read","allow","system"],["admin","Role","name","write","allow","system"],["admin","Role","name","update","allow","system"],["admin","Role","name","delete","allow","system"],["admin","Role","description","read","allow","system"],["admin","Role","description","write","allow","system"],["admin","Role","description","update","allow","system"],["admin","Role","description","delete","allow","system"],["admin","City","name","read","allow","system"],["admin","City","name","write","allow","system"],["admin","City","name","update","deny","system"],["admin","City","name","delete","deny","system"],["admin","City","post_code","read","allow","system"],["admin","City","post_code","write","allow","system"],["admin","City","post_code","update","deny","system"],["admin","City","post_code","delete","deny","system"],["admin","City","province_id","read","allow","system"],["admin","City","province_id","write","allow","system"],["admin","City","province_id","update","deny","system"],["admin","City","province_id","delete","deny","system"],["admin","City","longitude","read","allow","system"],["admin","City","longitude","write","allow","system"],["admin","City","longitude","update","deny","system"],["admin","City","longitude","delete","deny","system"],["admin","City","latitude","read","allow","system"],["admin","City","latitude","write","allow","system"],["admin","City","latitude","update","deny","system"],["admin","City","latitude","delete","deny","system"],["admin","City","created_by","read","allow","system"],["admin","City","created_by","write","allow","system"],["admin","City","created_by","update","deny","system"],["admin","City","created_by","delete","deny","system"],["admin","City","updated_by","read","allow","system"],["admin","City","updated_by","write","allow","system"],["admin","City","updated_by","update","deny","system"],["admin","City","updated_by","delete","deny","system"],["admin","City","deleted_by","read","allow","system"],["admin","City","deleted_by","write","allow","system"],["admin","City","deleted_by","update","deny","system"],["admin","City","deleted_by","delete","deny","system"],["admin","UsersController","index","allow","system"],["admin","UsersController","store","allow","system"],["admin","UsersController","show","allow","system"],["admin","UsersController","update","allow","system"],["admin","UsersController","destroy","allow","system"],["admin","UsersController","permissions","allow","system"],["admin","UsersController","assign","allow","system"],["admin","BrandsController","index","deny","system"],["admin","BrandsController","store","deny","system"],["admin","BrandsController","update","deny","system"],["admin","BrandsController","destroy","deny","system"],["admin","CitiesController","index","deny","system"],["admin","CitiesController","store","deny","system"],["admin","CitiesController","update","deny","system"],["admin","CitiesController","destroy","deny","system"],["admin","CountriesController","index","deny","system"],["admin","CountriesController","store","deny","system"],["admin","CountriesController","update","deny","system"],["admin","CountriesController","destroy","deny","system"],["admin","PoliciesController","index","deny","system"],["admin","PoliciesController","getAllRoles","deny","system"],["admin","PoliciesController","getModels","deny","system"],["admin","PoliciesController","getAttributes","deny","system"],["admin","PoliciesController","rolePermissionsByModel","deny","system"],["admin","PoliciesController","getControllers","deny","system"],["admin","PoliciesController","getControllerActions","deny","system"],["admin","PoliciesController","rolePermissionsByController","deny","system"],["admin","PoliciesController","createRole","deny","system"],["admin","PoliciesController","storeRolePermissionsByModel","deny","system"],["admin","PoliciesController","storeControllerPermissions","deny","system"]]]

@swarakaka

["admin","Brand","name","read","allow","system"]

Some policies have 6 columns, but your model configuration only has 5 parameters

@leeqvip
Yes it is true that some policies have 6 columns but I use two different models. As shown in the code, I am using the controller guard.

$enforcer = Enforcer::guard('controller');
$hasPermission = $enforcer->enforce($role, $controller, $method, $domain);

controller model:

[request_definition]
r = sub, obj, act, dom

[policy_definition]
p = sub, obj, act, eft, dom

[role_definition]
g = _, _, _

[policy_effect]
e = some(where (p.eft == allow)

[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act

@swarakaka So you need to modify your model or delete the policies that do not comply

@leeqvip
What do you mean by modifying the model? Which model, the controller or the base one?
So you can't have two different models and each check according to the columns in the rules table?

@swarakaka If you have multiple enforcers, different enforcers should use different adapters or data tables.

@leeqvip

Thank you very much for your reply. That's a good way. I found another solution, which compares all polices by roles:

return $roles->contains(function ($role) use ($enforcer, $resource, $action, $tenant) {
            $policies = collect($enforcer->getImplicitPermissionsForUser($role))->filter(function ($policy) {
                return is_array($policy) && count($policy) === 5;
            });
            if ($policies->isEmpty()) {
                return false;
            }
            return  $policies->contains(function ($policy) use ($role, $resource, $action, $tenant) {
                return $policy[0] === $role
                    && $policy[1] === $resource
                    && $policy[2] === $action
                    && $policy[3] === "allow"
                    && $policy[4] === $tenant;
            });
        });

Do you want to determine the role inheritance relationship? You can try getImplicitRolesForUser or getRolesForUser?

No. Because I’ve already got the roles.
$roles = collect($enforcer->getImplicitRolesForUser($identifier, $tenant));

As I described the problem above. I can't do my comparison with Enforcer::enforce(), hence I do my comparison with cops.

If you want to decide whether a role has direct permissions, you can modify the expression configured in the model.
m = g(r.sub, p.sub, r.dom) ... to m = r.sub == p.sub ...

@leeqvip
I don't know if the problem is related to roles and permissions. But I want to give the permissions directly to the roles. Users also have one or more roles.