ClientAuthenticationPlugin

Keystone integration on the server side of our services is relatively straightforward: pull the auth_token middleware in, add an appropriate middleware, if necessary, for the actual integration, and the result is unified keystone authentication.

We have not really looked at keystone integration into our client tools, however. This is a harder problem because each tool uses its own framework, and none of the frameworks really have the concept of a middleware that would be useful in this context. Additionally, we have to deal with the problem both at the Python API level and at a CLI level.

One possible approach is to create a single, uniform plugin (an "AuthPlugin" class) that would integrate with keystone--and of course to use some authentication system other than keystone, all that needs to be done is switch out that one plugin. The plugin centralizes all the logic necessary to perform the authentication, and advertises:


 * 1) The information it needs to do its job (username, tenant, password, auth URL, whatever)
 * 2) The information it provides once the authentication has been performed (base URL for the service, authentication token, etc.)
 * 3) The translations it needs to perform on the outgoing requests to do its job

This third item is the most complex, of course, since potentially a plugin may need to inject headers ("X-Auth-Token"), rewrite the URL, rewrite the request body, catch a authentication-related status code, even potentially resubmit an operation after having retrieved updated authentication information.

The authentication plugin would work with an object provided by the client (an "AuthSvc" object) which would tell the plugin what it needs to know about the client, such as the service name to look up the base URL for, as well as providing an interface for submitting requests to arbitrary URLs (so we can avoid reinventing the wheel or pulling in external client frameworks). It would also have the interface necessary for resubmitting an operation that the plugin has hooked based on an authentication-related status code.

Graphically, this architecture looks like the following:



The anticipated logic flow is essentially this:


 * Client determines required authentication information by inspecting the AuthPlugin (probably calling a class method)
 * Client instantiates its AuthSvc class and passes the object to the AuthPlugin constructor
 * Client feeds the AuthPlugin the authentication information it requires by calling the plugin's auth method with appropriate arguments
 * AuthPlugin performs authentication with the authentication information and returns an object containing the target base URL and possibly a blob of information it will need to authenticate individual requests
 * AuthPlugin's query submission is made using services provided by the AuthSvc object Client created
 * AuthPlugin will determine information about the client using it from AuthSvc, such as the service the client is against (nova, glance, swift, etc.)
 * Client performs its queries against the target base URL and calls appropriate AuthPlugin methods to determine headers to inject, URL rewriting, and even body rewriting
 * Client receives response from remote end and again calls appropriate AuthPlugin methods to verify response.
 * Client must be prepared that AuthPlugin may indicate that the request needs to be reissued with new information, e.g., in the case of token expiry

Corresponding blueprint is: https://blueprints.launchpad.net/glance/+spec/pluggable-auth