Ejemplo n.º 1
0
 def _get_token_id(self, token_data):
     try:
         token_id = cms.cms_sign_token(json.dumps(token_data), CONF.signing.certfile, CONF.signing.keyfile)
         return token_id
     except environment.subprocess.CalledProcessError:
         LOG.exception("Unable to sign token")
         raise exception.UnexpectedError(_("Unable to sign token."))
Ejemplo n.º 2
0
def create_token(context, auth_context, auth_info):
    token_data_helper = TokenDataHelper(context)
    (domain_id, project_id, trust) = auth_info.get_scope()
    method_names = list(set(auth_info.get_method_names() +
                            auth_context.get('method_names', [])))
    token_data = token_data_helper.get_token_data(
        auth_context['user_id'],
        method_names,
        auth_context['extras'],
        domain_id,
        project_id,
        auth_context.get('expires_at', None),
        trust)

    if CONF.signing.token_format == 'UUID':
        token_id = uuid.uuid4().hex
    elif CONF.signing.token_format == 'PKI':
        try:
            token_id = cms.cms_sign_token(json.dumps(token_data),
                                          CONF.signing.certfile,
                                          CONF.signing.keyfile)
        except subprocess.CalledProcessError:
            raise exception.UnexpectedError(_(
                'Unable to sign token.'))
    else:
        raise exception.UnexpectedError(_(
            'Invalid value for token_format: %s.'
            '  Allowed values are PKI or UUID.') %
            CONF.signing.token_format)
    token_api = token_module.Manager()
    try:
        expiry = token_data['token']['expires_at']
        if isinstance(expiry, basestring):
            expiry = timeutils.normalize_time(timeutils.parse_isotime(expiry))
        role_ids = []
        if 'project' in token_data['token']:
            # project-scoped token, fill in the v2 token data
            # all we care are the role IDs
            role_ids = [role['id'] for role in token_data['token']['roles']]
        metadata_ref = {'roles': role_ids}
        data = dict(key=token_id,
                    id=token_id,
                    expires=expiry,
                    user=token_data['token']['user'],
                    tenant=token_data['token'].get('project'),
                    metadata=metadata_ref,
                    token_data=token_data,
                    trust_id=trust['id'] if trust else None)
        token_api.create_token(context, token_id, data)
    except Exception as e:
        # an identical token may have been created already.
        # if so, return the token_data as it is also identical
        try:
            token_api.get_token(context=context,
                                token_id=token_id)
        except exception.TokenNotFound:
            raise e

    return (token_id, token_data)
Ejemplo n.º 3
0
def create_token(context, auth_context, auth_info):
    token_data_helper = TokenDataHelper(context)
    (domain_id, project_id, trust) = auth_info.get_scope()
    method_names = list(set(auth_info.get_method_names() +
                            auth_context.get('method_names', [])))
    token_data = token_data_helper.get_token_data(
        auth_context['user_id'],
        method_names,
        auth_context['extras'],
        domain_id,
        project_id,
        auth_context.get('expires_at', None),
        trust)

    if CONF.signing.token_format == 'UUID':
        token_id = uuid.uuid4().hex
    elif CONF.signing.token_format == 'PKI':
        try:
            token_id = cms.cms_sign_token(json.dumps(token_data),
                                          CONF.signing.certfile,
                                          CONF.signing.keyfile)
        except subprocess.CalledProcessError:
            raise exception.UnexpectedError(_(
                'Unable to sign token.'))
    else:
        raise exception.UnexpectedError(_(
            'Invalid value for token_format: %s.'
            '  Allowed values are PKI or UUID.') %
            CONF.signing.token_format)
    token_api = token_module.Manager()
    try:
        expiry = token_data['token']['expires_at']
        if isinstance(expiry, basestring):
            expiry = timeutils.normalize_time(timeutils.parse_isotime(expiry))
        role_ids = []
        if 'project' in token_data['token']:
            # project-scoped token, fill in the v2 token data
            # all we care are the role IDs
            role_ids = [role['id'] for role in token_data['token']['roles']]
        metadata_ref = {'roles': role_ids}
        data = dict(key=token_id,
                    id=token_id,
                    expires=expiry,
                    user=token_data['token']['user'],
                    tenant=token_data['token'].get('project'),
                    metadata=metadata_ref,
                    token_data=token_data,
                    trust_id=trust['id'] if trust else None)
        token_api.create_token(context, token_id, data)
    except Exception as e:
        # an identical token may have been created already.
        # if so, return the token_data as it is also identical
        try:
            token_api.get_token(context=context,
                                token_id=token_id)
        except exception.TokenNotFound:
            raise e

    return (token_id, token_data)
Ejemplo n.º 4
0
 def _get_token_id(self, token_data):
     try:
         token_id = cms.cms_sign_token(json.dumps(token_data),
                                       CONF.signing.certfile,
                                       CONF.signing.keyfile)
         return token_id
     except environment.subprocess.CalledProcessError:
         LOG.exception('Unable to sign token')
         raise exception.UnexpectedError(_('Unable to sign token.'))
Ejemplo n.º 5
0
 def test_v3_pki_token_id(self):
     self.opt_in_group('signing', token_format='PKI')
     auth_data = self.build_authentication_request(
         user_id=self.user['id'],
         password=self.user['password'])
     resp = self.post('/auth/tokens', body=auth_data)
     token_data = resp.body
     token_id = resp.getheader('X-Subject-Token')
     self.assertIn('expires_at', token_data['token'])
     token_signed = cms.cms_sign_token(json.dumps(token_data),
                                       CONF.signing.certfile,
                                       CONF.signing.keyfile)
     self.assertEqual(token_signed, token_id)
