With using V3 cloud admin policy, domain admin unable to list role assignment for projects in his domain

Bug #1437407 reported by Guang Yee on 2015-03-27
This bug affects 7 people
Affects Status Importance Assigned to Milestone
OpenStack Identity (keystone)
Guang Yee
Dan Nguyen

Bug Description

With v3 cloud admin policy file, domain admin can assignment roles to user for projects in his domain. However, he's unable to list those assignment.

The expectation is that domain admin should be able to list role assignments for projects in his own domain.

Priti Desai (priti-desai) wrote :

As a domain administrator (using token scoped to domain) - unable to list role assignments for a project in my domain:

$ openstack role assignment list --project 3013df710d604ed68ce8e3daf8089386
ERROR: openstack You are not authorized to perform the requested action, identity:list_role_assignments. (HTTP 403)

Brad Pokorny (bpokorny) wrote :

Priti and I have also tried fixing this with policy file modifications. Here's what we've got currently in the v3 policy file for keystone:

    "admin_on_domain_filter" : "rule:cloud_admin or (rule:admin_required and domain_id:%(scope.domain.id)s)",
    "admin_on_project_filter" : "rule:cloud_admin or (rule:admin_required and (project_id:%(scope.project.id)s or domain_id:%(target.project.domain_id)s))",
    "identity:list_role_assignments": "rule:admin_on_domain_filter or rule:admin_on_project_filter",

But that hasn't allowed us to get further. To rule out any possible limitations in the keystone client, I tried running directly to the API, but got the same error (TOKEN in the below command is a domain scoped token retrieved by an admin of the domain the project is under):

