SAML Federated Auth Plugin

SAML is usually thought of as a WebSSO mechanism, but it can be made to work for command line operations if you use the Extended Client Protocol (ECP). When we did the Rippowam demo last year, we were successful in getting an Unscoped token by using ECP, but that was not sufficient to perform operations on other services that need a scoped token.

The general approach that we are looking at for Keystone is to always have the user ask for an unscoped token first, and then upgrade that to a scoped token. The scoping process can only be done from unscoped to scoped (configuration option) to prevent elevation of privilege attacks.

The base federation plugin is capable of handling this kind of workflow. Thus, the general approach is to write a protocol specific plugin to get an unscoped token, and then to use common logic in the base class v3.FederatedBaseAuth to convert unscoped to scoped.

I just got [edit: used to say keystone] opentstack flavor list to work with ECP and Keycloak. I had to create a new auth plugin to do it:

Created a new entry point in

/usr/lib/python2.7/site-packages/python_keystoneclient-1.7.2-py2.7.egg-info/entry_points.txt

v3fedsaml = keystoneclient.contrib.auth.v3.saml2:FederatedSAML2

Added this to
/usr/lib/python2.7/site-packages/keystoneclient/contrib/auth/v3/saml2.py

class FederatedSAML2(v3.FederatedBaseAuth):
    """Authenticate using SAML via the keystone federation mechanisms.

       Wraps both the unscoped SAML2 Plugin to
       1.  Request an unscoped token
       2.  Use the unscoped token to request a scoped token

    """

    @classmethod
    def get_options(cls):
        options = super(FederatedSAML2, cls).get_options()
        options.extend([
            cfg.StrOpt('identity-provider', help="Identity Provider's name"),
            cfg.StrOpt('protocol', help="SAML2"),
            cfg.StrOpt('identity-provider-url',
                       help="Identity Provider's URL"),
            cfg.StrOpt('user-name', dest='username', help='Username',
                       deprecated_name='username'),
            cfg.StrOpt('password', help='Password')
        ])
        return options

    def __init__(self, auth_url,
                 identity_provider,
                 protocol,
                 identity_provider_url,
                 username, password,
                 **kwargs):
        #protocol = kwargs.pop('protocol')
        super(FederatedSAML2, self).__init__(auth_url, identity_provider, protocol,
                                             **kwargs)
        self._unscoped = Saml2UnscopedToken(auth_url,
                                            identity_provider,
                                            identity_provider_url,
                                            username, password,
                                            **kwargs)


    def get_unscoped_auth_ref(self, session, **kwargs):
         return self._unscoped.get_auth_ref(session, **kwargs)

Updated my keystone RC file:

export OS_AUTH_TYPE=v3fedsaml

This is based on RH OSP8 which is Liberty release. In later releases of OSP, the client libraries are synchronized with later versions, including the gradual replacement of keystoneauth for the Auth plugins housed in python-keystone. Thus, there will be a couple variations on this plauoing, including one that may have to live out of tree if we want it for OSP8.

3 thoughts on “SAML Federated Auth Plugin

  1. So we should definitely have that pattern upstream – i think there was the intent to get it there around the time we did the keystoneauth split and then things got lost.

    From a usage/distribution perspective the cool thing about setuptools entrypoints is that they don’t have to live in the same package as the thing that is using them. So instead of hacking around in egg-info folders and packages in /usr/lib/ it’s probably better to show creating a new package like we did with python-keystoneclient-kerberos [1]

    [1] https://github.com/openstack/python-keystoneclient-kerberos

Leave a Reply

Your email address will not be published. Required fields are marked *