[openstack-dev] [Keystone] Groups, mappings, and tokens

Adam Young ayoung at redhat.com
Wed Dec 19 14:22:24 UTC 2012


On 12/18/2012 05:26 PM, David Chadwick wrote:
> Hi Adam
>
> On 18/12/2012 21:26, Adam Young wrote:
>> One thing became clear to me during the meeting is that none of the
>> mechanisms we have been talking about are going to be useful without
>> extending the token mechanism.  Let me give you a brief overview, and
>> you can tell me what you plan on doing.
>>
>> With recent refactoring, the token generation moved into
>>
>> https://github.com/openstack/keystone/blob/master/keystone/token/controllers.py#L34 
>>
>>
>>
>> This code process auth via: userid/password, tokens, or REMOTE_USER.
>>
>> Unfortunately, the identity API authenticate method does too much: it
>> authenticates the user and also returns the roles etc:  This makes it
>> hard to reuse this code in conjunction with the token generation.  We
>> probably need to first and foremost split the identity.authenticate
>> method into two pieces, authN and authZ, and then we can make the authZ
>> step common to both.
>
> I agree. But I also think you need a separate function that generates 
> a token with a complementary function that validates a token (if you 
> dont have these already). Then the code for token creation and 
> validation is completely removed from the rest of the logic and can be 
> changed at will, since none of the other code will be effected by it. 
> I would suggest methods such as
>
> a) CreateToken: Given a set of tenants and roles (collectively known 
> as OpenStack attributes, which come out of the attribute mapping 
> function) return a token. The caller does not care if it is a scoped 
> token or unscoped token or any other type of token as it is simply a 
> binary blob to be carried around. Note that the set of input 
> attributes should be able to grow as OpenStack grows e.g. domains 
> should be able to be input as well as unique user IDs etc. If the 
> token needs to be constrained, then other attributes could be input as 
> well with the OpenStack attributes, such as service endpoints or other 
> constraining attributes.
>
> b) ValidateToken: Given a token, return the set of tenants and roles 
> (i.e. OpenStack attributes) that are associated with it.

Yes, we have these.  There are both external APIs for both of these 
functions and internal ones.

For V2:

http://docs.openstack.org/developer/keystone/api_curl_examples.html#get-tokens-token-id

This has been identified as something we want to deprecate in favor of 
not having the ID in the URL.  The V3 Version takes the token in the 
message body instead.

The call to get a new token is 
http://docs.openstack.org/developer/keystone/api_curl_examples.html#id3

This is the call that executes the
https://github.com/openstack/keystone/blob/master/keystone/token/controllers.py#L34 


There are several variation on what this accepts:

1.  UserID and password
2. Token (convert unscoped token to scoped token)
3. REMOTE_USER set by Apache or other web server container.

So it is this code path that needs to be modified to do role 
assignment.   The token validation code will also need to be able to 
confirm role assignement, which is a new scary thing that I had not 
thought about.  If a mapping changes, it changes who Has roles, which 
may invalidate tokens.  The same is true of group membership.

So changing mappings and changing roles will both potentially be token 
revocation events.  That is going to complicate matters somewhat.




>
> Note however that the token that is created is known as a bearer token 
> ie. whoever has it, effectively has the OpenStack attributes 
> associated with it. In order to move to a personalised token one can 
> use Holder of Key, in which the public key of the token owner is also 
> associated with the token. So you would need to add the public key of 
> the owner as another input parameter to CreateToken, and it would 
> return the token and a random challenge. The challenge is sent to the 
> owner, he signs the challenge and token, and the signed challenge and 
> token are given to ValidateToken which checks the signature against 
> the public key to ensure that it is the token owner who is presenting 
> it, and that it is not a replay (if you only want tokens to be used 
> once. Otherwise the challenge could be a timestamp allowing it to be 
> used multiple times until the time expires).
I'm aware of the shortcomings.  Before we implement this, we will work 
up an X509 or Kerberos  Based solution.

