summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElvin Tubillara <edtubill@us.ibm.com>2016-12-27 15:39:25 -0600
committerElvin Tubillara <edtubill@us.ibm.com>2017-01-12 14:01:47 -0600
commit597e6d79b40d7e063446f8fe9b265390d76b69ce (patch)
treea83ab0f2a5f633c98d185fcd89b189fd098dab34
parent2475fd33d97ebd5ea45cada9adb0296b1d31c3d6 (diff)
downloaddjango_openstack_auth-597e6d79b40d7e063446f8fe9b265390d76b69ce.tar.gz
Refactor project and domain scoping
Moves the project and domain logic into their own functions inside the plugin object. Change-Id: I3aa026364443220c9b3fa38ec306fed4d9e878cc
-rw-r--r--openstack_auth/backend.py106
-rw-r--r--openstack_auth/plugin/base.py113
-rw-r--r--openstack_auth/tests/tests.py2
3 files changed, 136 insertions, 85 deletions
diff --git a/openstack_auth/backend.py b/openstack_auth/backend.py
index 9509f45..9ada58d 100644
--- a/openstack_auth/backend.py
+++ b/openstack_auth/backend.py
@@ -20,7 +20,6 @@ import pytz
from django.conf import settings
from django.utils.module_loading import import_string # noqa
from django.utils.translation import ugettext_lazy as _
-from keystoneauth1 import exceptions as keystone_exceptions
from openstack_auth import exceptions
from openstack_auth import user as auth_user
@@ -110,51 +109,23 @@ class KeystoneBackend(object):
'configuration error that should be addressed.')
raise exceptions.KeystoneAuthException(msg)
- session = utils.get_session()
- keystone_client_class = utils.get_keystone_client().Client
-
- try:
- unscoped_auth_ref = unscoped_auth.get_access(session)
- except keystone_exceptions.ConnectFailure as exc:
- LOG.error(str(exc))
- msg = _('Unable to establish connection to keystone endpoint.')
- raise exceptions.KeystoneAuthException(msg)
- except (keystone_exceptions.Unauthorized,
- keystone_exceptions.Forbidden,
- keystone_exceptions.NotFound) as exc:
- LOG.debug(str(exc))
- raise exceptions.KeystoneAuthException(_('Invalid credentials.'))
- except (keystone_exceptions.ClientException,
- keystone_exceptions.AuthorizationFailure) as exc:
- msg = _("An error occurred authenticating. "
- "Please try again later.")
- LOG.debug(str(exc))
- raise exceptions.KeystoneAuthException(msg)
+ # the recent project id a user might have set in a cookie
+ recent_project = None
+ request = kwargs.get('request')
+ if request:
+ # Grab recent_project found in the cookie, try to scope
+ # to the last project used.
+ recent_project = request.COOKIES.get('recent_project')
+ unscoped_auth_ref = plugin.get_access_info(unscoped_auth)
# Check expiry for our unscoped auth ref.
self.check_auth_expiry(unscoped_auth_ref)
- # domain support can require domain scoped tokens to perform
- # identity operations depending on the policy files being used
- # for keystone.
- domain_auth = None
- domain_auth_ref = None
- if utils.get_keystone_version() >= 3 and 'user_domain_name' in kwargs:
- try:
- token = unscoped_auth_ref.auth_token
- domain_auth = utils.get_token_auth_plugin(
- auth_url,
- token,
- domain_name=kwargs['user_domain_name'])
- domain_auth_ref = domain_auth.get_access(session)
- except Exception:
- LOG.debug('Error getting domain scoped token.', exc_info=True)
-
- projects = plugin.list_projects(session,
- unscoped_auth,
- unscoped_auth_ref)
- # Attempt to scope only to enabled projects
- projects = [project for project in projects if project.enabled]
+ domain_name = kwargs.get('user_domain_name', None)
+ domain_auth, domain_auth_ref = plugin.get_domain_scoped_auth(
+ unscoped_auth, unscoped_auth_ref, domain_name)
+ scoped_auth, scoped_auth_ref = plugin.get_project_scoped_auth(
+ unscoped_auth, unscoped_auth_ref, recent_project=recent_project)
# Abort if there are no projects for this user and a valid domain
# token has not been obtained
@@ -171,54 +142,17 @@ class KeystoneBackend(object):
# token)
# 3) user cannot obtain a domain scoped token, but can
# obtain a project scoped token
- if not projects and not domain_auth_ref:
+ if not scoped_auth_ref and domain_auth_ref:
+ # if the user can't obtain a project scoped token, set the scoped
+ # token to be the domain token, if valid
+ scoped_auth = domain_auth
+ scoped_auth_ref = domain_auth_ref
+ elif not scoped_auth_ref and not domain_auth_ref:
msg = _('You are not authorized for any projects.')
if utils.get_keystone_version() >= 3:
msg = _('You are not authorized for any projects or domains.')
raise exceptions.KeystoneAuthException(msg)
- # the recent project id a user might have set in a cookie
- recent_project = None
- request = kwargs.get('request')
-
- if request:
- # Grab recent_project found in the cookie, try to scope
- # to the last project used.
- recent_project = request.COOKIES.get('recent_project')
-
- # if a most recent project was found, try using it first
- if recent_project:
- for pos, project in enumerate(projects):
- if project.id == recent_project:
- # move recent project to the beginning
- projects.pop(pos)
- projects.insert(0, project)
- break
-
- for project in projects:
- token = unscoped_auth_ref.auth_token
- scoped_auth = utils.get_token_auth_plugin(auth_url,
- token=token,
- project_id=project.id)
-
- try:
- scoped_auth_ref = scoped_auth.get_access(session)
- except (keystone_exceptions.ClientException,
- keystone_exceptions.AuthorizationFailure):
- pass
- else:
- break
- else:
- # if the user can't obtain a project scoped token, set the scoped
- # token to be the domain token, if valid
- if domain_auth_ref:
- scoped_auth = domain_auth
- scoped_auth_ref = domain_auth_ref
- else:
- # if no domain or project token for user, abort
- msg = _("Unable to authenticate to any available projects.")
- raise exceptions.KeystoneAuthException(msg)
-
# Check expiry for our new scoped token.
self.check_auth_expiry(scoped_auth_ref)
@@ -276,6 +210,8 @@ class KeystoneBackend(object):
session_time = min(timeout, int(token_life.total_seconds()))
request.session.set_expiry(session_time)
+ keystone_client_class = utils.get_keystone_client().Client
+ session = utils.get_session()
scoped_client = keystone_client_class(session=session,
auth=scoped_auth)
diff --git a/openstack_auth/plugin/base.py b/openstack_auth/plugin/base.py
index da87365..7170421 100644
--- a/openstack_auth/plugin/base.py
+++ b/openstack_auth/plugin/base.py
@@ -11,6 +11,7 @@
# under the License.
import abc
+import logging
from django.utils.translation import ugettext_lazy as _
from keystoneauth1 import exceptions as keystone_exceptions
@@ -21,6 +22,7 @@ import six
from openstack_auth import exceptions
from openstack_auth import utils
+LOG = logging.getLogger(__name__)
__all__ = ['BasePlugin']
@@ -95,3 +97,114 @@ class BasePlugin(object):
keystone_exceptions.AuthorizationFailure):
msg = _('Unable to retrieve authorized projects.')
raise exceptions.KeystoneAuthException(msg)
+
+ def get_access_info(self, keystone_auth):
+ """Get the access info from an unscoped auth
+
+ This function provides the base functionality that the
+ plugins will use to authenticate and get the access info object.
+
+ :param keystone_auth: keystoneauth1 identity plugin
+ :raises: exceptions.KeystoneAuthException on auth failure
+ :returns: keystoneclient.access.AccessInfo
+ """
+ session = utils.get_session()
+
+ try:
+ unscoped_auth_ref = keystone_auth.get_access(session)
+ except keystone_exceptions.ConnectFailure as exc:
+ LOG.error(str(exc))
+ msg = _('Unable to establish connection to keystone endpoint.')
+ raise exceptions.KeystoneAuthException(msg)
+ except (keystone_exceptions.Unauthorized,
+ keystone_exceptions.Forbidden,
+ keystone_exceptions.NotFound) as exc:
+ LOG.debug(str(exc))
+ raise exceptions.KeystoneAuthException(_('Invalid credentials.'))
+ except (keystone_exceptions.ClientException,
+ keystone_exceptions.AuthorizationFailure) as exc:
+ msg = _("An error occurred authenticating. "
+ "Please try again later.")
+ LOG.debug(str(exc))
+ raise exceptions.KeystoneAuthException(msg)
+ return unscoped_auth_ref
+
+ def get_project_scoped_auth(self, unscoped_auth, unscoped_auth_ref,
+ recent_project=None):
+ """Get the project scoped keystone auth and access info
+
+ This function returns a project scoped keystone token plugin
+ and AccessInfo object.
+
+ :param unscoped_auth: keystone auth plugin
+ :param unscoped_auth_ref: keystoneclient.access.AccessInfo` or None.
+ :param recent_project: project that we should try to scope to
+ :return: keystone token auth plugin, AccessInfo object
+ """
+ auth_url = unscoped_auth.auth_url
+ session = utils.get_session()
+
+ projects = self.list_projects(
+ session, unscoped_auth, unscoped_auth_ref)
+ # Attempt to scope only to enabled projects
+ projects = [project for project in projects if project.enabled]
+
+ # if a most recent project was found, try using it first
+ if recent_project:
+ for pos, project in enumerate(projects):
+ if project.id == recent_project:
+ # move recent project to the beginning
+ projects.pop(pos)
+ projects.insert(0, project)
+ break
+
+ scoped_auth = None
+ scoped_auth_ref = None
+ for project in projects:
+ token = unscoped_auth_ref.auth_token
+ scoped_auth = utils.get_token_auth_plugin(auth_url,
+ token=token,
+ project_id=project.id)
+ try:
+ scoped_auth_ref = scoped_auth.get_access(session)
+ except (keystone_exceptions.ClientException,
+ keystone_exceptions.AuthorizationFailure):
+ pass
+ else:
+ break
+
+ return scoped_auth, scoped_auth_ref
+
+ def get_domain_scoped_auth(self, unscoped_auth, unscoped_auth_ref,
+ domain_name=None):
+ """Get the domain scoped keystone auth and access info
+
+ This function returns a domain scoped keystone token plugin
+ and AccessInfo object.
+
+ :param unscoped_auth: keystone auth plugin
+ :param unscoped_auth_ref: keystoneclient.access.AccessInfo` or None.
+ :param domain_name: domain that we should try to scope to
+ :return: keystone token auth plugin, AccessInfo object
+ """
+ session = utils.get_session()
+ auth_url = unscoped_auth.auth_url
+
+ if not domain_name or utils.get_keystone_version() < 3:
+ return None, None
+
+ # domain support can require domain scoped tokens to perform
+ # identity operations depending on the policy files being used
+ # for keystone.
+ domain_auth = None
+ domain_auth_ref = None
+ try:
+ token = unscoped_auth_ref.auth_token
+ domain_auth = utils.get_token_auth_plugin(
+ auth_url,
+ token,
+ domain_name=domain_name)
+ domain_auth_ref = domain_auth.get_access(session)
+ except Exception:
+ LOG.debug('Error getting domain scoped token.', exc_info=True)
+ return domain_auth, domain_auth_ref
diff --git a/openstack_auth/tests/tests.py b/openstack_auth/tests/tests.py
index f2dbe55..c58aacc 100644
--- a/openstack_auth/tests/tests.py
+++ b/openstack_auth/tests/tests.py
@@ -55,6 +55,7 @@ class OpenStackAuthTestsMixin(object):
plugin = self._create_password_auth()
plugin.get_access(mox.IsA(session.Session)). \
AndReturn(self.data.unscoped_access_info)
+ plugin.auth_url = settings.OPENSTACK_KEYSTONE_URL
return self.ks_client_module.Client(session=mox.IsA(session.Session),
auth=plugin)
@@ -810,6 +811,7 @@ class OpenStackAuthTestsWebSSO(OpenStackAuthTestsMixin, test.TestCase):
token=unscoped.auth_token,
url=settings.OPENSTACK_KEYSTONE_URL)
plugin.get_access(mox.IsA(session.Session)).AndReturn(unscoped)
+ plugin.auth_url = settings.OPENSTACK_KEYSTONE_URL
return self.ks_client_module.Client(session=mox.IsA(session.Session),
auth=plugin)