예제 #1
0
    def authenticate(self, context, auth_info):

        if 'token' in auth_info:
            try:

                response_data = {}

                userdata = json.loads(self._parse_cryptoken(
                    auth_info['token']))
                if not 'username' in userdata or not 'domain' in userdata:
                    raise Unauthorized("Cannot retrieve user data")

                LOG.info("Accepted secret for user %s" % userdata['username'])

                uDict = self.identity_api.get_user_by_name(
                    userdata['username'], userdata['domain'])

                if not uDict['enabled']:
                    raise Unauthorized("User %s is disabled" % uDict['name'])

                response_data['user_id'] = uDict['id']
                return base.AuthHandlerResponse(status=True,
                                                response_body=None,
                                                response_data=response_data)

            except UserNotFound:
                raise NotFound("Missing user")
            except Unauthorized as noAuthEx:
                LOG.error(str(noAuthEx))
                raise
            except Exception:
                LOG.error("Cannot decrypt token", exc_info=True)

        raise Unauthorized('Cannot authenticate using sKey')
예제 #2
0
    def authenticate(self, auth_payload):
        """Use HTTP_X_USER_NAME to look up the user in the identity backend.
        """
        response_data = {}

        try:
            # trusted-key header configured?
            if CONF.cc_external.trusted_key_value:
                # check it
                secret = flask.request.environ[
                    CONF.cc_external.trusted_key_header]
                if secret != CONF.cc_external.trusted_key_value:
                    raise KeyError
        except KeyError:
            LOG.error(
                "Authentication failed. Invalid trusted secret from: %s" %
                flask.request.environ.get('REMOTE_ADDR'))
            msg = _('Authentication requested from a untrusted source')
            raise exception.Unauthorized(msg)

        try:
            remote_user = flask.request.environ[
                CONF.cc_external.user_name_header]
            user_ref = self._authenticate(remote_user)
        except Exception:
            msg = _('Unable to lookup user %s') % flask.request.environ.get(
                CONF.cc_external.user_name_header)
            raise exception.Unauthorized(msg)

        response_data['user_id'] = user_ref['id']
        return base.AuthHandlerResponse(status=True,
                                        response_body=None,
                                        response_data=response_data)
예제 #3
0
    def authenticate(self, request, auth_payload):
        """Authenticate mapped user and set an authentication context.

        :param request: keystone's request context
        :param auth_payload: the content of the authentication for a
                             given method

        In addition to ``user_id`` in ``response_data``, this plugin sets
        ``group_ids``, ``OS-FEDERATION:identity_provider`` and
        ``OS-FEDERATION:protocol``

        """
        if 'id' in auth_payload:
            token_ref = self._get_token_ref(auth_payload)
            response_data = handle_scoped_token(request, token_ref,
                                                self.federation_api,
                                                self.identity_api)
        else:
            response_data = handle_unscoped_token(
                request, auth_payload, self.resource_api, self.federation_api,
                self.identity_api, self.assignment_api, self.role_api)

        return base.AuthHandlerResponse(status=True,
                                        response_body=None,
                                        response_data=response_data)
예제 #4
0
    def authenticate(self, auth_payload, user_context=None):
        """Try to authenticate against the identity backend."""
        user_info = password.auth_plugins.UserAuthInfo.create(
            auth_payload, 'password')

        # FIXME(gyee): identity.authenticate() can use some refactoring since
        # all we care is password matches
        try:
            res = PROVIDERS.identity_api.authenticate(
                user_id=user_info.user_id, password=user_info.password)
        except AssertionError:
            # authentication failed because of invalid username or password
            msg = 'Invalid username or password'
            raise exception.Unauthorized(msg)

        if not user_context:
            user_context = {}

        if 'user_id' not in user_context:
            user_context['user_id'] = user_info.user_id
        if 'extras' in res:
            user_context['extras'] = res['extras']
        LOG.debug("authenticate %s" % user_context)
        if ('O' in RELEASES):  # true when current version is Newton or upper
            from keystone.auth.plugins import base
            return base.AuthHandlerResponse(status=True,
                                            response_body=None,
                                            response_data=user_context)
