[openstack-dev] [keystone] Domain-namespaced user attributes in SAML assertions from Keystone IdPs

Lance Bragstad lbragstad at gmail.com
Mon Sep 24 14:16:59 UTC 2018


On Mon, Sep 24, 2018 at 7:00 AM Colleen Murphy <colleen at gazlene.net> wrote:

> This is in regard to https://launchpad.net/bugs/1641625 and the proposed
> patch https://review.openstack.org/588211 for it. Thanks Vishakha for
> getting the ball rolling.
>
> tl;dr: Keystone as an IdP should support sending
> non-strings/lists-of-strings as user attribute values, specifically lists
> of keystone groups, here's how that might happen.
>
> Problem statement:
>
> When keystone is set up as a service provider with an external
> non-keystone identity provider, it is common to configure the mapping rules
> to accept a list of group names from the IdP and map them to some property
> of a local keystone user, usually also a keystone group name. When keystone
> acts as the IdP, it's not currently possible to send a group name as a user
> property in the assertion. There are a few problems:
>
>     1. We haven't added any openstack_groups key in the creation of the
> SAML assertion (
> http://git.openstack.org/cgit/openstack/keystone/tree/keystone/federation/idp.py?h=14.0.0#n164
> ).
>     2. If we did, this would not be enough. Unlike other IdPs, in keystone
> there can be multiple groups with the same name, namespaced by domain. So
> it's not enough for the SAML AttributeStatement to contain a
> semi-colon-separated list of group names, since a user could theoretically
> be a member of two or more groups with the same name.
>    * Why can't we just send group IDs, which are unique? Because two
> different keystones are not going to have independent groups with the same
> UUID, so we cannot possibly map an ID of a group from keystone A to the ID
> of a different group in keystone B. We could map the ID of the group in in
> A to the name of a group in B but then operators need to create groups with
> UUIDs as names which is a little awkward for both the operator and the user
> who now is a member of groups with nondescriptive names.
>     3. If we then were able to encode a complex type like a group dict in
> a SAML assertion, we'd have to deal with it on the service provider side by
> being able to parse such an environment variable from the Apache headers.
>     4. The current mapping rules engine uses basic python string
> formatting to translate remote key-value pairs to local rules. We would
> need to change the mapping API to work with values more complex than
> strings and lists of strings.
>
> Possible solution:
>
> Vishakha's patch (https://review.openstack.org/588211) starts to solve
> (1) but it doesn't go far enough to solve (2-4). What we talked about at
> the PTG was:
>
>     2. Encode the group+domain as a string, for example by using the dict
> string repr or a string representation of some custom XML and maybe base64
> encoding it.
>         * It's not totally clear whether the AttributeValue class of the
> pysaml2 library supports any data types outside of the xmlns:xs namespace
> or whether nested XML is an option, so encoding the whole thing as an
> xs:string seems like the simplest solution.
>

Encoding this makes sense. We can formally support different SAML data
types in the future if a better solution comes along. We would have to make
the service provider deal with both types of encoding, but we could
eventually consolidate, and users shouldn't know the difference. Right?


>     3. The SP will have to be aware that openstack_groups is a special key
> that needs the encoding reversed.
>         * I wrote down "MultiDict" in my notes but I don't recall exactly
> what format the environment variable would take that would make a MultiDict
> make sense here, in any case I think encoding the whole thing as a string
> eliminates the need for this.
>     4. We didn't talk about the mapping API, but here's what I think. If
> we were just talking about group names, the mapping API today would work
> like this (slight oversimplification for brevity):
>
> Given a list of openstack_groups like ["A", "B", "C"], it would work like
> this:
>
> [
>   {
>     "local":
>     [
>       {
>         "group":
>         {
>           "name": "{0}",
>           "domain":
>           {
>             "name": "federated_domain"
>           }
>         }
>       }
>     ], "remote":
>     [
>       {
>         "type": "openstack_groups"
>       }
>     ]
>   }
> ]
> (paste in case the spacing makes this unreadable:
> http://paste.openstack.org/show/730623/ )
>
> But now, we no longer have a list of strings but something more like
> [{"name": "A", "domain_name": "Default"} {"name": "B", "domain_name":
> "Default", "name": "A", "domain_name": "domainB"}]. Since {0} isn't a
> string, this example doesn't really work. Instead, let's assume that in
> step (3) we converted the decoded AttributeValue text to an object. Then
> the mapping could look more like this:
>
> [
>   {
>     "local":
>     [
>       {
>         "group":
>         {
>           "name": "{0.name}",
>           "domain":
>           {
>             "name": "{0.domain_name}"
>           }
>         }
>       }
>     ], "remote":
>     [
>       {
>         "type": "openstack_groups"
>       }
>     ]
>   }
> ]
> (paste: http://paste.openstack.org/show/730622/ )
>
>
I can't come up with a reason not to do this at the moment. If we serialize
the group+domain name information in SAML, then it seems appropriate to
teach the service provider how to deserialize it and apply it to mappings.
Otherwise, does it make sense to build serialization into the identity
provider if we aren't going to use the domain name?


> Alternatively, we could forget about the namespacing problem and simply
> say we only pass group names in the assertion, and if you have ambiguous
> group names you're on your own. We could also try to support both, e.g.
> have an openstack_groups mean a list of group names for simpler use cases,
> and openstack_groups_unique mean the list of encoded group+domain strings
> for advanced use cases.
>
> Finally, whatever we decide for groups we should also apply to
> openstack_roles which currently only supports global roles and not
> domain-specific roles.
>
> (It's also worth noting, for clarity, that the samlize function does
> handle namespaced projects, but this is because it's retrieving the project
> from the token and therefore there is only ever one project and one project
> domain so there is no ambiguity.)
>
> Thoughts?
>
> - Colleen (cmurphy)
>
> __________________________________________________________________________
> OpenStack Development Mailing List (not for usage questions)
> Unsubscribe: OpenStack-dev-request at lists.openstack.org?subject:unsubscribe
> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openstack.org/pipermail/openstack-dev/attachments/20180924/8e4c0789/attachment.html>


More information about the OpenStack-dev mailing list