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

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


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

> On Mon, Sep 24, 2018, at 4:16 PM, Lance Bragstad wrote:
> > 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?
>
> The only way this would make a difference to the user is if they need to
> debug a request by actually looking at the response to this request[1]. If
> we were to base64-encode the string that immediately obfuscates what the
> actual value is. I'm not really sure if we need to base64-encode it or just
> serialize it some other way.
>

Oh - yeah that makes sense. In your opinion, does that prevent us from
adopting another way of solving the problem if we find a better data type?


>
> [1]
> https://developer.openstack.org/api-ref/identity/v3-ext/index.html#id404
> >
> >
> > >     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
> > >
> >
> __________________________________________________________________________
> > 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
>
> __________________________________________________________________________
> 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/cc36807f/attachment.html>


More information about the OpenStack-dev mailing list