예제 #5
0
    def authenticate(
        self,
        request,
        auth_payload,
    ):
        """Use REMOTE_USER to look up the user in the identity backend.

        The user_id from the actual user from the REMOTE_USER env variable is
        placed in the response_data.
        """
        response_data = {}
        if not request.remote_user:
            msg = _('No authenticated user')
            raise exception.Unauthorized(msg)

        try:
            user_ref = self._authenticate(request)
        except Exception:
            msg = _('Unable to lookup user %s') % request.remote_user
            raise exception.Unauthorized(msg)

        response_data['user_id'] = user_ref['id']
        auth_type = (request.auth_type or '').lower()

        if 'kerberos' in CONF.token.bind and auth_type == 'negotiate':
            response_data.setdefault('bind', {})['kerberos'] = user_ref['name']

        return base.AuthHandlerResponse(status=True,
                                        response_body=None,
                                        response_data=response_data)
예제 #6
0
파일: totp.py 프로젝트: tiansen87/keystone
    def authenticate(self, request, auth_payload):
        """Try to authenticate using TOTP."""
        response_data = {}
        user_info = plugins.TOTPUserInfo.create(auth_payload, METHOD_NAME)
        auth_passcode = auth_payload.get('user').get('passcode')

        credentials = self.credential_api.list_credentials_for_user(
            user_info.user_id, type='totp')

        valid_passcode = False
        for credential in credentials:
            try:
                generated_passcode = _generate_totp_passcode(
                    credential['blob'])
                if auth_passcode == generated_passcode:
                    valid_passcode = True
                    break
            except (ValueError, KeyError):
                LOG.debug('No TOTP match; credential id: %s, user_id: %s',
                          credential['id'], user_info.user_id)
            except (TypeError):
                LOG.debug('Base32 decode failed for TOTP credential %s',
                          credential['id'])

        if not valid_passcode:
            # authentication failed because of invalid username or passcode
            msg = _('Invalid username or TOTP passcode')
            raise exception.Unauthorized(msg)

        response_data['user_id'] = user_info.user_id

        return base.AuthHandlerResponse(status=True,
                                        response_body=None,
                                        response_data=response_data)
예제 #7
0
    def authenticate(self, context, auth_payload):
        response_data = {}
        if 'response' in auth_payload:
            if auth_payload['response'] != EXPECTED_RESPONSE:
                raise exception.Unauthorized('Wrong answer')

            response_data['user_id'] = DEMO_USER_ID
            return base.AuthHandlerResponse(status=True,
                                            response_body=None,
                                            response_data=response_data)
        else:
            return base.AuthHandlerResponse(
                status=False,
                response_body={
                    "challenge": "What's the name of your high school?"
                },
                response_data=None)