Ejemplo n.º 6
0
 def _get_token_id(self, token_data):
     try:
         # force conversion to a string as the keystone client cms code
         # produces unicode.  This can be removed if the client returns
         # str()
         # TODO(ayoung): Make to a byte_str for Python3
         token_json = jsonutils.dumps(token_data, cls=utils.PKIEncoder)
         token_id = str(cms.cms_sign_token(token_json,
                                           CONF.signing.certfile,
                                           CONF.signing.keyfile))
         return token_id
     except environment.subprocess.CalledProcessError:
         LOG.exception(_LE('Unable to sign token'))
         raise exception.UnexpectedError(_(
             'Unable to sign token.'))
Ejemplo n.º 7
0
    def authenticate(self, context, auth=None):
        """Authenticate credentials and return a token.

        Accept auth as a dict that looks like::

            {
                "auth":{
                    "passwordCredentials":{
                        "username":"******",
                        "password":"******"
                    },
                    "tenantName":"customer-x"
                }
            }

        In this case, tenant is optional, if not provided the token will be
        considered "unscoped" and can later be used to get a scoped token.

        Alternatively, this call accepts auth with only a token and tenant
        that will return a token that is scoped to that tenant.
        """

        if auth is None:
            raise exception.ValidationError(attribute='auth',
                                            target='request body')

        auth_token_data = None

        if "token" in auth:
            # Try to authenticate using a token
            auth_info = self._authenticate_token(context, auth)
        else:
            # Try external authentication
            try:
                auth_info = self._authenticate_external(context, auth)
            except ExternalAuthNotApplicable:
                # Try local authentication
                auth_info = self._authenticate_local(context, auth)

        user_ref, tenant_ref, metadata_ref, expiry = auth_info
        core.validate_auth_info(self, context, user_ref, tenant_ref)
        trust_id = metadata_ref.get('trust_id')
        user_ref = self._filter_domain_id(user_ref)
        if tenant_ref:
            tenant_ref = self._filter_domain_id(tenant_ref)
        auth_token_data = self._get_auth_token_data(user_ref, tenant_ref,
                                                    metadata_ref, expiry)

        if tenant_ref:
            catalog_ref = self.catalog_api.get_catalog(
                context=context,
                user_id=user_ref['id'],
                tenant_id=tenant_ref['id'],
                metadata=metadata_ref)
        else:
            catalog_ref = {}

        auth_token_data['id'] = 'placeholder'

        roles_ref = []
        for role_id in metadata_ref.get('roles', []):
            role_ref = self.identity_api.get_role(context, role_id)
            roles_ref.append(dict(name=role_ref['name']))

        token_data = Auth.format_token(auth_token_data, roles_ref)

        service_catalog = Auth.format_catalog(catalog_ref)
        token_data['access']['serviceCatalog'] = service_catalog

        if CONF.signing.token_format == 'UUID':
            token_id = uuid.uuid4().hex
        elif CONF.signing.token_format == 'PKI':
            try:
                token_id = cms.cms_sign_token(json.dumps(token_data),
                                              CONF.signing.certfile,
                                              CONF.signing.keyfile)
            except subprocess.CalledProcessError:
                raise exception.UnexpectedError(_('Unable to sign token.'))
        else:
            raise exception.UnexpectedError(
                _('Invalid value for token_format: %s.'
                  '  Allowed values are PKI or UUID.') %
                CONF.signing.token_format)
        try:
            self.token_api.create_token(
                context, token_id,
                dict(key=token_id,
                     id=token_id,
                     expires=auth_token_data['expires'],
                     user=user_ref,
                     tenant=tenant_ref,
                     metadata=metadata_ref,
                     trust_id=trust_id))
        except Exception as e:
            # an identical token may have been created already.
            # if so, return the token_data as it is also identical
            try:
                self.token_api.get_token(context=context, token_id=token_id)
            except exception.TokenNotFound:
                raise e

        token_data['access']['token']['id'] = token_id

        return token_data
