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

Colleen Murphy colleen at gazlene.net
Mon Sep 24 16:27:05 UTC 2018


On Mon, Sep 24, 2018, at 4:35 PM, Lance Bragstad wrote:
> 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?

Not 100% sure. The format of the SAML assertion is part of our API so we do have to be really careful about changing it, that's why I nacked the current patch. But how much leeway we have might depend on what the alternate solution is: maybe if the end result changes the NameFormat or the xsi:type of the Attribute, and we still support the xsi:type="xs:string" solution (the one we're discussing now), that might be okay?

> 
> 
> >
> > [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
> >
> __________________________________________________________________________
> 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



More information about the OpenStack-dev mailing list