예제 #8
0
파일: wmtotp.py 프로젝트: zbyszkop/puppet
    def authenticate(self, request, auth_payload):
        """Try to authenticate against the identity backend."""
        response_data = {}
        user_info = auth_plugins.UserAuthInfo.create(auth_payload, self.method)

        # Before we do anything else, make sure that this user is allowed
        #  access from their source IP
        password_safelist.check_safelist(user_info.user_id,
                                         request.environ['REMOTE_ADDR'])

        try:
            PROVIDERS.identity_api.authenticate(request,
                                                user_id=user_info.user_id,
                                                password=user_info.password)
        except AssertionError:
            # authentication failed because of invalid username or password
            msg = _('Invalid username or password')
            raise exception.Unauthorized(msg)

        # Password auth succeeded, check two-factor
        # LOG.debug("OATH: Doing 2FA for user_info " +
        #     ( "%s(%r)" % (user_info.__class__, user_info.__dict__) ) )
        # LOG.debug("OATH: Doing 2FA for auth_payload " +
        #     ( "%s(%r)" % (auth_payload.__class__, auth_payload) ) )
        if 'totp' not in auth_payload['user']:
            LOG.debug("OATH: 2FA failed, missing totp param")
            msg = _('Missing two-factor token')
            raise exception.Unauthorized(msg)

        wtclient = wikitechclient.WikitechClient(
            CONF.oath.wikitech_host, CONF.oath.wikitech_consumer_token,
            CONF.oath.wikitech_consumer_secret,
            CONF.oath.wikitech_access_token, CONF.oath.wikitech_access_secret)
        valid = wtclient.oathvalidate(user_info.user_ref['name'],
                                      auth_payload['user']['totp'])

        if valid['enabled']:
            if valid['valid']:
                LOG.debug("OATH: 2FA passed")
            else:
                LOG.debug("OATH: 2FA failed")
                msg = _('Invalid two-factor token')
                raise exception.Unauthorized(msg)
        else:
            LOG.debug("OATH: user '%s' does not have 2FA enabled.",
                      user_info.user_ref['name'])
            msg = _('2FA is not enabled; login forbidden')
            raise exception.Unauthorized(msg)

        response_data['user_id'] = user_info.user_id

        return base.AuthHandlerResponse(status=True,
                                        response_body=None,
                                        response_data=response_data)
예제 #9
0
    def authenticate(self, request, auth_payload):
        """Try to authenticate against the identity backend and with TOTP."""
        response_data = {}

        user_info = plugins.UserAuthInfo.create(auth_payload, METHOD_NAME)

        # First we check if the given user_id has totp credentials
        credentials = PROVIDERS.credential_api.list_credentials_for_user(
            user_info.user_id, type='totp')

        if credentials:
            # If the user has credentials, strip passcode from password
            user_password = user_info.password[:-utils.PASSCODE_LENGTH]
            auth_passcode = user_info.password[-utils.PASSCODE_LENGTH:]
            valid_passcode = False
        else:
            # If the user has no TOTP credentials, skip TOTP.
            user_password = user_info.password
            valid_passcode = True

        try:
            PROVIDERS.identity_api.authenticate(
                request,
                user_id=user_info.user_id,
                password=user_password)
        except AssertionError:
            # authentication failed because of invalid username or password
            msg = _('Invalid username or password')
            raise exception.Unauthorized(msg)

        for credential in credentials:
            try:
                generated_passcodes = utils._generate_totp_passcodes(
                    credential['blob'])
                if auth_passcode in generated_passcodes:
                    valid_passcode = True
                    break
            except (ValueError, KeyError):
                LOG.debug('No TOTP match; credential id: %s, user_id: %s',
                          credential['id'], user_info.user_id)
            except (TypeError):
                LOG.debug('Base32 decode failed for TOTP credential %s',
                          credential['id'])

        if not valid_passcode:
            # authentication failed because of invalid passcode
            msg = _('Invalid TOTP passcode')
            raise exception.Unauthorized(msg)

        response_data['user_id'] = user_info.user_id

        return base.AuthHandlerResponse(status=True, response_body=None,
                                        response_data=response_data)
예제 #10
0
    def authenticate(self, request, auth_payload):
        if 'id' not in auth_payload:
            raise exception.ValidationError(attribute='id', target='token')
        token_ref = self._get_token_ref(auth_payload)
        if token_ref.is_federated_user and self.federation_api:
            response_data = mapped.handle_scoped_token(request, token_ref,
                                                       self.federation_api,
                                                       self.identity_api)
        else:
            response_data = token_authenticate(request, token_ref)

        return base.AuthHandlerResponse(status=True,
                                        response_body=None,
                                        response_data=response_data)