Ejemplo n.º 8
0
    def authenticate(self, context, auth=None):
        """Authenticate credentials and return a token.

        Accept auth as a dict that looks like::

            {
                "auth":{
                    "passwordCredentials":{
                        "username":"******",
                        "password":"******"
                    },
                    "tenantName":"customer-x"
                }
            }

        In this case, tenant is optional, if not provided the token will be
        considered "unscoped" and can later be used to get a scoped token.

        Alternatively, this call accepts auth with only a token and tenant
        that will return a token that is scoped to that tenant.
        """

        if auth is None:
            raise exception.ValidationError(attribute='auth',
                                            target='request body')

        auth_token_data = None

        if "token" in auth:
            # Try to authenticate using a token
            auth_info = self._authenticate_token(
                context, auth)
        else:
            # Try external authentication
            try:
                auth_info = self._authenticate_external(
                    context, auth)
            except ExternalAuthNotApplicable:
                # Try local authentication
                auth_info = self._authenticate_local(
                    context, auth)

        user_ref, tenant_ref, metadata_ref, expiry = auth_info
        user_ref = self._filter_domain_id(user_ref)
        if tenant_ref:
            tenant_ref = self._filter_domain_id(tenant_ref)
        auth_token_data = self._get_auth_token_data(user_ref,
                                                    tenant_ref,
                                                    metadata_ref,
                                                    expiry)

        # If the user is disabled don't allow them to authenticate
        if not user_ref.get('enabled', True):
            msg = 'User is disabled: %s' % user_ref['id']
            LOG.warning(msg)
            raise exception.Unauthorized(msg)

        # If the user's domain is disabled don't allow them to authenticate
        # TODO(dolph): remove this check after default-domain migration
        if user_ref.get('domain_id') is not None:
            user_domain_ref = self.identity_api.get_domain(
                context,
                user_ref['domain_id'])
            if user_domain_ref and not user_domain_ref.get('enabled', True):
                msg = 'Domain is disabled: %s' % user_domain_ref['id']
                LOG.warning(msg)
                raise exception.Unauthorized(msg)

        if tenant_ref:
            # If the project is disabled don't allow them to authenticate
            if not tenant_ref.get('enabled', True):
                msg = 'Tenant is disabled: %s' % tenant_ref['id']
                LOG.warning(msg)
                raise exception.Unauthorized(msg)

            # If the project's domain is disabled don't allow them to
            # authenticate
            # TODO(dolph): remove this check after default-domain migration
            if tenant_ref.get('domain_id') is not None:
                project_domain_ref = self.identity_api.get_domain(
                    context,
                    tenant_ref['domain_id'])
                if (project_domain_ref and
                        not project_domain_ref.get('enabled', True)):
                    msg = 'Domain is disabled: %s' % project_domain_ref['id']
                    LOG.warning(msg)
                    raise exception.Unauthorized(msg)

            catalog_ref = self.catalog_api.get_catalog(
                context=context,
                user_id=user_ref['id'],
                tenant_id=tenant_ref['id'],
                metadata=metadata_ref)
        else:
            catalog_ref = {}

        auth_token_data['id'] = 'placeholder'

        roles_ref = []
        for role_id in metadata_ref.get('roles', []):
            role_ref = self.identity_api.get_role(context, role_id)
            roles_ref.append(dict(name=role_ref['name']))

        token_data = Auth.format_token(auth_token_data, roles_ref)

        service_catalog = Auth.format_catalog(catalog_ref)
        token_data['access']['serviceCatalog'] = service_catalog

        if CONF.signing.token_format == 'UUID':
            token_id = uuid.uuid4().hex
        elif CONF.signing.token_format == 'PKI':
            token_id = cms.cms_sign_token(json.dumps(token_data),
                                          CONF.signing.certfile,
                                          CONF.signing.keyfile)
        else:
            raise exception.UnexpectedError(
                'Invalid value for token_format: %s.'
                '  Allowed values are PKI or UUID.' %
                CONF.signing.token_format)
        try:
            self.token_api.create_token(
                context, token_id, dict(key=token_id,
                                        id=token_id,
                                        expires=auth_token_data['expires'],
                                        user=user_ref,
                                        tenant=tenant_ref,
                                        metadata=metadata_ref))
        except Exception as e:
            # an identical token may have been created already.
            # if so, return the token_data as it is also identical
            try:
                self.token_api.get_token(context=context,
                                         token_id=token_id)
            except exception.TokenNotFound:
                raise e

        token_data['access']['token']['id'] = token_id

        return token_data
Ejemplo n.º 9
0
    def authenticate(self, context, auth=None):
        """Authenticate credentials and return a token.

        Accept auth as a dict that looks like::

            {
                "auth":{
                    "passwordCredentials":{
                        "username":"******",
                        "password":"******"
                    },
                    "tenantName":"customer-x"
                }
            }

        In this case, tenant is optional, if not provided the token will be
        considered "unscoped" and can later be used to get a scoped token.

        Alternatively, this call accepts auth with only a token and tenant
        that will return a token that is scoped to that tenant.
        """

        if auth is None:
            raise exception.ValidationError(attribute='auth',
                                            target='request body')

        auth_token_data = None

        if "token" in auth:
            # Try to authenticate using a token
            auth_info = self._authenticate_token(
                context, auth)
        else:
            # Try external authentication
            try:
                auth_info = self._authenticate_external(
                    context, auth)
            except ExternalAuthNotApplicable:
                # Try local authentication
                auth_info = self._authenticate_local(
                    context, auth)

        user_ref, tenant_ref, metadata_ref, expiry = auth_info
        core.validate_auth_info(self, context, user_ref, tenant_ref)
        trust_id = metadata_ref.get('trust_id')
        user_ref = self._filter_domain_id(user_ref)
        if tenant_ref:
            tenant_ref = self._filter_domain_id(tenant_ref)
        auth_token_data = self._get_auth_token_data(user_ref,
                                                    tenant_ref,
                                                    metadata_ref,
                                                    expiry)

        if tenant_ref:
            catalog_ref = self.catalog_api.get_catalog(
                context=context,
                user_id=user_ref['id'],
                tenant_id=tenant_ref['id'],
                metadata=metadata_ref)
        else:
            catalog_ref = {}

        auth_token_data['id'] = 'placeholder'

        roles_ref = []
        for role_id in metadata_ref.get('roles', []):
            role_ref = self.identity_api.get_role(context, role_id)
            roles_ref.append(dict(name=role_ref['name']))

        token_data = Auth.format_token(auth_token_data, roles_ref)

        service_catalog = Auth.format_catalog(catalog_ref)
        token_data['access']['serviceCatalog'] = service_catalog

        if CONF.signing.token_format == 'UUID':
            token_id = uuid.uuid4().hex
        elif CONF.signing.token_format == 'PKI':
            try:
                token_id = cms.cms_sign_token(json.dumps(token_data),
                                              CONF.signing.certfile,
                                              CONF.signing.keyfile)
            except environment.subprocess.CalledProcessError:
                raise exception.UnexpectedError(_(
                    'Unable to sign token.'))
        else:
            raise exception.UnexpectedError(_(
                'Invalid value for token_format: %s.'
                '  Allowed values are PKI or UUID.') %
                CONF.signing.token_format)
        try:
            self.token_api.create_token(
                context, token_id, dict(key=token_id,
                                        id=token_id,
                                        expires=auth_token_data['expires'],
                                        user=user_ref,
                                        tenant=tenant_ref,
                                        metadata=metadata_ref,
                                        trust_id=trust_id))
        except Exception as e:
            # an identical token may have been created already.
            # if so, return the token_data as it is also identical
            try:
                self.token_api.get_token(context=context,
                                         token_id=token_id)
            except exception.TokenNotFound:
                raise e

        token_data['access']['token']['id'] = token_id

        return token_data
