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 clean(self): region_id = self.cleaned_data.get('region') try: region = get_region_endpoint(region_id) except (ValueError, IndexError, TypeError): raise forms.ValidationError("Invalid region %r" % region_id) self.cleaned_data['region'] = region password = self.cleaned_data.get('password') original_password = self.cleaned_data.get('original_password') confirm_password = self.cleaned_data.get('confirm_password') if password != confirm_password: raise forms.ValidationError(_('Passwords do not match.')) if password == original_password: raise forms.ValidationError( _('Old password and new password must be different.')) # Doing it here, to be able to raise ValidationError on failure. user_id = self.initial['user_id'] session = utils.get_session(auth=DummyAuth(user_id)) Client = utils.get_keystone_client().Client client = Client(session=session, user_id=user_id, auth_url=region, endpoint=region) # This is needed so that keystoneclient doesn't try to authenticate. client.users.client.endpoint_override = region try: client.users.update_password(original_password, password) except Exception: raise forms.ValidationError( _("Unable to update the user password.")) return self.cleaned_data
def get_plugin(self, service_provider=None, auth_url=None, plugins=[], **kwargs): """Authenticate using keystone to keystone federation. This plugin uses other v3 plugins to authenticate a user to a identity provider in order to authenticate the user to a service provider :param service_provider: service provider ID :param auth_url: Keystone auth url :param plugins: list of openstack_auth plugins to check :returns Keystone2Keystone keystone auth plugin """ # service_provider being None prevents infinite recursion if utils.get_keystone_version() < 3 or not service_provider: return None keystone_idp_id = getattr(settings, 'KEYSTONE_PROVIDER_IDP_ID', 'localkeystone') if service_provider == keystone_idp_id: return None for plugin in plugins: unscoped_idp_auth = plugin.get_plugin(plugins=plugins, auth_url=auth_url, **kwargs) if unscoped_idp_auth: break else: LOG.debug('Could not find base authentication backend for ' 'K2K plugin with the provided credentials.') return None idp_exception = None scoped_idp_auth = None unscoped_auth_ref = base.BasePlugin.get_access_info( self, unscoped_idp_auth) try: scoped_idp_auth, __ = self.get_project_scoped_auth( unscoped_idp_auth, unscoped_auth_ref) except exceptions.KeystoneAuthException as idp_excp: idp_exception = idp_excp if not scoped_idp_auth or idp_exception: msg = 'Identity provider authentication Failed.' raise exceptions.KeystoneAuthException(msg) session = utils.get_session() if scoped_idp_auth.get_sp_auth_url(session, service_provider) is None: msg = _('Could not find service provider ID on Keystone.') raise exceptions.KeystoneAuthException(msg) unscoped_auth = v3_auth.Keystone2Keystone( base_plugin=scoped_idp_auth, service_provider=service_provider) return unscoped_auth
def get_plugin(self, service_provider=None, auth_url=None, plugins=None, **kwargs): """Authenticate using keystone to keystone federation. This plugin uses other v3 plugins to authenticate a user to a identity provider in order to authenticate the user to a service provider :param service_provider: service provider ID :param auth_url: Keystone auth url :param plugins: list of openstack_auth plugins to check :returns Keystone2Keystone keystone auth plugin """ # Avoid mutable default arg for plugins plugins = plugins or [] # service_provider being None prevents infinite recursion if utils.get_keystone_version() < 3 or not service_provider: return None keystone_idp_id = getattr(settings, 'KEYSTONE_PROVIDER_IDP_ID', 'localkeystone') if service_provider == keystone_idp_id: return None for plugin in plugins: unscoped_idp_auth = plugin.get_plugin(plugins=plugins, auth_url=auth_url, **kwargs) if unscoped_idp_auth: break else: LOG.debug('Could not find base authentication backend for ' 'K2K plugin with the provided credentials.') return None idp_exception = None scoped_idp_auth = None unscoped_auth_ref = base.BasePlugin.get_access_info( self, unscoped_idp_auth) try: scoped_idp_auth, __ = self.get_project_scoped_auth( unscoped_idp_auth, unscoped_auth_ref) except exceptions.KeystoneAuthException as idp_excp: idp_exception = idp_excp if not scoped_idp_auth or idp_exception: msg = 'Identity provider authentication Failed.' raise exceptions.KeystoneAuthException(msg) session = utils.get_session() if scoped_idp_auth.get_sp_auth_url(session, service_provider) is None: msg = _('Could not find service provider ID on Keystone.') raise exceptions.KeystoneAuthException(msg) unscoped_auth = v3_auth.Keystone2Keystone( base_plugin=scoped_idp_auth, service_provider=service_provider) return unscoped_auth
def designateclient(request): session = utils.get_session() session.auth = token_endpoint.Token( base.url_for(request, 'dns') + "/v2", request.user.token.id) c = designate_client.Client(session=session) return c
def login(request, **kwargs): ''' Logs a user in using the :class:`~openstack_auth.forms.Login` form. Referenced from openstack_auth.views.login ''' if not request.is_ajax(): # If the user is already authenticated, redirect them to the # dashboard straight away, unless the 'next' parameter is set as it # usually indicates requesting access to a page that requires different # permissions. if request.user.is_authenticated(): return HttpResponseRedirect('/') # Get our initial region for the form. form = functional.curry(openstack_auth_form) template_name = 'auth/login.html' res = django_auth_views.login(request, template_name=template_name, authentication_form=form, **kwargs) # Save the region in the cookie, this is used as the default # selected region next time the Login form loads. if request.method == "POST": openstack_auth_utils.set_response_cookie( res, 'login_region', request.POST.get('region', '')) openstack_auth_utils.set_response_cookie( res, 'login_domain', request.POST.get('domain', '')) # Set the session data here because django's session key rotation # will erase it if we set it earlier. print request.user.is_authenticated() if request.user.is_authenticated(): openstack_auth_user.set_session_from_user(request, request.user) session = openstack_auth_utils.get_session() user_endpoint = settings.OPENSTACK_KEYSTONE_URL auth = openstack_auth_utils.get_token_auth_plugin( auth_url=user_endpoint, token=request.user.unscoped_token, project_id=settings.ADMIN_TENANT_ID) try: auth_ref = auth.get_access(session) except keystone_client_exceptions.ClientException as e: auth_ref = None if auth_ref: new_user = openstack_auth_user.create_user_from_token( request, openstack_auth_user.Token(auth_ref), endpoint=request.user.endpoint) openstack_auth_user.set_session_from_user(request, new_user) return res
def login(request, **kwargs): ''' Logs a user in using the :class:`~openstack_auth.forms.Login` form. Referenced from openstack_auth.views.login ''' if not request.is_ajax(): # If the user is already authenticated, redirect them to the # dashboard straight away, unless the 'next' parameter is set as it # usually indicates requesting access to a page that requires different # permissions. if request.user.is_authenticated(): return HttpResponseRedirect('/') # Get our initial region for the form. form = functional.curry(openstack_auth_form) template_name = 'auth/login.html' res = django_auth_views.login(request, template_name=template_name, authentication_form=form, **kwargs) # Save the region in the cookie, this is used as the default # selected region next time the Login form loads. if request.method == "POST": openstack_auth_utils.set_response_cookie(res, 'login_region', request.POST.get('region', '')) openstack_auth_utils.set_response_cookie(res, 'login_domain', request.POST.get('domain', '')) # Set the session data here because django's session key rotation # will erase it if we set it earlier. print request.user.is_authenticated() if request.user.is_authenticated(): openstack_auth_user.set_session_from_user(request, request.user) session = openstack_auth_utils.get_session() user_endpoint = settings.OPENSTACK_KEYSTONE_URL auth = openstack_auth_utils.get_token_auth_plugin(auth_url=user_endpoint, token=request.user.unscoped_token, project_id=settings.ADMIN_TENANT_ID) try: auth_ref = auth.get_access(session) except keystone_client_exceptions.ClientException as e: auth_ref = None if auth_ref: new_user = openstack_auth_user.create_user_from_token(request, openstack_auth_user.Token(auth_ref), endpoint=request.user.endpoint) openstack_auth_user.set_session_from_user(request, new_user) return res
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 utils.get_keystone_version() < 3: return None, None if domain_name: domains = [domain_name] else: domains = self.list_domains(session, unscoped_auth, unscoped_auth_ref) domains = [domain.name for domain in domains if domain.enabled] # 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 for domain_name in domains: token = unscoped_auth_ref.auth_token domain_auth = utils.get_token_auth_plugin(auth_url, token, domain_name=domain_name) try: domain_auth_ref = domain_auth.get_access(session) except (keystone_exceptions.ClientException, keystone_exceptions.AuthorizationFailure): LOG.info( 'Attempted scope to domain %s failed, will attempt ' 'to scope to another domain.', domain_name) pass else: if len(domains) > 1: LOG.info( "More than one valid domain found for user %s," " scoping to %s", (unscoped_auth_ref.user_id, domain_name)) break return domain_auth, domain_auth_ref
def switch(request, tenant_id, redirect_field_name=auth.REDIRECT_FIELD_NAME): """Switches an authenticated user from one project to another.""" LOG.debug('Switching to tenant %s for user "%s".' % (tenant_id, request.user.username)) endpoint = utils.fix_auth_url_version(request.user.endpoint) session = utils.get_session() # Keystone can be configured to prevent exchanging a scoped token for # another token. Always use the unscoped token for requesting a # scoped token. unscoped_token = request.user.unscoped_token auth = utils.get_token_auth_plugin(auth_url=endpoint, token=unscoped_token, project_id=tenant_id) try: auth_ref = auth.get_access(session) msg = 'Project switch successful for user "%(username)s".' % \ {'username': request.user.username} LOG.info(msg) except keystone_exceptions.ClientException: msg = ( _('Project switch failed for user "%(username)s".') % {'username': request.user.username}) messages.error(request, msg) auth_ref = None LOG.exception('An error occurred while switching sessions.') # Ensure the user-originating redirection url is safe. # Taken from django.contrib.auth.views.login() redirect_to = request.REQUEST.get(redirect_field_name, '') if not is_safe_url(url=redirect_to, host=request.get_host()): redirect_to = settings.LOGIN_REDIRECT_URL if auth_ref: old_endpoint = request.session.get('region_endpoint') old_token = request.session.get('token') if old_token and old_endpoint and old_token.id != auth_ref.auth_token: delete_token(endpoint=old_endpoint, token_id=old_token.id) user = auth_user.create_user_from_token( request, auth_user.Token(auth_ref, unscoped_token=unscoped_token), endpoint) auth_user.set_session_from_user(request, user) message = ( _('Switch to project "%(project_name)s" successful.') % {'project_name': request.user.project_name}) messages.success(request, message) response = shortcuts.redirect(redirect_to) utils.set_response_cookie(response, 'recent_project', request.user.project_id) return response
def switch(request, project_id=None): if not project_id: data = json.loads(request.body) tenant_id = data['project_id'] else: tenant_id = project_id LOG.debug('Switching to tenant %s for user "%s".', tenant_id, request.user.username) endpoint, __ = utils.fix_auth_url_version_prefix(request.user.endpoint) session = utils.get_session() unscoped_token = request.user.unscoped_token auth = utils.get_token_auth_plugin(auth_url=endpoint, token=unscoped_token, project_id=tenant_id) try: auth_ref = auth.get_access(session) msg = 'Project switch successful for user "%(username)s".' % \ {'username': request.user.username} LOG.info(msg) except keystone_exceptions.ClientException: msg = (_('Project switch failed for user "%(username)s".') % { 'username': request.user.username }) messages.error(request, msg) auth_ref = None LOG.exception('An error occurred while switching sessions.') if auth_ref: user = auth_user.create_user_from_token( request, auth_user.Token(auth_ref, unscoped_token=unscoped_token), endpoint) auth_user.set_session_from_user(request, user) message = (_('Switch to project "%(project_name)s" successful.') % { 'project_name': request.user.project_name }) messages.success(request, message) # utils.set_response_cookie(response, 'recent_project', # request.user.project_id) print({ "tenant_id": request.user.tenant_id, "tenant_name": request.user.tenant_name, "username": request.user.username }) return JsonResponse("success", safe=False) else: return JsonResponse("failed", status=400, safe=False)
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 utils.get_keystone_version() < 3: return None, None if domain_name: domains = [domain_name] else: domains = self.list_domains(session, unscoped_auth, unscoped_auth_ref) domains = [domain.name for domain in domains if domain.enabled] # 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 for domain_name in domains: token = unscoped_auth_ref.auth_token domain_auth = utils.get_token_auth_plugin( auth_url, token, domain_name=domain_name) try: domain_auth_ref = domain_auth.get_access(session) except (keystone_exceptions.ClientException, keystone_exceptions.AuthorizationFailure): LOG.info('Attempted scope to domain %s failed, will attempt ' 'to scope to another domain.', domain_name) pass else: if len(domains) > 1: LOG.info("More than one valid domain found for user %s," " scoping to %s", (unscoped_auth_ref.user_id, domain_name)) break return domain_auth, domain_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): LOG.info( 'Attempted scope to project %s failed, will attempt ' 'to scope to another project.', project.name) pass else: break return scoped_auth, scoped_auth_ref
def get_new_user_token_from(request): """Generate new token for the given request to use in the context""" tenant_id = request.user.project_id endpoint = auth_utils.fix_auth_url_version(request.user.endpoint) session = auth_utils.get_session() # Keystone can be configured to prevent exchanging a scoped token for # another token. Always use the unscoped token for requesting a # scoped token. unscoped_token = request.user.unscoped_token auth = auth_utils.get_token_auth_plugin(auth_url=endpoint, token=unscoped_token, project_id=tenant_id) auth_ref = auth.get_access(session) return auth_ref.auth_token
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): LOG.info('Attempted scope to project %s failed, will attempt ' 'to scope to another project.', project.name) pass else: break return scoped_auth, scoped_auth_ref
def delete_token(endpoint, token_id): """Delete a token.""" try: endpoint = utils.fix_auth_url_version(endpoint) session = utils.get_session() auth_plugin = token_endpoint.Token(endpoint=endpoint, token=token_id) client = utils.get_keystone_client().Client(session=session, auth=auth_plugin) if utils.get_keystone_version() >= 3: client.tokens.revoke_token(token=token_id) else: client.tokens.delete(token=token_id) LOG.info('Deleted token %s' % token_id) except keystone_exceptions.ClientException: LOG.info('Could not delete token')
def switch_system_scope(request, redirect_field_name=auth.REDIRECT_FIELD_NAME): """Switches an authenticated user from one system to another.""" LOG.debug('Switching to system scope for user "%s".', request.user.username) endpoint, __ = utils.fix_auth_url_version_prefix(request.user.endpoint) session = utils.get_session() # Keystone can be configured to prevent exchanging a scoped token for # another token. Always use the unscoped token for requesting a # scoped token. unscoped_token = request.user.unscoped_token auth = utils.get_token_auth_plugin(auth_url=endpoint, token=unscoped_token, system_scope='all') try: auth_ref = auth.get_access(session) except keystone_exceptions.ClientException: msg = (_('System switch failed for user "%(username)s".') % { 'username': request.user.username }) messages.error(request, msg) auth_ref = None LOG.exception('An error occurred while switching sessions.') else: msg = 'System switch successful for user "%(username)s".' % \ {'username': request.user.username} LOG.info(msg) # Ensure the user-originating redirection url is safe. # Taken from django.contrib.auth.views.login() redirect_to = request.GET.get(redirect_field_name, '') if not http.is_safe_url(url=redirect_to, allowed_hosts=[request.get_host()]): redirect_to = settings.LOGIN_REDIRECT_URL if auth_ref: user = auth_user.create_user_from_token( request, auth_user.Token(auth_ref, unscoped_token=unscoped_token), endpoint) auth_user.set_session_from_user(request, user) message = _('Switch to system scope successful.') messages.success(request, message) response = shortcuts.redirect(redirect_to) return response
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.KeystoneConnectionException(msg) except (keystone_exceptions.Unauthorized, keystone_exceptions.Forbidden, keystone_exceptions.NotFound) as exc: msg = str(exc) LOG.debug(msg) match = re.match( r"The password is expired and needs to be changed" r" for user: ([^.]*)[.].*", msg) if match: exc = exceptions.KeystonePassExpiredException( _('Password expired.')) exc.user_id = match.group(1) raise exc msg = _('Invalid credentials.') raise exceptions.KeystoneCredentialsException(msg) 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_system_scoped_auth(self, unscoped_auth, unscoped_auth_ref, system_scope): """Get the system scoped keystone auth and access info This function returns a system scoped keystone token plugin and AccessInfo object. :param unscoped_auth: keystone auth plugin :param unscoped_auth_ref: keystoneclient.access.AccessInfo` or None. :param system_scope: system that we should try to scope to :return: keystone token auth plugin, AccessInfo object """ session = utils.get_session() auth_url = unscoped_auth.auth_url system_auth = None system_auth_ref = None token = unscoped_auth_ref.auth_token system_auth = utils.get_token_auth_plugin( auth_url, token, system_scope=system_scope) system_auth_ref = system_auth.get_access(session) return system_auth, system_auth_ref
def authenticate(self, request, 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.") plugin, unscoped_auth = self._get_auth_backend(auth_url, **kwargs) # the recent project id a user might have set in a cookie recent_project = None 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 or domains.') raise exceptions.KeystoneNoProjectsException(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 id_endpoints['identity']: if auth_url in id_endpoint.values(): region_name = id_endpoint['region'] break interface = settings.OPENSTACK_ENDPOINT_TYPE endpoint = scoped_auth_ref.service_catalog.url_for( service_type='identity', interface=interface, region_name=region_name) # 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 = settings.SESSION_TIMEOUT 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 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.") plugin, unscoped_auth = self._get_auth_backend(auth_url, **kwargs) # 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 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 = utils.fix_auth_url_version(auth_url) 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.warn('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) session = utils.get_session() keystone_client_class = utils.get_keystone_client().Client try: unscoped_auth_ref = unscoped_auth.get_access(session) except keystone_exceptions.ConnectionRefused 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) # Check expiry for our unscoped auth ref. self.check_auth_expiry(unscoped_auth_ref) 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] # Abort if there are no projects for this user if not projects: msg = _('You are not authorized for any projects.') 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: 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) interface = getattr(settings, 'OPENSTACK_ENDPOINT_TYPE', 'public') # 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), scoped_auth_ref.service_catalog.url_for(endpoint_type=interface)) if request is not None: request.session['unscoped_token'] = unscoped_token request.user = user timeout = getattr(settings, "SESSION_TIMEOUT", 3600) token_life = user.token.expires - datetime.datetime.now(pytz.utc) session_time = min(timeout, token_life.seconds) request.session.set_expiry(session_time) 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 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 = utils.fix_auth_url_version(auth_url) 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.warn('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) 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) # 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] # 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 projects 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) interface = getattr(settings, 'OPENSTACK_ENDPOINT_TYPE', 'public') # 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), scoped_auth_ref.service_catalog.url_for(service_type='identity', interface=interface)) if request is not None: 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 # Custom hack for WMF: if 'extended_session' in kwargs and kwargs['extended_session']: timeout = getattr(settings, "SESSION_TIMEOUT", 86400) else: timeout = getattr(settings, "SESSION_SHORT_TIMEOUT", 1800) token_life = user.token.expires - datetime.datetime.now(pytz.utc) # Fix for https://bugs.launchpad.net/django-openstack-auth/+bug/1562452: session_time = min(timeout, int(token_life.total_seconds())) request.session.set_expiry(session_time) 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 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 = utils.fix_auth_url_version(auth_url) 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) 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) # 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] # 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 projects 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) # 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 = utils.fix_auth_url_version( scoped_auth_ref.service_catalog.url_for( service_type='identity', interface=interface, region_name=region_name)) # 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: 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) 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 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 = utils.fix_auth_url_version(auth_url) 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.warn('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) session = utils.get_session() keystone_client_class = utils.get_keystone_client().Client try: unscoped_auth_ref = unscoped_auth.get_access(session) except keystone_exceptions.ConnectionRefused 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) # Check expiry for our unscoped auth ref. self.check_auth_expiry(unscoped_auth_ref) 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] # Abort if there are no projects for this user if not projects: msg = _('You are not authorized for any projects.') 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: # Check if token is automatically scoped to default_project # grab the project from this token, to use as a default # if no recent_project is found in the cookie recent_project = request.COOKIES.get('recent_project', unscoped_auth_ref.project_id) # 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: 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) interface = getattr(settings, 'OPENSTACK_ENDPOINT_TYPE', 'public') # 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), scoped_auth_ref.service_catalog.url_for(endpoint_type=interface)) if request is not None: request.session['unscoped_token'] = unscoped_token request.user = user timeout = getattr(settings, "SESSION_TIMEOUT", 3600) token_life = user.token.expires - datetime.datetime.now(pytz.utc) session_time = min(timeout, token_life.seconds) request.session.set_expiry(session_time) 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