Exemple #1
0
def download_rc_file(request):
    template = 'project/access_and_security/api_access/openrc.sh.template'
    context = _get_openrc_credentials(request)

    # make v3 specific changes
    context['user_domain_name'] = request.user.user_domain_name
    # sanity fix for removing v2.0 from the url if present
    context['auth_url'] = utils.fix_auth_url_version(context['auth_url'])
    return _download_rc_file_for_template(request, context, template)
Exemple #2
0
def download_rc_file(request):
    template = 'project/access_and_security/api_access/openrc.sh.template'
    context = _get_openrc_credentials(request)

    # make v3 specific changes
    context['user_domain_name'] = request.user.user_domain_name
    # sanity fix for removing v2.0 from the url if present
    context['auth_url'] = utils.fix_auth_url_version(context['auth_url'])
    return _download_rc_file_for_template(request, context, template)
 def test_fix_auth_url_version_v20(self):
     settings.OPENSTACK_API_VERSIONS['identity'] = 2.0
     test_urls = [
         ("http://a/", "http://a/v2.0"),
         ("http://a", "http://a/v2.0"),
         ("http://a:8080/", "http://a:8080/v2.0"),
         ("http://a/v2.0", "http://a/v2.0"),
         ("http://a/v2.0/", "http://a/v2.0/"),
     ]
     for src, expected in test_urls:
         self.assertEqual(expected, utils.fix_auth_url_version(src))
Exemple #4
0
 def test_fix_auth_url_version_v20(self):
     settings.OPENSTACK_API_VERSIONS['identity'] = 2.0
     test_urls = [
         ("http://a/", "http://a/v2.0"),
         ("http://a", "http://a/v2.0"),
         ("http://a:8080/", "http://a:8080/v2.0"),
         ("http://a/v2.0", "http://a/v2.0"),
         ("http://a/v2.0/", "http://a/v2.0/"),
     ]
     for src, expected in test_urls:
         self.assertEqual(expected, utils.fix_auth_url_version(src))
Exemple #5
0
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
Exemple #6
0
def _get_endpoint_url(request, endpoint_type, catalog=None):
    if getattr(request.user, "service_catalog", None):
        url = base.url_for(request,
                           service_type='identity',
                           endpoint_type=endpoint_type)
    else:
        auth_url = getattr(settings, 'OPENSTACK_KEYSTONE_URL')
        url = request.session.get('region_endpoint', auth_url)

    # TODO(gabriel): When the Service Catalog no longer contains API versions
    # in the endpoints this can be removed.
    url = auth_utils.fix_auth_url_version(url)

    return url
Exemple #7
0
def _get_endpoint_url(request, endpoint_type, catalog=None):
    if getattr(request.user, "service_catalog", None):
        url = base.url_for(request,
                           service_type='identity',
                           endpoint_type=endpoint_type)
    else:
        auth_url = getattr(settings, 'OPENSTACK_KEYSTONE_URL')
        url = request.session.get('region_endpoint', auth_url)

    # TODO(gabriel): When the Service Catalog no longer contains API versions
    # in the endpoints this can be removed.
    url = auth_utils.fix_auth_url_version(url)

    return url
Exemple #8
0
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
Exemple #9
0
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 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')
Exemple #11
0
    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.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
Exemple #14
0
    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