예제 #11
0
    def authenticate(self, auth_payload):
        """Try to authenticate using SecurID ober Radius"""
        response_data = {}

        user_info = plugins.TOTPUserInfo.create(auth_payload, METHOD_NAME)
        auth_passcode = auth_payload.get('user').get('passcode')

        LOG.info("Authenticating %s's SecurID passcode" %
                 user_info.user_ref['name'])

        if not re.match(UID_REGEX, user_info.user_ref['name']):
            # authentication failed because of invalid username
            raise exception.Unauthorized(
                'SecurID/Radius authentication is only supported for CID users'
            )

        if not CONF.cc_radius.host or not CONF.cc_radius.port or not CONF.cc_radius.secret:
            raise exception.Unauthorized(
                'SecurID/Radius backend service configuration is missing')

        try:
            if not radius.authenticate(CONF.cc_radius.secret,
                                       user_info.user_ref['name'],
                                       auth_passcode,
                                       host=CONF.cc_radius.host,
                                       port=CONF.cc_radius.port):
                LOG.info(
                    "Authentication failed: SecurID token of '%s' invalid" %
                    user_info.user_ref['name'])
                # authentication failed because of invalid username or passcode
                msg = _('Invalid username or passcode')
                raise exception.Unauthorized(msg)
        except exception.Unauthorized:
            raise
        except Exception as e:
            LOG.error(
                "Authentication failed: SecurID verification of '%s' failed: %s"
                % (user_info.user_ref['name'], e))
            # authentication failed because of radius backend issue
            msg = _('SecurID authentication failed')
            raise exception.Unauthorized(msg)

        response_data['user_id'] = user_info.user_id

        return base.AuthHandlerResponse(status=True,
                                        response_body=None,
                                        response_data=response_data)
    def authenticate(self, auth_payload):
        """Authenticate an application."""
        response_data = {}
        app_cred_info = auth_plugins.AppCredInfo.create(
            auth_payload, METHOD_NAME)

        try:
            PROVIDERS.application_credential_api.authenticate(
                application_credential_id=app_cred_info.id,
                secret=app_cred_info.secret)
        except AssertionError as e:
            raise exception.Unauthorized(e)
        response_data['user_id'] = app_cred_info.user_id

        return base.AuthHandlerResponse(status=True,
                                        response_body=None,
                                        response_data=response_data)
예제 #13
0
    def authenticate(self, auth_payload):
        """Try to authenticate against the identity backend."""
        response_data = {}
        user_info = auth_plugins.UserAuthInfo.create(auth_payload, METHOD_NAME)

        try:
            PROVIDERS.identity_api.authenticate(user_id=user_info.user_id,
                                                password=user_info.password)
        except AssertionError:
            # authentication failed because of invalid username or password
            msg = _('Invalid username or password')
            raise exception.Unauthorized(msg)

        response_data['user_id'] = user_info.user_id

        return base.AuthHandlerResponse(status=True,
                                        response_body=None,
                                        response_data=response_data)
예제 #14
0
    def authenticate(self, auth_payload):
        if 'id' not in auth_payload:
            raise exception.ValidationError(attribute='id', target='token')
        token = self._get_token_ref(auth_payload)
        if token.is_federated and PROVIDERS.federation_api:
            response_data = mapped.handle_scoped_token(
                token, PROVIDERS.federation_api, PROVIDERS.identity_api)
        else:
            response_data = token_authenticate(token)

        # NOTE(notmorgan): The Token auth method is *very* special and sets the
        # previous values to the method_names. This is because it can be used
        # for re-scoping and we want to maintain the values. Most
        # AuthMethodHandlers do no such thing and this is not required.
        response_data.setdefault('method_names', []).extend(token.methods)

        return base.AuthHandlerResponse(status=True,
                                        response_body=None,
                                        response_data=response_data)