>
>
>>
>> Mapping comes in at the authZ step.
>
> agreed
>
>  The current logic for a scoped
>> token is to enumerate the roles for a given user/tenant pairing.
>
> I am suggesting that this logic will be a wrapper for the token 
> generation and validation mechanism. This logic might wish to
> a) generate an unscoped token when a set of tenants is input
> b) generate a scoped token when a single tenant is input
> c) call the mapper when a set of organisational attributes are input
> etc. as you wish

Interesting.  So the mapper would only be called based on a trigger.  
Wouldn't that prevent using the mapper being used for groups?

>
>
>>
>> What needs to happen is we need to use mapping and groups to generate
>> the list of roles.
>
> agreed
>
>>
>> Since the mapping code is so close to implemented, I am OK if we try to
>> push through and do groups on top of roles.  I think we still want to
>> have a "group" web API, but I can see the argument that with mapping, we
>> will be much more capable of mapping to complex LDAP structures.
>
> Mapping is independent of the LDAP structure. The code for handling 
> groups is responsible for both storing and retrieving the groups from 
> LDAP before the mapping function is called.

Right.  What I was saying is that LDAP has many implementations.  I like 
Mapping as a more flexible approach to dealing with LDAP in the wild.

>
>
>> However, I am not sure if the mapping mechanism as specified will work
>> if there is no implementation that the org_attributes can point to.
>
> The groups ARE the org attributes. They replace them for a centralised 
> Keystone. The org attributes come from IDPs in a federated Keystone. I 
> have just updated the role mapping blueprint to clarify this.

>>
>> Am I correct in understanding that  the difference between the current
>> group review request (https://review.openstack.org/#/c/18138/) and the
>> Kent approach is how to assign groups to roles?
>
> Yes this is the main difference. In the Kent approach there would be 
> no assigning of groups to roles, but rather mappings would be set up 
> between groups and roles/tenants/projects/domains
I understand this better now.  Mapping is between groups and roles. I 
previously though mapping was a group implementation.   Thanks for 
clarifying

>
>>
>>
>> It is my understanding that, if we were to use  the Kent approach in
>> conjunction with LDAP, we would still use groupOfNames for groups, and
>> assign users to groups using the members attribute, but then the role
>> assignments would be done via mapping.
>
> this is correct
>
>   In the case, the org_attribute
>> would be the group, and the os_attribute would be the role for the 
>> tenant?
>
> I think the os_attributes would be both the role and the tenant, 
> because after the user has authenticated, the only thing Keystone 
> needs to pick up for him is his groups from the gON in LDAP (or SQL 
> db). then it calls the mapping functionality to pick up the tenant and 
> role
That makes sense.
>
>
>>
>> I think we need to lay out the python code necessary to:
>>
>> 1. assign the groups to a role for a tenant
>> 2. create a scoped token where the user gets their roles from the group.
>>
>> we can call the group "superadmins"  and the role "admin"   the tenant
>> "default_tenant".
>
>
> So you could create the superadmin group in LDAP as a gON.
> Then assign user "cn=....." as a member.
> Then you create a mapping from group=superadmin to role=admin and 
> tenant=default_tenant in the attribute mapper
This is the step I want to see implemented using 
https://review.openstack.org/#/c/18280/


>
> Now user cn=.... logs in, is authenticated, his groups are picked up 
> by scanning the member attributes of each gON for his DN, then you 
> call the mapper passing the group=superadmin and receiving the output 
> role=admin and tenant=default_tenant
Specifically,  we need a function called from:
https://github.com/openstack/keystone/blob/master/keystone/token/controllers.py#L304

That would generate the roles for a user based on mapping.  The term 
Metadata for role assignements predates the Keystone project.


>
> What you do next with tokens is surely as now isnt it?
>
> regards
>
> David
>
>>
>>
>>
>>
>>
>> _______________________________________________
>> OpenStack-dev mailing list
>> OpenStack-dev at lists.openstack.org
>> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
>>




More information about the OpenStack-dev mailing list