Files
deb-python-django-openstack…/openstack_auth/backend.py
Gabriel Hurley 998c96cfae Adds docs.
Fixes #2.
2012-07-08 15:39:38 -07:00

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