예제 #15
0
    def authenticate(self, request, auth_payload):
        """Autenticate the athenz token

        Validate the athenz token create projects/users if needed
        """
        response_data = {}
        user_info = AthenzUserAuthInfo.create(auth_payload, METHOD_NAME)
        if not is_athenz_role_token(user_info.athenz_token):
            LOG.error("Not a valid athenz role token")
            raise exception.Unauthorized(_('Not a valid athenz role token'))

        atoken = AthenzToken(user_info.athenz_token)
        if atoken.validate(user_info.user_name) and atoken.user:
            # We got a valid athenz token
            LOG.debug("Athenz token is valid")
            # Get domain ID from name if it is not part of the request
            domain_id = user_info.domain_id
            if not user_info.domain_id:
                domain_ref = self.resource_api.get_domain_by_name(
                    user_info.domain_name)
                domain_id = domain_ref['id']

            # Assert domain isn't disabled
            self._lookup_domain(domain_id)

            # Create the user specified in athenz token if necessary
            user_ref = self._lookup_and_create_user(request, domain_id,
                                                    atoken.user)
            # Create keystone project specified by the user in the request
            # (user_info.project_name) after validating athenz role token has
            # the same project name in its roles.
            self._create_project_and_assign_roles(request, atoken,
                                                  user_info.project_name,
                                                  user_ref, domain_id)
            response_data['user_id'] = user_ref['id']
            response_data['athenz_token'] = user_info.athenz_token

            return base.AuthHandlerResponse(status=True,
                                            response_body=None,
                                            response_data=response_data)
        msg = _('Invalid athenz token')
        raise exception.Unauthorized(msg)
예제 #16
0
    def authenticate(self, auth_payload):
        response_data = {}

        try:
            domain = auth_payload['user'].get('domain', {})
            LOG.info("Authenticating %s@%s.." %
                     (auth_payload['user'].get(
                         'name', auth_payload['user'].get('id', '<nil>')),
                      domain.get('name', domain.get('id', '<nil>'))))
            user_info = core.UserAuthInfo.create(auth_payload, METHOD_NAME)
        except Exception as e:
            LOG.info("Authentication failed: %s" % e)
            raise

        try:
            # Try to authenticate against the identity backend.
            PROVIDERS.identity_api.authenticate(user_id=user_info.user_id,
                                                password=user_info.password)
        except AssertionError:
            try:
                # check if the user actually exists in domain, since the exception gives no clue about the root-cause
                self.identity_api.get_user(user_info.user_id)
            except Exception as e:
                LOG.info("Authentication failed: %s" % e)
                # authentication failed because of invalid username
                msg = _('Invalid username or password')
                raise exception.Unauthorized(msg)

            # if it is a CID user, check if the user has changed his GLOBAL password
            if re.match(UID_REGEX, user_info.user_ref['name']) \
                    and self._authenticate_ews(user_info.user_ref['name'], user_info.password):
                # and update the password in CCloud AD
                self._update_password(user_info)
            else:
                # authentication failed because of invalid username or password
                msg = _('Invalid username or password')
                raise exception.Unauthorized(msg)

        response_data['user_id'] = user_info.user_id
        return base.AuthHandlerResponse(status=True,
                                        response_body=None,
                                        response_data=response_data)
예제 #17
0
    def authenticate(self, request, auth_payload,):
        """Use REMOTE_USER to look up the user in the identity backend.

        The user_id from the actual user from the REMOTE_USER env variable is
        placed in the response_data.
        """
        response_data = {}
        if not request.remote_user:
            msg = _('No authenticated user')
            raise exception.Unauthorized(msg)

        try:
            user_ref = self._authenticate(request)
        except Exception:
            msg = _('Unable to lookup user %s') % request.remote_user
            raise exception.Unauthorized(msg)

        response_data['user_id'] = user_ref['id']
        return base.AuthHandlerResponse(status=True, response_body=None,
                                        response_data=response_data)