Ejemplo n.º 10
0
    def authenticate(self, context, auth=None):
        """Authenticate credentials and return a token.

        Accept auth as a dict that looks like::

            {
                "auth":{
                    "passwordCredentials":{
                        "username":"******",
                        "password":"******"
                    },
                    "tenantName":"customer-x"
                }
            }

        In this case, tenant is optional, if not provided the token will be
        considered "unscoped" and can later be used to get a scoped token.

        Alternatively, this call accepts auth with only a token and tenant
        that will return a token that is scoped to that tenant.
        """

        if 'passwordCredentials' in auth:
            user_id = auth['passwordCredentials'].get('userId', None)
            username = auth['passwordCredentials'].get('username', '')
            password = auth['passwordCredentials'].get('password', '')
            tenant_name = auth.get('tenantName', None)

            if username:
                try:
                    user_ref = self.identity_api.get_user_by_name(
                        context=context, user_name=username)
                    user_id = user_ref['id']
                except exception.UserNotFound:
                    raise exception.Unauthorized()

            # more compat
            tenant_id = auth.get('tenantId', None)
            if tenant_name:
                try:
                    tenant_ref = self.identity_api.get_tenant_by_name(
                        context=context, tenant_name=tenant_name)
                    tenant_id = tenant_ref['id']
                except exception.TenantNotFound:
                    raise exception.Unauthorized()

            try:
                auth_info = self.identity_api.authenticate(context=context,
                                                           user_id=user_id,
                                                           password=password,
                                                           tenant_id=tenant_id)
                (user_ref, tenant_ref, metadata_ref) = auth_info

                # If the user is disabled don't allow them to authenticate
                if not user_ref.get('enabled', True):
                    LOG.warning('User %s is disabled' % user_id)
                    raise exception.Unauthorized()

                # If the tenant is disabled don't allow them to authenticate
                if tenant_ref and not tenant_ref.get('enabled', True):
                    LOG.warning('Tenant %s is disabled' % tenant_id)
                    raise exception.Unauthorized()
            except AssertionError as e:
                raise exception.Unauthorized(e.message)
            auth_token_data = dict(zip(['user', 'tenant', 'metadata'],
                                       auth_info))
            expiry = self.token_api._get_default_expire_time(context=context)

            if tenant_ref:
                catalog_ref = self.catalog_api.get_catalog(
                    context=context,
                    user_id=user_ref['id'],
                    tenant_id=tenant_ref['id'],
                    metadata=metadata_ref)
            else:
                catalog_ref = {}
        elif 'token' in auth:
            old_token = auth['token'].get('id', None)
            tenant_name = auth.get('tenantName')

            try:
                old_token_ref = self.token_api.get_token(context=context,
                                                         token_id=old_token)
            except exception.NotFound:
                raise exception.Unauthorized()

            user_ref = old_token_ref['user']
            user_id = user_ref['id']

            current_user_ref = self.identity_api.get_user(context=context,
                                                          user_id=user_id)

            # If the user is disabled don't allow them to authenticate
            if not current_user_ref.get('enabled', True):
                LOG.warning('User %s is disabled' % user_id)
                raise exception.Unauthorized()

            if tenant_name:
                tenant_ref = self.identity_api.get_tenant_by_name(
                    context=context,
                    tenant_name=tenant_name)
                tenant_id = tenant_ref['id']
            else:
                tenant_id = auth.get('tenantId', None)
            tenants = self.identity_api.get_tenants_for_user(context, user_id)

            if tenant_id:
                if not tenant_id in tenants:
                    LOG.warning('User %s is authorized for tenant %s'
                                % (user_id, tenant_id))
                    raise exception.Unauthorized()

                # if the old token is sufficient unpack and return it
                if (old_token_ref['tenant']
                        and tenant_id == old_token_ref['tenant']['id']
                        and len(old_token) > cms.UUID_TOKEN_LENGTH):
                    json_data = cms.verify_token(
                        old_token,
                        config.CONF.signing.certfile,
                        config.CONF.signing.ca_certs)
                    return_data = json.loads(json_data)
                    return_data['access']['token']['id'] = old_token
                    return return_data

            expiry = old_token_ref['expires']
            try:
                tenant_ref = self.identity_api.get_tenant(context=context,
                                                          tenant_id=tenant_id)
            except exception.TenantNotFound:
                tenant_ref = None
                metadata_ref = {}
                catalog_ref = {}
            except exception.MetadataNotFound:
                metadata_ref = {}
                catalog_ref = {}

            # If the tenant is disabled don't allow them to authenticate
            if tenant_ref and not tenant_ref.get('enabled', True):
                LOG.warning('Tenant %s is disabled' % tenant_id)
                raise exception.Unauthorized()

            if tenant_ref:
                metadata_ref = self.identity_api.get_metadata(
                    context=context,
                    user_id=user_ref['id'],
                    tenant_id=tenant_ref['id'])
                catalog_ref = self.catalog_api.get_catalog(
                    context=context,
                    user_id=user_ref['id'],
                    tenant_id=tenant_ref['id'],
                    metadata=metadata_ref)

            auth_token_data = dict(dict(user=current_user_ref,
                                        tenant=tenant_ref,
                                        metadata=metadata_ref))

        auth_token_data['expires'] = expiry
        auth_token_data['id'] = 'placeholder'

        roles_ref = []
        for role_id in metadata_ref.get('roles', []):
            role_ref = self.identity_api.get_role(context, role_id)
            roles_ref.append(dict(name=role_ref['name']))

        token_data = self._format_token(auth_token_data, roles_ref)

        service_catalog = self._format_catalog(catalog_ref)
        token_data['access']['serviceCatalog'] = service_catalog

        if config.CONF.signing.token_format == "UUID":
            token_id = uuid.uuid4().hex
        elif config.CONF.signing.token_format == "PKI":

            token_id = cms.cms_sign_token(json.dumps(token_data),
                                          config.CONF.signing.certfile,
                                          config.CONF.signing.keyfile)
        else:
            raise exception.UnexpectedError(
                "Invalid value for token_format: %s."
                "  Allowed values are PKI or UUID." %
                config.CONF.signing.token_format)
        try:
            self.token_api.create_token(
                context, token_id, dict(key=token_id,
                                        id=token_id,
                                        user=user_ref,
                                        tenant=tenant_ref,
                                        metadata=metadata_ref))
        except Exception as e:
            # an identical token may have been created already.
            # if so, return the token_data as it is also identical
            try:
                self.token_api.get_token(context=context,
                                         token_id=token_id)
            except exception.TokenNotFound:
                raise e

        token_data['access']['token']['id'] = token_id

        return token_data