$ curl -sX GET https://keystonehost:443/v3/role_assignments?scope.project.id=63901d683ce04c248f5f2786db05a0b1 -H "X-Auth-Token: $TOKEN" | jq .
  "error": {
    "title": "Forbidden",
    "code": 403,
    "message": "You are not authorized to perform the requested action: identity:list_role_assignments (Disable debug mode to suppress these details.)"

So I'm not sure at this point whether we've missed something in the policy file or if there's a limitation in the keystone code that doesn't allow this via the API.

Guang Yee (guang-yee) wrote :

Don't think it'll work by just tweaking policy.json. The way our authorization model works, we are essentially doing policy checks prior to backend actions.


In this case, we are matching the incoming credential against the query filter. In other words, the target object hasn't been retrieved yet.

Because Oslo policy engine can only do plain attribute matches. It does not know anything about objects and their relationships. In other words, to use oslo policy the way it is implemented right now, the consumer (in this case, the API code) would have to interpret the object relations for the target object and flatten them into meta data (key-value pairs) before feeding them to the enforce method.

Otherwise, we would have to change the Oslo policy to take object relationship into consideration. Or we would have to pass the filters to the backend and then filter the result on the way out.

Changed in keystone:
status: New → Confirmed
Lin Hua Cheng (lin-hua-cheng) wrote :

I agree with Guang, tweaking the policy.json won't be enough.

The problem is in the rule "domain_id:%(target.project.domain_id)s", the value won't get set before the policy is enforced.

This would involve more work to enhance the @filterprotected decorator to work for the case mentioned.

Changed in keystone:
importance: Undecided → Medium
Changed in keystone:
status: Confirmed → Triaged
status: Triaged → Confirmed
Changed in keystone:
assignee: nobody → Lin Hua Cheng (lin-hua-cheng)
Priti Desai (priti-desai) wrote :

Hi Lin, Here is my working changes:


- @controller.filterprotected('group.id', 'role.id',
- 'scope.domain.id', 'scope.project.id',
- 'scope.OS-INHERIT:inherited_to', 'user.id')
+ def _check_list_role_assignments(self, context):
+ project_id = context['query_string'].get('scope.project.id')
+ target = {}
+ if project_id is not None:
+ target['project'] = self.assignment_api.get_project(
+ context['query_string']['scope.project.id'])
+ return target
+ @controller.filterprotected_with_callback(
+ _check_list_role_assignments,
+ 'group.id', 'role.id', 'scope.domain.id', 'scope.project.id',
+ 'scope.OS-INHERIT:inherited_to', 'user.id')
     def list_role_assignments(self, context, filters):


+ return filterprotected_with_callback(None, *filters)
+def filterprotected_with_callback(callback, *filters):
+ """Wraps filtered API calls with role based access controls (RBAC)."""

                 # Now any formal url parameters
                 for key in kwargs:
                     target[key] = kwargs[key]
+ if callback is not None:
+ target['target'] = callback(self, context, **kwargs)

Priti Desai (priti-desai) wrote :

I can create a review request and send it your way, I am having difficulty writing unit tests :(

Lin Hua Cheng (lin-hua-cheng) wrote :

Ooops sorry... Hi Priti, I wasn't aware you're already working on this. It would be easier if I just re-assign the bug to you.

Yeah, you can submit the gerrit patch and add me as reviewer.

Changed in keystone:
assignee: Lin Hua Cheng (lin-hua-cheng) → Priti Desai (priti-desai)
Priti Desai (priti-desai) wrote :

Thanks Lin, I just saw your comment, will upload the patch next week.

Fix proposed to branch: master
Review: https://review.openstack.org/180846

Changed in keystone:
status: Confirmed → In Progress
Chenhong Liu (liuchenhong) wrote :

I can reproduce this bug, and I dug the code.

Firstly, add policy rule like:
won't work, because assignment.controllers.RoleAssignmentV3.list_role_assignments is decorated by @flterprotected which only generate target dictionary only from API's query string. So there is not "target.project.domain_id" in the target dictionary passed to oslo.policy engine.

Secondly, based on current code, I found that the problem is that when oslo.policy engine process rule like "project_id:%(scope.project.id)s", it can not find any project id in the user's credential ( If a user authenticated via domain id, there is even not project id in the creds['token'])

Henry Nash (henry-nash) wrote :

So I think we need to think long and hard about this one. The original concept of a domain token was NOT that it gave you magical powers over all projects in your domain....rather it would be used to do domain-level management tasks (e.g. create users, groups...and create projects). It was not intended that you could use a domain token to access all projects in your domain. Likewise the original v3policysample I wrote clearly separated domain_admin from project_admin and being domain_admin did NOT mean you were automatically you had the rights to be a project_admin for all projects in your domain. I think others may have modified the sample subsequently to try and make this true....which means we fall into traps like this one.

Having said all the above, I understand the desire here. We faced a related problem with list_users() in fact when we implemented domain specific drivers - where we didn't want to allow people to list all uses across all backend drivers....so we require you to either specify a domain_id filter or we use the domain_id of the domain scoped token you are using as a query filter.

The big difference here is that in this case the thing you want to restrict the output on (domain_id) is not being returned as part of the collection....in all other filtering cases this is true...our filters apply to attributes being returned (the scope: domain_id part of the filter means it is looking for assignments on the domain...not that you should return all project assignments for projects in that domain).

So, first off, we need to decide on the conceptual model we wish to present, then we can decide how to implement it. Let's discuss!

Chenhong Liu (liuchenhong) wrote :

The big difference here is that in this case the thing you want to restrict the output on (domain_id) is not being returned as part of the collection....in all other filtering cases this is true

Henry, can you make a example on "all other filtering cases this is true", I don't quite understand.

And no matter how we decide to implement it, I think we should write some unit test cases firstly to match expected behavior.

Brad Pokorny (bpokorny) wrote :

The following use case is something I thought domain admins were supposed to be able to do:

1. Domain admin creates a project in a domain
2. Domain admin gives roles on the project to users in the domain

To accomplish #2, the domain admin could simply list the users in the domain and add users from the list. However, if there's a time lapse between #1 and #2, one of the things domain admins are going to want to do is check what roles (if any) they've already given on the project.

I realize there are larger concerns about how to handle this, as Henry points out, but we need to make sure domain admins can do what they need to manage projects in their domains.

Changed in keystone:
assignee: Priti Desai (priti-desai) → Guang Yee (guang-yee)

Reviewed: https://review.openstack.org/187899
Committed: https://git.openstack.org/cgit/openstack/keystone/commit/?id=e2061c291c0ab1a7f876cd5d6b6b97da50b3cc69
Submitter: Jenkins
Branch: master

commit e2061c291c0ab1a7f876cd5d6b6b97da50b3cc69
Author: liuchenhong <email address hidden>
Date: Fri Jun 5 12:01:42 2015 +0800

    Add testcases for list_role_assignments of v3 domains

    There are no unit testcases to cover list_role_assignments in

    Change-Id: Id7d3fe77e63aaff30e09b8b850ade9eef598ce75
    Related-Bug: #1437407

javeme (javaloveme) wrote :

We also hit this bug, this is our patch:

Henry Nash (henry-nash) wrote :

This is being solved by blueprint https://review.openstack.org/#/c/187045/ and NOT by giving the domain token magical powers. I am aiming to get this in for Liberty

Guang Yee (guang-yee) wrote :

I agree with Henry. Lets do this properly. We need to make the API unambiguous.

javeme (javaloveme) wrote :

ok, I am looking forward to the blueprint

Change abandoned by javeme (<email address hidden>) on branch: master
Review: https://review.openstack.org/210318

Guang Yee (guang-yee) wrote :
Brad Pokorny (bpokorny) wrote :

I agree. This now works in Horizon with the fixes Guang mentioned.

Changed in keystone:
status: In Progress → Fix Committed
Changed in python-keystoneclient:
status: New → Fix Committed
Steve Martinelli (stevemar) wrote :

the fix for the server was included in the mitaka-2 release of keystone

the fix for keystoneclient was included in 2.1.0 of keystoneclient

Changed in keystone:
milestone: none → mitaka-2
status: Fix Committed → Fix Released
Changed in python-keystoneclient:
status: Fix Committed → Fix Released
assignee: nobody → Dan Nguyen (daniel-a-nguyen)
importance: Undecided → Medium

Change abandoned by Samuel de Medeiros Queiroz (<email address hidden>) on branch: master
Review: https://review.openstack.org/180846
Reason: This has already been fixed by [1] and [2].

[1] https://review.openstack.org/#/q/topic:bp/list-assignment-subtree
[2] https://review.openstack.org/#/c/188184/

To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers