diff options
Diffstat (limited to 'openstack_auth/backend.py')
-rw-r--r-- | openstack_auth/backend.py | 282 |
1 files changed, 0 insertions, 282 deletions
diff --git a/openstack_auth/backend.py b/openstack_auth/backend.py deleted file mode 100644 index dae603a..0000000 --- a/openstack_auth/backend.py +++ /dev/null @@ -1,282 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" Module defining the Django auth backend class for the Keystone API. """ - -import datetime -import logging -import pytz - -from django.conf import settings -from django.utils.module_loading import import_string -from django.utils.translation import ugettext_lazy as _ - -from openstack_auth import exceptions -from openstack_auth import user as auth_user -from openstack_auth import utils - - -LOG = logging.getLogger(__name__) - - -KEYSTONE_CLIENT_ATTR = "_keystoneclient" - - -class KeystoneBackend(object): - """Django authentication backend for use with ``django.contrib.auth``.""" - - def __init__(self): - self._auth_plugins = None - - @property - def auth_plugins(self): - if self._auth_plugins is None: - plugins = getattr( - settings, - 'AUTHENTICATION_PLUGINS', - ['openstack_auth.plugin.password.PasswordPlugin', - 'openstack_auth.plugin.token.TokenPlugin']) - - self._auth_plugins = [import_string(p)() for p in plugins] - - return self._auth_plugins - - def check_auth_expiry(self, auth_ref, margin=None): - if not utils.is_token_valid(auth_ref, margin): - 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 exceptions.KeystoneAuthException(msg) - return True - - def get_user(self, user_id): - """Returns the current user from the session data. - - If authenticated, this return the user object 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 (hasattr(self, 'request') and - user_id == self.request.session["user_id"]): - token = self.request.session['token'] - endpoint = self.request.session['region_endpoint'] - services_region = self.request.session['services_region'] - user = auth_user.create_user_from_token(self.request, token, - endpoint, services_region) - return user - else: - return None - - def authenticate(self, auth_url=None, **kwargs): - """Authenticates a user via the Keystone Identity API.""" - LOG.debug('Beginning user authentication') - - if not auth_url: - auth_url = settings.OPENSTACK_KEYSTONE_URL - - auth_url, url_fixed = utils.fix_auth_url_version_prefix(auth_url) - if url_fixed: - LOG.warning("The OPENSTACK_KEYSTONE_URL setting points to a v2.0 " - "Keystone endpoint, but v3 is specified as the API " - "version to use by Horizon. Using v3 endpoint for " - "authentication.") - - for plugin in self.auth_plugins: - unscoped_auth = plugin.get_plugin(auth_url=auth_url, **kwargs) - - if unscoped_auth: - break - else: - msg = _('No authentication backend could be determined to ' - 'handle the provided credentials.') - LOG.warning('No authentication backend could be determined to ' - 'handle the provided credentials. This is likely a ' - 'configuration error that should be addressed.') - 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_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 - # - # The valid use cases for a user login are: - # Keystone v2: user must have a role on a project and be able - # to obtain a project scoped token - # Keystone v3: 1) user can obtain a domain scoped token (user - # has a role on the domain they authenticated to), - # only, no roles on a project - # 2) user can obtain a domain scoped token and has - # a role on a project in the domain they - # authenticated to (and can obtain a project scoped - # token) - # 3) user cannot obtain a domain scoped token, but can - # obtain a project scoped token - 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) - - # Check expiry for our new scoped token. - self.check_auth_expiry(scoped_auth_ref) - - # We want to try to use the same region we just logged into - # which may or may not be the default depending upon the order - # keystone uses - region_name = None - id_endpoints = scoped_auth_ref.service_catalog.\ - get_endpoints(service_type='identity') - for id_endpoint in [cat for cat in id_endpoints['identity']]: - if auth_url in id_endpoint.values(): - region_name = id_endpoint['region'] - break - - interface = getattr(settings, 'OPENSTACK_ENDPOINT_TYPE', 'public') - - endpoint, url_fixed = utils.fix_auth_url_version_prefix( - scoped_auth_ref.service_catalog.url_for( - service_type='identity', - interface=interface, - region_name=region_name)) - if url_fixed: - LOG.warning("The Keystone URL in service catalog points to a v2.0 " - "Keystone endpoint, but v3 is specified as the API " - "version to use by Horizon. Using v3 endpoint for " - "authentication.") - - # If we made it here we succeeded. Create our User! - unscoped_token = unscoped_auth_ref.auth_token - - user = auth_user.create_user_from_token( - request, - auth_user.Token(scoped_auth_ref, unscoped_token=unscoped_token), - endpoint, - services_region=region_name) - - if request is not None: - # if no k2k providers exist then the function returns quickly - utils.store_initial_k2k_session(auth_url, request, scoped_auth_ref, - unscoped_auth_ref) - request.session['unscoped_token'] = unscoped_token - if domain_auth_ref: - # check django session engine, if using cookies, this will not - # work, as it will overflow the cookie so don't add domain - # scoped token to the session and put error in the log - if utils.using_cookie_backed_sessions(): - LOG.error('Using signed cookies as SESSION_ENGINE with ' - 'OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT is ' - 'enabled. This disables the ability to ' - 'perform identity operations due to cookie size ' - 'constraints.') - else: - request.session['domain_token'] = domain_auth_ref - - request.user = user - timeout = getattr(settings, "SESSION_TIMEOUT", 3600) - token_life = user.token.expires - datetime.datetime.now(pytz.utc) - 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) - - # Support client caching to save on auth calls. - setattr(request, KEYSTONE_CLIENT_ATTR, scoped_client) - - LOG.debug('Authentication completed.') - return user - - def get_group_permissions(self, user, obj=None): - """Returns an empty set since Keystone doesn't support "groups".""" - # Keystone V3 added "groups". The Auth token response includes the - # roles from the user's Group assignment. It should be fine just - # returning an empty set here. - return set() - - def get_all_permissions(self, user, obj=None): - """Returns a set of permission strings that the user has. - - This permission available to the user is derived from the user's - Keystone "roles". - - The permissions are returned as ``"openstack.{{ role.name }}"``. - """ - if user.is_anonymous() or obj is not None: - return set() - # TODO(gabrielhurley): Integrate policy-driven RBAC - # when supported by Keystone. - role_perms = {utils.get_role_permission(role['name']) - for role in user.roles} - - services = [] - for service in user.service_catalog: - try: - service_type = service['type'] - except KeyError: - continue - service_regions = [utils.get_endpoint_region(endpoint) for endpoint - in service.get('endpoints', [])] - if user.services_region in service_regions: - services.append(service_type.lower()) - service_perms = {"openstack.services.%s" % service - for service in services} - return role_perms | service_perms - - def has_perm(self, user, perm, obj=None): - """Returns True if the given user has the specified permission.""" - if not user.is_active: - return False - return perm in self.get_all_permissions(user, obj) - - def has_module_perms(self, user, app_label): - """Returns True if user has any permissions in the given app_label. - - Currently this matches for the app_label ``"openstack"``. - """ - if not user.is_active: - return False - for perm in self.get_all_permissions(user): - if perm[:perm.index('.')] == app_label: - return True - return False |