Ejemplo n.º 11
0
    def authenticate(self, context, auth=None):
        """Authenticate credentials and return a token.

        Accept auth as a dict that looks like::

            {
                "auth":{
                    "passwordCredentials":{
                        "username":"******",
                        "password":"******"
                    },
                    "tenantName":"customer-x"
                }
            }

        In this case, tenant is optional, if not provided the token will be
        considered "unscoped" and can later be used to get a scoped token.

        Alternatively, this call accepts auth with only a token and tenant
        that will return a token that is scoped to that tenant.
        """

        if 'passwordCredentials' in auth:
            user_id = auth['passwordCredentials'].get('userId', None)
            username = auth['passwordCredentials'].get('username', '')
            password = auth['passwordCredentials'].get('password', '')
            tenant_name = auth.get('tenantName', None)

            if username:
                try:
                    user_ref = self.identity_api.get_user_by_name(
                        context=context, user_name=username)
                    user_id = user_ref['id']
                except exception.UserNotFound:
                    raise exception.Unauthorized()

            # more compat
            tenant_id = auth.get('tenantId', None)
            if tenant_name:
                try:
                    tenant_ref = self.identity_api.get_tenant_by_name(
                        context=context, tenant_name=tenant_name)
                    tenant_id = tenant_ref['id']
                except exception.TenantNotFound:
                    raise exception.Unauthorized()

            try:
                auth_info = self.identity_api.authenticate(context=context,
                                                           user_id=user_id,
                                                           password=password,
                                                           tenant_id=tenant_id)
                (user_ref, tenant_ref, metadata_ref) = auth_info

                # If the user is disabled don't allow them to authenticate
                if not user_ref.get('enabled', True):
                    LOG.warning('User %s is disabled' % user_id)
                    raise exception.Unauthorized()

                # If the tenant is disabled don't allow them to authenticate
                if tenant_ref and not tenant_ref.get('enabled', True):
                    LOG.warning('Tenant %s is disabled' % tenant_id)
                    raise exception.Unauthorized()
            except AssertionError as e:
                raise exception.Unauthorized(e.message)
            auth_token_data = dict(
                zip(['user', 'tenant', 'metadata'], auth_info))
            expiry = self.token_api._get_default_expire_time(context=context)

            if tenant_ref:
                catalog_ref = self.catalog_api.get_catalog(
                    context=context,
                    user_id=user_ref['id'],
                    tenant_id=tenant_ref['id'],
                    metadata=metadata_ref)
            else:
                catalog_ref = {}
        elif 'token' in auth:
            old_token = auth['token'].get('id', None)
            tenant_name = auth.get('tenantName')

            try:
                old_token_ref = self.token_api.get_token(context=context,
                                                         token_id=old_token)
            except exception.NotFound:
                LOG.warning("Token not found: " + str(old_token))
                raise exception.Unauthorized()

            user_ref = old_token_ref['user']
            user_id = user_ref['id']

            current_user_ref = self.identity_api.get_user(context=context,
                                                          user_id=user_id)

            # If the user is disabled don't allow them to authenticate
            if not current_user_ref.get('enabled', True):
                LOG.warning('User %s is disabled' % user_id)
                raise exception.Unauthorized()

            if tenant_name:
                tenant_ref = self.identity_api.get_tenant_by_name(
                    context=context, tenant_name=tenant_name)
                tenant_id = tenant_ref['id']
            else:
                tenant_id = auth.get('tenantId', None)
            tenants = self.identity_api.get_tenants_for_user(context, user_id)

            if tenant_id:
                if not tenant_id in tenants:
                    LOG.warning('User %s is authorized for tenant %s' %
                                (user_id, tenant_id))
                    raise exception.Unauthorized()

            expiry = old_token_ref['expires']
            try:
                tenant_ref = self.identity_api.get_tenant(context=context,
                                                          tenant_id=tenant_id)
            except exception.TenantNotFound:
                tenant_ref = None
                metadata_ref = {}
                catalog_ref = {}
            except exception.MetadataNotFound:
                metadata_ref = {}
                catalog_ref = {}

            # If the tenant is disabled don't allow them to authenticate
            if tenant_ref and not tenant_ref.get('enabled', True):
                LOG.warning('Tenant %s is disabled' % tenant_id)
                raise exception.Unauthorized()

            if tenant_ref:
                metadata_ref = self.identity_api.get_metadata(
                    context=context,
                    user_id=user_ref['id'],
                    tenant_id=tenant_ref['id'])
                catalog_ref = self.catalog_api.get_catalog(
                    context=context,
                    user_id=user_ref['id'],
                    tenant_id=tenant_ref['id'],
                    metadata=metadata_ref)

            auth_token_data = dict(
                dict(user=current_user_ref,
                     tenant=tenant_ref,
                     metadata=metadata_ref))

        auth_token_data['expires'] = expiry
        auth_token_data['id'] = 'placeholder'

        roles_ref = []
        for role_id in metadata_ref.get('roles', []):
            role_ref = self.identity_api.get_role(context, role_id)
            roles_ref.append(dict(name=role_ref['name']))

        token_data = self._format_token(auth_token_data, roles_ref)

        service_catalog = self._format_catalog(catalog_ref)
        token_data['access']['serviceCatalog'] = service_catalog

        if config.CONF.signing.token_format == 'UUID':
            token_id = uuid.uuid4().hex
        elif config.CONF.signing.token_format == 'PKI':

            token_id = cms.cms_sign_token(json.dumps(token_data),
                                          config.CONF.signing.certfile,
                                          config.CONF.signing.keyfile)
        else:
            raise exception.UnexpectedError(
                'Invalid value for token_format: %s.'
                '  Allowed values are PKI or UUID.' %
                config.CONF.signing.token_format)
        try:
            self.token_api.create_token(
                context, token_id,
                dict(key=token_id,
                     id=token_id,
                     user=user_ref,
                     tenant=tenant_ref,
                     metadata=metadata_ref))
        except Exception as e:
            # an identical token may have been created already.
            # if so, return the token_data as it is also identical
            try:
                self.token_api.get_token(context=context, token_id=token_id)
            except exception.TokenNotFound:
                raise e

        token_data['access']['token']['id'] = token_id

        return token_data
Ejemplo n.º 12
0
    def authenticate(self, context, auth=None):
        """Authenticate credentials and return a token.

        Accept auth as a dict that looks like::

            {
                "auth":{
                    "passwordCredentials":{
                        "username":"******",
                        "password":"******"
                    },
                    "tenantName":"customer-x"
                }
            }

        In this case, tenant is optional, if not provided the token will be
        considered "unscoped" and can later be used to get a scoped token.

        Alternatively, this call accepts auth with only a token and tenant
        that will return a token that is scoped to that tenant.
        """
        if not auth:
            raise exception.ValidationError(attribute='auth',
                                            target='request body')

        if auth is None:
            auth = {}
        remote_auth = False
        if 'REMOTE_USER' in context and not 'token' in auth:
            # authenticated external request
            remote_auth = True

            if 'passwordCredentials' not in auth:
                auth['passwordCredentials'] = {}
            auth['passwordCredentials']['username'] = context.get(
                'REMOTE_USER', None)

        if 'passwordCredentials' in auth:
            user_id = auth['passwordCredentials'].get('userId', None)
            username = auth['passwordCredentials'].get('username', '')
            password = auth['passwordCredentials'].get('password', '')
            tenant_name = auth.get('tenantName', None)

            if not user_id and not username:
                raise exception.ValidationError(
                    attribute='username or userId',
                    target='passwordCredentials')

            tenant_ref = None
            user_ref = None
            metadata_ref = {}

            if username:
                try:
                    user_ref = self.identity_api.get_user_by_name(
                        context=context, user_name=username)
                    user_id = user_ref['id']
                except exception.UserNotFound:
                    raise exception.Unauthorized()

            if not password and not remote_auth:
                raise exception.ValidationError(
                    attribute='password',
                    target='passwordCredentials')

            # more compat
            tenant_id = auth.get('tenantId', None)
            if tenant_name:
                try:
                    tenant_ref = self.identity_api.get_tenant_by_name(
                        context=context, tenant_name=tenant_name)
                    tenant_id = tenant_ref['id']
                except exception.TenantNotFound:
                    raise exception.Unauthorized()

            try:
                if not remote_auth:
                    # local identity authentication required
                    auth_info = self.identity_api.authenticate(
                        context=context,
                        user_id=user_id,
                        password=password,
                        tenant_id=tenant_id)
                    (user_ref, tenant_ref, metadata_ref) = auth_info
                else:
                    # remote authentication already performed
                    if not user_ref:
                        user_ref = self.identity_api.get_user(
                            self.identity_api,
                            user_id)
                    if tenant_id:
                        if not tenant_ref:
                            tenant_ref = self.identity_api.get_tenant(
                                self.identity_api,
                                tenant_id)
                        metadata_ref = self.identity_api.get_metadata(
                            self.identity_api,
                            user_id,
                            tenant_id)
                    auth_info = (user_ref, tenant_ref, metadata_ref)

                # If the user is disabled don't allow them to authenticate
                if not user_ref.get('enabled', True):
                    LOG.warning('User %s is disabled' % user_id)
                    raise exception.Unauthorized()

                # If the tenant is disabled don't allow them to authenticate
                if tenant_ref and not tenant_ref.get('enabled', True):
                    LOG.warning('Tenant %s is disabled' % tenant_id)
                    raise exception.Unauthorized()
            except AssertionError as e:
                raise exception.Unauthorized(str(e))
            auth_token_data = dict(zip(['user', 'tenant', 'metadata'],
                                       auth_info))
            expiry = self.token_api._get_default_expire_time(context=context)

            if tenant_ref:
                catalog_ref = self.catalog_api.get_catalog(
                    context=context,
                    user_id=user_ref['id'],
                    tenant_id=tenant_ref['id'],
                    metadata=metadata_ref)
            else:
                catalog_ref = {}
        elif 'token' in auth:
            old_token = auth['token'].get('id', None)
            tenant_name = auth.get('tenantName')

            try:
                old_token_ref = self.token_api.get_token(context=context,
                                                         token_id=old_token)
            except exception.NotFound:
                LOG.warning("Token not found: " + str(old_token))
                raise exception.Unauthorized()

            user_ref = old_token_ref['user']
            user_id = user_ref['id']

            current_user_ref = self.identity_api.get_user(context=context,
                                                          user_id=user_id)

            # If the user is disabled don't allow them to authenticate
            if not current_user_ref.get('enabled', True):
                LOG.warning('User %s is disabled' % user_id)
                raise exception.Unauthorized()

            if tenant_name:
                tenant_ref = self.identity_api.get_tenant_by_name(
                    context=context,
                    tenant_name=tenant_name)
                tenant_id = tenant_ref['id']
            else:
                tenant_id = auth.get('tenantId', None)
            tenants = self.identity_api.get_tenants_for_user(context, user_id)

            if tenant_id:
                if not tenant_id in tenants:
                    LOG.warning('User %s is unauthorized for tenant %s'
                                % (user_id, tenant_id))
                    raise exception.Unauthorized()

            expiry = old_token_ref['expires']
            try:
                tenant_ref = self.identity_api.get_tenant(context=context,
                                                          tenant_id=tenant_id)
            except exception.TenantNotFound:
                tenant_ref = None
                metadata_ref = {}
                catalog_ref = {}
            except exception.MetadataNotFound:
                metadata_ref = {}
                catalog_ref = {}

            # If the tenant is disabled don't allow them to authenticate
            if tenant_ref and not tenant_ref.get('enabled', True):
                LOG.warning('Tenant %s is disabled' % tenant_id)
                raise exception.Unauthorized()

            if tenant_ref:
                metadata_ref = self.identity_api.get_metadata(
                    context=context,
                    user_id=user_ref['id'],
                    tenant_id=tenant_ref['id'])
                catalog_ref = self.catalog_api.get_catalog(
                    context=context,
                    user_id=user_ref['id'],
                    tenant_id=tenant_ref['id'],
                    metadata=metadata_ref)

            auth_token_data = dict(dict(user=current_user_ref,
                                        tenant=tenant_ref,
                                        metadata=metadata_ref))
        else:
            raise exception.ValidationError(
                attribute='passwordCredentials or token', target='auth')

        auth_token_data['expires'] = expiry
        auth_token_data['id'] = 'placeholder'

        roles_ref = []
        for role_id in metadata_ref.get('roles', []):
            role_ref = self.identity_api.get_role(context, role_id)
            roles_ref.append(dict(name=role_ref['name']))

        token_data = self._format_token(auth_token_data, roles_ref)

        service_catalog = self._format_catalog(catalog_ref)
        token_data['access']['serviceCatalog'] = service_catalog

        if config.CONF.signing.token_format == 'UUID':
            token_id = uuid.uuid4().hex
        elif config.CONF.signing.token_format == 'PKI':

            token_id = cms.cms_sign_token(json.dumps(token_data),
                                          config.CONF.signing.certfile,
                                          config.CONF.signing.keyfile)
        else:
            raise exception.UnexpectedError(
                'Invalid value for token_format: %s.'
                '  Allowed values are PKI or UUID.' %
                config.CONF.signing.token_format)
        try:
            self.token_api.create_token(
                context, token_id, dict(key=token_id,
                                        id=token_id,
                                        user=user_ref,
                                        tenant=tenant_ref,
                                        metadata=metadata_ref))
        except Exception as e:
            # an identical token may have been created already.
            # if so, return the token_data as it is also identical
            try:
                self.token_api.get_token(context=context,
                                         token_id=token_id)
            except exception.TokenNotFound:
                raise e

        token_data['access']['token']['id'] = token_id

        return token_data
