121 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """ Module defining the Django auth backend class for the Keystone API. """
 | |
| 
 | |
| import logging
 | |
| 
 | |
| from django.utils.translation import ugettext as _
 | |
| 
 | |
| from keystoneclient.v2_0 import client as keystone_client
 | |
| from keystoneclient import exceptions as keystone_exceptions
 | |
| from keystoneclient.v2_0.tokens import Token, TokenManager
 | |
| 
 | |
| from .exceptions import KeystoneAuthException
 | |
| from .user import create_user_from_token
 | |
| from .utils import check_token_expiration
 | |
| 
 | |
| 
 | |
| LOG = logging.getLogger(__name__)
 | |
| 
 | |
| 
 | |
| KEYSTONE_CLIENT_ATTR = "_keystoneclient"
 | |
| 
 | |
| 
 | |
| class KeystoneBackend(object):
 | |
|     """
 | |
|     Django authentication backend class for use with ``django.contrib.auth``.
 | |
|     """
 | |
|     def check_auth_expiry(self, token):
 | |
|         if not check_token_expiration(token):
 | |
|             msg = _("The authentication token issued by the Identity service "
 | |
|                     "has expired.")
 | |
|             LOG.warning("The authentication token issued by the Identity "
 | |
|                         "service appears to have expired before it was "
 | |
|                         "issued. This may indicate a problem with either your "
 | |
|                         "server or client configuration.")
 | |
|             raise KeystoneAuthException(msg)
 | |
|         return True
 | |
| 
 | |
|     def get_user(self, user_id):
 | |
|         """
 | |
|         Returns the current user (if authenticated) based on the user ID
 | |
|         and session data.
 | |
| 
 | |
|         Note: this required monkey-patching the ``contrib.auth`` middleware
 | |
|         to make the ``request`` object available to the auth backend class.
 | |
|         """
 | |
|         if user_id == self.request.session["user_id"]:
 | |
|             token = Token(TokenManager(None),
 | |
|                           self.request.session['token'],
 | |
|                           loaded=True)
 | |
|             endpoint = self.request.session['region_endpoint']
 | |
|             return create_user_from_token(self.request, token, endpoint)
 | |
|         else:
 | |
|             return None
 | |
| 
 | |
|     def authenticate(self, request=None, username=None, password=None,
 | |
|                      tenant=None, auth_url=None):
 | |
|         """ Authenticates a user via the Keystone Identity API. """
 | |
|         LOG.debug('Beginning user authentication for user "%s".' % username)
 | |
| 
 | |
|         try:
 | |
|             client = keystone_client.Client(username=username,
 | |
|                                             password=password,
 | |
|                                             tenant_id=tenant,
 | |
|                                             auth_url=auth_url)
 | |
|             unscoped_token_data = {"token": client.service_catalog.get_token()}
 | |
|             unscoped_token = Token(TokenManager(None),
 | |
|                                    unscoped_token_data,
 | |
|                                    loaded=True)
 | |
|         except keystone_exceptions.Unauthorized:
 | |
|             msg = _('Invalid user name or password.')
 | |
|             raise KeystoneAuthException(msg)
 | |
|         except keystone_exceptions.ClientException:
 | |
|             msg = _("An error occurred authenticating. "
 | |
|                     "Please try again later.")
 | |
|             raise KeystoneAuthException(msg)
 | |
| 
 | |
|         # Check expiry for our unscoped token.
 | |
|         self.check_auth_expiry(unscoped_token)
 | |
| 
 | |
|         # FIXME: Log in to default tenant when the Keystone API returns it...
 | |
|         # For now we list all the user's tenants and iterate through.
 | |
|         try:
 | |
|             tenants = client.tenants.list()
 | |
|         except keystone_exceptions.ClientException:
 | |
|             msg = _('Unable to retrieve authorized projects.')
 | |
|             raise KeystoneAuthException(msg)
 | |
| 
 | |
|         # Abort if there are no tenants for this user
 | |
|         if not tenants:
 | |
|             msg = _('You are not authorized for any projects.')
 | |
|             raise KeystoneAuthException(msg)
 | |
| 
 | |
|         while tenants:
 | |
|             tenant = tenants.pop()
 | |
|             try:
 | |
|                 token = client.tokens.authenticate(username=username,
 | |
|                                                    token=unscoped_token.id,
 | |
|                                                    tenant_id=tenant.id)
 | |
|                 break
 | |
|             except keystone_exceptions.ClientException:
 | |
|                 token = None
 | |
| 
 | |
|         if token is None:
 | |
|             msg = _("Unable to authenticate to any available projects.")
 | |
|             raise KeystoneAuthException(msg)
 | |
| 
 | |
|         # Check expiry for our new scoped token.
 | |
|         self.check_auth_expiry(token)
 | |
| 
 | |
|         # If we made it here we succeeded. Create our User!
 | |
|         user = create_user_from_token(request, token, client.management_url)
 | |
| 
 | |
|         if request is not None:
 | |
|             request.session['unscoped_token'] = unscoped_token.id
 | |
|             request.user = user
 | |
| 
 | |
|             # Support client caching to save on auth calls.
 | |
|             setattr(request, KEYSTONE_CLIENT_ATTR, client)
 | |
| 
 | |
|         LOG.debug('Authentication completed for user "%s".' % username)
 | |
|         return user
 | 
