Added documentation for the external auth support
This covers given authentication using REMOTE_USER and also the way to implement custom auth with WSGI middleware. DocImpact blueprint: pluggable-identity-authentication-handlers Change-Id: Idbac8c38d1f0be1febbbc8056c929bada6bbb07e
This commit is contained in:
parent
75277cf1ae
commit
8c15e3eba6
117
doc/source/external-auth.rst
Normal file
117
doc/source/external-auth.rst
Normal file
@ -0,0 +1,117 @@
|
||||
===========================================
|
||||
Using external authentication with Keystone
|
||||
===========================================
|
||||
|
||||
When Keystone is executed in :doc:`HTTPD <apache-httpd>` it is possible to
|
||||
use external authentication methods different from the authentication
|
||||
provided by the identity store backend. For example, this makes possible to
|
||||
use a SQL identity backend together with X.509 authentication, Kerberos, etc.
|
||||
instead of using the username/password combination.
|
||||
|
||||
Using HTTPD authentication
|
||||
==========================
|
||||
|
||||
Webservers like Apache HTTP support many methods of authentication. Keystone can
|
||||
profit from this feature and let the authentication be done in the webserver,
|
||||
that will pass down the authenticated user to Keystone using the ``REMOTE_USER``
|
||||
environment variable. This user must exist in advance in the identity backend
|
||||
so as to get a token from the controller.
|
||||
|
||||
To use this method, Keystone should be running on :doc:`HTTPD <apache-httpd>`.
|
||||
|
||||
X.509 example
|
||||
-------------
|
||||
|
||||
The following snippet for the Apache conf will authenticate the user based on
|
||||
a valid X.509 certificate from a known CA::
|
||||
|
||||
<VirtualHost _default_:5000>
|
||||
SSLEngine on
|
||||
SSLCertificateFile /etc/ssl/certs/ssl.cert
|
||||
SSLCertificateKeyFile /etc/ssl/private/ssl.key
|
||||
|
||||
SSLCACertificatePath /etc/ssl/allowed_cas
|
||||
SSLCARevocationPath /etc/ssl/allowed_cas
|
||||
SSLUserName SSL_CLIENT_S_DN_CN
|
||||
SSLVerifyClient require
|
||||
SSLVerifyDepth 10
|
||||
|
||||
(...)
|
||||
</VirtualHost>
|
||||
|
||||
Developing a WSGI middleware for authentication
|
||||
===============================================
|
||||
|
||||
In addition to the method described above, it is possible to implement other
|
||||
custom authentication mechanisms using the ``REMOTE_USER`` WSGI environment
|
||||
variable.
|
||||
|
||||
.. ATTENTION::
|
||||
Please note that even if it is possible to develop a custom authentication
|
||||
module, it is preferable to use the modules in the HTTPD server. Such
|
||||
authentication modules in webservers like Apache have normally undergone
|
||||
years of development and use in production systems and are actively maintained
|
||||
upstream. Developing a custom authentication module that implements the same
|
||||
authentication as an existing Apache module likely introduces a higher
|
||||
security risk.
|
||||
|
||||
If you find you must implement a custom authentication mechanism, you will need
|
||||
to develop a custom WSGI middleware pipeline component. This middleware should
|
||||
set the environment variable ``REMOTE_USER`` to the authenticated username.
|
||||
Keystone then will assume that the user has been already authenticated upstream
|
||||
and will not try to authenticate it. However, as with HTTPD authentication, the
|
||||
user must exist in advance in the identity backend so that a proper token can
|
||||
be issued.
|
||||
|
||||
Your code should set the ``REMOTE_USER`` if the user is properly authenticated,
|
||||
following the semantics below::
|
||||
|
||||
class MyMiddlewareAuth(wsgi.Middleware):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MyMiddlewareAuth, self).__init__(*args, **kwargs)
|
||||
|
||||
def process_request(self, request):
|
||||
if request.environ.get('REMOTE_USER', None) is not None:
|
||||
# Assume that it is authenticated upstream
|
||||
return self.application
|
||||
|
||||
if not self.is_auth_applicable(request):
|
||||
# Not applicable
|
||||
return self.application
|
||||
|
||||
username = self.do_auth(request):
|
||||
if username is not None:
|
||||
# User is authenticated
|
||||
request.environ['REMOTE_USER'] = username
|
||||
else:
|
||||
# User is not authenticated
|
||||
raise exception.Unauthorized("Invalid user")
|
||||
|
||||
|
||||
Pipeline configuration
|
||||
----------------------
|
||||
|
||||
Once you have your WSGI middleware component developed you have to add it to
|
||||
your pipeline. The first step is to add the middleware to your configuration file.
|
||||
Assuming that your middleware module is ``keystone.middleware.MyMiddlewareAuth``,
|
||||
you can configure it in your ``keystone.conf`` as::
|
||||
|
||||
[filter:my_auth]
|
||||
paste.filter_factory = keystone.middleware.MyMiddlewareAuth.factory
|
||||
|
||||
The second step is to add your middleware to the pipeline. The exact place where
|
||||
you should place it will depend on your code (i.e. if you need for example that
|
||||
the request body is converted from JSON before perform the authentication you
|
||||
should place it after the ``json_body`` filter) but it should be set before the
|
||||
``public_service`` (for the ``public_api`` pipeline) or ``admin_service`` (for
|
||||
the ``admin_api`` pipeline), since they consume authentication.
|
||||
|
||||
For example, if the original pipeline looks like this::
|
||||
|
||||
[pipeline:public_api]
|
||||
pipeline = stats_monitoring url_normalize token_auth admin_token_auth xml_body json_body debug ec2_extension user_crud_extension public_service
|
||||
|
||||
Your modified pipeline might then look like this::
|
||||
|
||||
[pipeline:public_api]
|
||||
pipeline = stats_monitoring url_normalize token_auth admin_token_auth xml_body json_body my_auth debug ec2_extension user_crud_extension public_service
|
@ -66,6 +66,7 @@ Developers Documentation
|
||||
middlewarearchitecture
|
||||
api_curl_examples
|
||||
apache-httpd
|
||||
external-auth
|
||||
|
||||
Code Documentation
|
||||
==================
|
||||
|
Loading…
x
Reference in New Issue
Block a user