Ejemplo n.º 13
0
    def authenticate(self, context, auth=None):
        """Authenticate credentials and return a token.

        Accept auth as a dict that looks like::

            {
                "auth":{
                    "passwordCredentials":{
                        "username":"******",
                        "password":"******"
                    },
                    "tenantName":"customer-x"
                }
            }

        In this case, tenant is optional, if not provided the token will be
        considered "unscoped" and can later be used to get a scoped token.

        Alternatively, this call accepts auth with only a token and tenant
        that will return a token that is scoped to that tenant.
        """

        if "passwordCredentials" in auth:
            user_id = auth["passwordCredentials"].get("userId", None)
            username = auth["passwordCredentials"].get("username", "")
            password = auth["passwordCredentials"].get("password", "")
            tenant_name = auth.get("tenantName", None)

            if username:
                try:
                    user_ref = self.identity_api.get_user_by_name(context=context, user_name=username)
                    user_id = user_ref["id"]
                except exception.UserNotFound:
                    raise exception.Unauthorized()

            # more compat
            tenant_id = auth.get("tenantId", None)
            if tenant_name:
                try:
                    tenant_ref = self.identity_api.get_tenant_by_name(context=context, tenant_name=tenant_name)
                    tenant_id = tenant_ref["id"]
                except exception.TenantNotFound:
                    raise exception.Unauthorized()

            try:
                auth_info = self.identity_api.authenticate(
                    context=context, user_id=user_id, password=password, tenant_id=tenant_id
                )
                (user_ref, tenant_ref, metadata_ref) = auth_info

                # If the user is disabled don't allow them to authenticate
                if not user_ref.get("enabled", True):
                    LOG.warning("User %s is disabled" % user_id)
                    raise exception.Unauthorized()

                # If the tenant is disabled don't allow them to authenticate
                if tenant_ref and not tenant_ref.get("enabled", True):
                    LOG.warning("Tenant %s is disabled" % tenant_id)
                    raise exception.Unauthorized()
            except AssertionError as e:
                raise exception.Unauthorized(e.message)
            auth_token_data = dict(zip(["user", "tenant", "metadata"], auth_info))
            expiry = self.token_api._get_default_expire_time(context=context)

            if tenant_ref:
                catalog_ref = self.catalog_api.get_catalog(
                    context=context, user_id=user_ref["id"], tenant_id=tenant_ref["id"], metadata=metadata_ref
                )
            else:
                catalog_ref = {}
        elif "token" in auth:
            old_token = auth["token"].get("id", None)
            tenant_name = auth.get("tenantName")

            try:
                old_token_ref = self.token_api.get_token(context=context, token_id=old_token)
            except exception.NotFound:
                LOG.warning("Token not found: " + str(old_token))
                raise exception.Unauthorized()

            user_ref = old_token_ref["user"]
            user_id = user_ref["id"]

            current_user_ref = self.identity_api.get_user(context=context, user_id=user_id)

            # If the user is disabled don't allow them to authenticate
            if not current_user_ref.get("enabled", True):
                LOG.warning("User %s is disabled" % user_id)
                raise exception.Unauthorized()

            if tenant_name:
                tenant_ref = self.identity_api.get_tenant_by_name(context=context, tenant_name=tenant_name)
                tenant_id = tenant_ref["id"]
            else:
                tenant_id = auth.get("tenantId", None)
            tenants = self.identity_api.get_tenants_for_user(context, user_id)

            if tenant_id:
                if not tenant_id in tenants:
                    LOG.warning("User %s is authorized for tenant %s" % (user_id, tenant_id))
                    raise exception.Unauthorized()

            expiry = old_token_ref["expires"]
            try:
                tenant_ref = self.identity_api.get_tenant(context=context, tenant_id=tenant_id)
            except exception.TenantNotFound:
                tenant_ref = None
                metadata_ref = {}
                catalog_ref = {}
            except exception.MetadataNotFound:
                metadata_ref = {}
                catalog_ref = {}

            # If the tenant is disabled don't allow them to authenticate
            if tenant_ref and not tenant_ref.get("enabled", True):
                LOG.warning("Tenant %s is disabled" % tenant_id)
                raise exception.Unauthorized()

            if tenant_ref:
                metadata_ref = self.identity_api.get_metadata(
                    context=context, user_id=user_ref["id"], tenant_id=tenant_ref["id"]
                )
                catalog_ref = self.catalog_api.get_catalog(
                    context=context, user_id=user_ref["id"], tenant_id=tenant_ref["id"], metadata=metadata_ref
                )

            auth_token_data = dict(dict(user=current_user_ref, tenant=tenant_ref, metadata=metadata_ref))

        auth_token_data["expires"] = expiry
        auth_token_data["id"] = "placeholder"

        roles_ref = []
        for role_id in metadata_ref.get("roles", []):
            role_ref = self.identity_api.get_role(context, role_id)
            roles_ref.append(dict(name=role_ref["name"]))

        token_data = self._format_token(auth_token_data, roles_ref)

        service_catalog = self._format_catalog(catalog_ref)
        token_data["access"]["serviceCatalog"] = service_catalog

        if config.CONF.signing.token_format == "UUID":
            token_id = uuid.uuid4().hex
        elif config.CONF.signing.token_format == "PKI":

            token_id = cms.cms_sign_token(
                json.dumps(token_data), config.CONF.signing.certfile, config.CONF.signing.keyfile
            )
        else:
            raise exception.UnexpectedError(
                "Invalid value for token_format: %s."
                "  Allowed values are PKI or UUID." % config.CONF.signing.token_format
            )
        try:
            self.token_api.create_token(
                context,
                token_id,
                dict(key=token_id, id=token_id, user=user_ref, tenant=tenant_ref, metadata=metadata_ref),
            )
        except Exception as e:
            # an identical token may have been created already.
            # if so, return the token_data as it is also identical
            try:
                self.token_api.get_token(context=context, token_id=token_id)
            except exception.TokenNotFound:
                raise e

        token_data["access"]["token"]["id"] = token_id

        return token_data