예제 #18
0
    def authenticate(self, request, auth_payload):
        """Turn a signed request with an access key into a keystone token."""
        response_data = {}
        oauth_headers = oauth.get_oauth_headers(request.headers)
        access_token_id = oauth_headers.get('oauth_token')

        if not access_token_id:
            raise exception.ValidationError(
                attribute='oauth_token', target='request')

        acc_token = self.oauth_api.get_access_token(access_token_id)

        expires_at = acc_token['expires_at']
        if expires_at:
            now = timeutils.utcnow()
            expires = timeutils.normalize_time(
                timeutils.parse_isotime(expires_at))
            if now > expires:
                raise exception.Unauthorized(_('Access token is expired'))

        url = controller.V3Controller.base_url(request.context_dict,
                                               request.path_info)
        access_verifier = oauth.ResourceEndpoint(
            request_validator=validator.OAuthValidator(),
            token_generator=oauth.token_generator)
        result, request = access_verifier.validate_protected_resource_request(
            url,
            http_method='POST',
            body=request.params,
            headers=request.headers,
            realms=None
        )
        if not result:
            msg = _('Could not validate the access token')
            raise exception.Unauthorized(msg)
        response_data['user_id'] = acc_token['authorizing_user_id']
        response_data['access_token_id'] = access_token_id
        response_data['project_id'] = acc_token['project_id']

        return base.AuthHandlerResponse(status=True, response_body=None,
                                        response_data=response_data)
예제 #19
0
    def authenticate(self, auth_info):
        """Use HTTP_SSL_CLIENT_CERT to look up the user in the identity backend.
        """
        response_data = {}
        cert = ''

        try:
            # client certificate validated?
            verification = flask.request.environ[
                CONF.cc_x509.certificate_verify_header]
            if verification != 'SUCCESS':
                raise Exception("Certificate has not been validated")

            # grab the certificate
            certificate = flask.request.environ[
                CONF.cc_x509.certificate_header]
            cert = crypto.load_certificate(crypto.FILETYPE_PEM,
                                           unquote_to_bytes(certificate))

            # is it stil valid?
            if cert.has_expired():
                raise Exception("certificate has expired")

            # check the issuer
            items = []
            x509name = cert.get_issuer()
            for item in reversed(x509name.get_components()):
                items.append(
                    '%s=%s' %
                    (item[0].decode("utf-8"), item[1].decode("utf-8")))
            issuer = ",".join(items)

            if issuer not in CONF.cc_x509.trusted_issuer:
                raise Exception(
                    "certificate issuer %s is not configured as trusted issuer (we trust %s)"
                    % (issuer, CONF.cc_x509.trusted_issuer))

            # and the subject (username)
            username = cert.get_subject().CN
        except Exception as e:
            LOG.info("Invalid certificate from %s: %s" %
                     (flask.request.environ.get('REMOTE_ADDR'), e))
            if CONF.debug:
                LOG.info("%s",
                         crypto.dump_certificate(crypto.FILETYPE_TEXT, cert))
            raise exception.Unauthorized(
                "Authentication failed. No trusted certificate provided: %s" %
                e)

        try:
            user_ref = self._authenticate(username)
            user_info = plugins.BaseUserInfo.create(user_ref, METHOD_NAME)
            response_data['user_id'] = user_info.user_id
            # at this point the user is considered to be authenticated, mark
            # the user as active
            ref = PROVIDERS.identity_api._shadow_nonlocal_user(
                user_info.user_ref)
            PROVIDERS.shadow_users_api.set_last_active_at(ref['id'])
            # send a notification. The notification wrapper expects that
            # there is a method that accepts user_id as the first argument,
            # and that method actually authenticates a user. Out mechanism
            # verifies authentication differently. So lets provide a simple
            # wrapper just to please the interface.
            # TODO: move the actual authn and certificate checks to this
            # method.
            self.authenticate_by_id(ref['id'])

            return base.AuthHandlerResponse(status=True,
                                            response_body=None,
                                            response_data=response_data)
        except Exception as e:
            LOG.info("Authentication failed. Invalid username %s from %s: %s" %
                     (username, flask.request.environ.get('REMOTE_ADDR'), e))
            msg = _('Authentication failed: %s' % e)
            raise exception.Unauthorized(msg)