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.
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
Cool stuff, I want this!
> I just got *keystone flavor list* to work
You mean “openstack flavor list”?
Yes I mean openstack flavor list….will update. Thanks