Ejemplo n.º 1
0
def build_token_values(token_data):

    token_expires_at = timeutils.parse_isotime(token_data['expires_at'])

    # Trim off the microseconds because the revocation event only has
    # expirations accurate to the second.
    token_expires_at = token_expires_at.replace(microsecond=0)

    token_values = {
        'expires_at': timeutils.normalize_time(token_expires_at),
        'issued_at': timeutils.normalize_time(
            timeutils.parse_isotime(token_data['issued_at']))}

    user = token_data.get('user')
    if user is not None:
        token_values['user_id'] = user['id']
        token_values['identity_domain_id'] = user['domain']['id']
    else:
        token_values['user_id'] = None
        token_values['identity_domain_id'] = None

    project = token_data.get('project', token_data.get('tenant'))
    if project is not None:
        token_values['project_id'] = project['id']
        token_values['assignment_domain_id'] = project['domain']['id']
    else:
        token_values['project_id'] = None

        domain = token_data.get('domain')
        if domain is not None:
            token_values['assignment_domain_id'] = domain['id']
        else:
            token_values['assignment_domain_id'] = None

    role_list = []
    roles = token_data.get('roles')
    if roles is not None:
        for role in roles:
            role_list.append(role['id'])
    token_values['roles'] = role_list

    trust = token_data.get('OS-TRUST:trust')
    if trust is None:
        token_values['trust_id'] = None
        token_values['trustor_id'] = None
        token_values['trustee_id'] = None
    else:
        token_values['trust_id'] = trust['id']
        token_values['trustor_id'] = trust['trustor_user']['id']
        token_values['trustee_id'] = trust['trustee_user']['id']

    oauth1 = token_data.get('OS-OAUTH1')
    if oauth1 is None:
        token_values['consumer_id'] = None
        token_values['access_token_id'] = None
    else:
        token_values['consumer_id'] = oauth1['consumer_id']
        token_values['access_token_id'] = oauth1['access_token_id']
    return token_values
Ejemplo n.º 2
0
    def test_token_expiry_maintained(self):
        foo_client = self.get_client(self.user_foo)

        orig_token = foo_client.service_catalog.catalog["token"]
        time.sleep(0.5)
        reauthenticated_token = foo_client.tokens.authenticate(token=foo_client.auth_token)

        self.assertCloseEnoughForGovernmentWork(
            timeutils.parse_isotime(orig_token["expires"]), timeutils.parse_isotime(reauthenticated_token.expires)
        )
Ejemplo n.º 3
0
    def _add_to_revocation_list(self, data, lock):
        filtered_list = []
        revoked_token_data = {}

        current_time = self._get_current_time()
        expires = data['expires']

        if isinstance(expires, six.string_types):
            expires = timeutils.parse_isotime(expires)

        expires = timeutils.normalize_time(expires)

        if expires < current_time:
            LOG.warning(_('Token `%s` is expired, not adding to the '
                          'revocation list.'), data['id'])
            return

        revoked_token_data['expires'] = timeutils.isotime(expires,
                                                          subsecond=True)
        revoked_token_data['id'] = data['id']

        token_list = self._get_key_or_default(self.revocation_key, default=[])
        if not isinstance(token_list, list):
            # NOTE(morganfainberg): In the case that the revocation list is not
            # in a format we understand, reinitialize it. This is an attempt to
            # not allow the revocation list to be completely broken if
            # somehow the key is changed outside of keystone (e.g. memcache
            # that is shared by multiple applications). Logging occurs at error
            # level so that the cloud administrators have some awareness that
            # the revocation_list needed to be cleared out. In all, this should
            # be recoverable. Keystone cannot control external applications
            # from changing a key in some backends, however, it is possible to
            # gracefully handle and notify of this event.
            LOG.error(_('Reinitializing revocation list due to error '
                        'in loading revocation list from backend.  '
                        'Expected `list` type got `%(type)s`. Old '
                        'revocation list data: %(list)r'),
                      {'type': type(token_list), 'list': token_list})
            token_list = []

        # NOTE(morganfainberg): on revocation, cleanup the expired entries, try
        # to keep the list of tokens revoked at the minimum.
        for token_data in token_list:
            try:
                expires_at = timeutils.normalize_time(
                    timeutils.parse_isotime(token_data['expires']))
            except ValueError:
                LOG.warning(_('Removing `%s` from revocation list due to '
                              'invalid expires data in revocation list.'),
                            token_data.get('id', 'INVALID_TOKEN_DATA'))
                continue
            if expires_at > current_time:
                filtered_list.append(token_data)
        filtered_list.append(revoked_token_data)
        self._set_key(self.revocation_key, filtered_list, lock)
Ejemplo n.º 4
0
    def test_token_expiry_maintained(self):
        timeutils.set_time_override()
        foo_client = self.get_client(self.user_foo)

        orig_token = foo_client.service_catalog.catalog['token']
        timeutils.advance_time_seconds(1)
        reauthenticated_token = foo_client.tokens.authenticate(
            token=foo_client.auth_token)

        self.assertCloseEnoughForGovernmentWork(
            timeutils.parse_isotime(orig_token['expires']),
            timeutils.parse_isotime(reauthenticated_token.expires))
Ejemplo n.º 5
0
    def test_token_expiry_maintained(self, mock_utcnow):
        now = datetime.datetime.utcnow()
        mock_utcnow.return_value = now
        foo_client = self.get_client(self.user_foo)

        orig_token = foo_client.service_catalog.catalog['token']
        mock_utcnow.return_value = now + datetime.timedelta(seconds=1)
        reauthenticated_token = foo_client.tokens.authenticate(
            token=foo_client.auth_token)

        self.assertCloseEnoughForGovernmentWork(
            timeutils.parse_isotime(orig_token['expires']),
            timeutils.parse_isotime(reauthenticated_token.expires))
Ejemplo n.º 6
0
    def assertEqualTokens(self, a, b):
        def normalize(token):
            token['access']['token']['id'] = 'dummy'
            del token['access']['token']['expires']
            del token['access']['token']['issued_at']
            return token

        self.assertCloseEnoughForGovernmentWork(
            timeutils.parse_isotime(a['access']['token']['expires']),
            timeutils.parse_isotime(b['access']['token']['expires']))
        self.assertCloseEnoughForGovernmentWork(
            timeutils.parse_isotime(a['access']['token']['issued_at']),
            timeutils.parse_isotime(b['access']['token']['issued_at']))
        return self.assertDictEqual(normalize(a), normalize(b))
Ejemplo n.º 7
0
    def authenticate(self, context, auth_info, auth_context):
        """Turn a signed request with an access key into a keystone token."""

        if not self.oauth_api:
            raise exception.Unauthorized(_("%s not supported") % self.method)

        headers = context["headers"]
        oauth_headers = oauth.get_oauth_headers(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(context, context["path"])
        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=context["query_string"], headers=headers, realms=None
        )
        if not result:
            msg = _("Could not validate the access token")
            raise exception.Unauthorized(msg)
        auth_context["user_id"] = acc_token["authorizing_user_id"]
        auth_context["access_token_id"] = access_token_id
        auth_context["project_id"] = acc_token["project_id"]
Ejemplo n.º 8
0
    def issue_v2_token(self, token_ref, roles_ref=None,
                       catalog_ref=None):
        token_data = self.v2_token_data_helper.format_token(
            token_ref, roles_ref, catalog_ref)
        token_id = self._get_token_id(token_data)
        token_data['access']['token']['id'] = token_id
        try:
            expiry = token_data['access']['token']['expires']
            if isinstance(expiry, basestring):
                expiry = timeutils.normalize_time(
                    timeutils.parse_isotime(expiry))
            data = dict(key=token_id,
                        id=token_id,
                        expires=expiry,
                        user=token_ref['user'],
                        tenant=token_ref['tenant'],
                        metadata=token_ref['metadata'],
                        token_data=token_data,
                        bind=token_ref.get('bind'),
                        trust_id=token_ref['metadata'].get('trust_id'),
                        token_version=token.provider.V2)
            self.token_api.create_token(token_id, data)
        except Exception:
            exc_info = sys.exc_info()
            # 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(token_id)
            except exception.TokenNotFound:
                raise exc_info[0], exc_info[1], exc_info[2]

        return (token_id, token_data)
Ejemplo n.º 9
0
    def issue_v2_token(self, token_ref, roles_ref=None, catalog_ref=None):
        token_data = self.v2_token_data_helper.format_token(token_ref, roles_ref, catalog_ref)
        token_id = self._get_token_id(token_data)
        token_data["access"]["token"]["id"] = token_id
        try:
            expiry = token_data["access"]["token"]["expires"]
            if isinstance(expiry, six.string_types):
                expiry = timeutils.normalize_time(timeutils.parse_isotime(expiry))
            data = dict(
                key=token_id,
                id=token_id,
                expires=expiry,
                user=token_ref["user"],
                tenant=token_ref["tenant"],
                metadata=token_ref["metadata"],
                token_data=token_data,
                bind=token_ref.get("bind"),
                trust_id=token_ref["metadata"].get("trust_id"),
                token_version=token.provider.V2,
            )
            self.token_api.create_token(token_id, data)
        except Exception:
            exc_info = sys.exc_info()
            # 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(token_id)
            except exception.TokenNotFound:
                raise exc_info[0], exc_info[1], exc_info[2]

        return (token_id, token_data)
Ejemplo n.º 10
0
    def _request_admin_token(self):
        """Retrieve new token as admin user from keystone.

        :return token id upon success
        :raises ServerError when unable to communicate with keystone

        """
        params = {
            'auth': {
                'passwordCredentials': {
                    'username': self.admin_user,
                    'password': self.admin_password,
                },
                'tenantName': self.admin_tenant_name,
            }
        }

        response, data = self._json_request('POST',
                                            '/v2.0/tokens',
                                            body=params)

        try:
            token = data['access']['token']['id']
            expiry = data['access']['token']['expires']
            assert token
            assert expiry
            datetime_expiry = timeutils.parse_isotime(expiry)
            return (token, timeutils.normalize_time(datetime_expiry))
        except (AssertionError, KeyError):
            LOG.warn("Unexpected response from keystone service: %s", data)
            raise ServiceError('invalid json response')
        except (ValueError):
            LOG.warn("Unable to parse expiration time from token: %s", data)
            raise ServiceError('invalid json response')
Ejemplo n.º 11
0
    def _is_valid_token(self, token):
        """Verify the token is valid format and has not expired."""

        current_time = timeutils.normalize_time(timeutils.utcnow())

        try:
            # Get the data we need from the correct location (V2 and V3 tokens
            # differ in structure, Try V3 first, fall back to V2 second)
            token_data = token.get('token', token.get('access'))
            expires_at = token_data.get('expires_at',
                                        token_data.get('expires'))
            if not expires_at:
                expires_at = token_data['token']['expires']
            expiry = timeutils.normalize_time(
                timeutils.parse_isotime(expires_at))
        except Exception:
            LOG.exception(_('Unexpected error or malformed token determining '
                            'token expiry: %s'), token)
            raise exception.TokenNotFound(_('Failed to validate token'))

        if current_time < expiry:
            self.check_revocation(token)
            # Token has not expired and has not been revoked.
            return None
        else:
            raise exception.TokenNotFound(_('Failed to validate token'))
Ejemplo n.º 12
0
    def _is_valid_token(self, token):
         # Verify the token has not expired.
        current_time = timeutils.normalize_time(timeutils.utcnow())

        try:
            # Get the data we need from the correct location (V2 and V3 tokens
            # differ in structure, Try V3 first, fall back to V2 second)
            token_data = token.get('token', token.get('access'))
            expires_at = token_data.get('expires_at',
                                        token_data.get('expires'))
            if not expires_at:
                expires_at = token_data['token']['expires']
            expiry = timeutils.normalize_time(
                timeutils.parse_isotime(expires_at))
            if current_time < expiry:
                # Token is has not expired and has not been revoked.
                return None
        except Exception:
            LOG.exception(_('Unexpected error or malformed token determining '
                            'token expiry: %s') % token)

        # FIXME(morganfainberg): This error message needs to be updated to
        # reflect the token couldn't be found, but this change needs to wait
        # until Icehouse due to string freeze in Havana.  This should be:
        # "Failed to find valid token" or something similar.
        raise exception.TokenNotFound(_('Failed to validate token'))
Ejemplo n.º 13
0
def build_token_values(token_data):
    token_values = {
        "expires_at": timeutils.normalize_time(timeutils.parse_isotime(token_data["expires_at"])),
        "issued_at": timeutils.normalize_time(timeutils.parse_isotime(token_data["issued_at"])),
    }

    user = token_data.get("user")
    if user is not None:
        token_values["user_id"] = user["id"]
        token_values["identity_domain_id"] = user["domain"]["id"]
    else:
        token_values["user_id"] = None
        token_values["identity_domain_id"] = None

    project = token_data.get("project", token_data.get("tenant"))
    if project is not None:
        token_values["project_id"] = project["id"]
        token_values["assignment_domain_id"] = project["domain"]["id"]
    else:
        token_values["project_id"] = None
        token_values["assignment_domain_id"] = None

    role_list = []
    roles = token_data.get("roles")
    if roles is not None:
        for role in roles:
            role_list.append(role["id"])
    token_values["roles"] = role_list

    trust = token_data.get("OS-TRUST:trust")
    if trust is None:
        token_values["trust_id"] = None
        token_values["trustor_id"] = None
        token_values["trustee_id"] = None
    else:
        token_values["trust_id"] = trust["id"]
        token_values["trustor_id"] = trust["trustor_user"]["id"]
        token_values["trustee_id"] = trust["trustee_user"]["id"]

    oauth1 = token_data.get("OS-OAUTH1")
    if oauth1 is None:
        token_values["consumer_id"] = None
        token_values["access_token_id"] = None
    else:
        token_values["consumer_id"] = oauth1["consumer_id"]
        token_values["access_token_id"] = oauth1["access_token_id"]
    return token_values
Ejemplo n.º 14
0
    def create_trust(self, context, trust=None):
        """Create a new trust.

        The user creating the trust must be the trustor.

        """

        # TODO(ayoung): instead of raising ValidationError on the first
        # problem, return a collection of all the problems.

        # Explicitly prevent a trust token from creating a new trust.
        auth_context = context.get('environment',
                                   {}).get('KEYSTONE_AUTH_CONTEXT', {})
        if auth_context.get('is_delegated_auth'):
            raise exception.Forbidden(
                _('Cannot create a trust'
                  ' with a token issued via delegation.'))

        if not trust:
            raise exception.ValidationError(attribute='trust',
                                            target='request')
        if trust.get('project_id') and not trust.get('roles'):
            raise exception.Forbidden(
                _('At least one role should be specified.'))
        try:
            user_id = self._get_user_id(context)
            _trustor_only(context, trust, user_id)
            #confirm that the trustee exists
            self.identity_api.get_user(trust['trustee_user_id'])
            all_roles = self.assignment_api.list_roles()
            clean_roles = self._clean_role_list(context, trust, all_roles)
            if trust.get('project_id'):
                user_role = self.assignment_api.get_roles_for_user_and_project(
                    user_id,
                    trust['project_id'])
            else:
                user_role = []
            for trust_role in clean_roles:
                matching_roles = [x for x in user_role
                                  if x == trust_role['id']]
                if not matching_roles:
                    raise exception.RoleNotFound(role_id=trust_role['id'])
            if trust.get('expires_at') is not None:
                if not trust['expires_at'].endswith('Z'):
                    trust['expires_at'] += 'Z'
                try:
                    trust['expires_at'] = (timeutils.parse_isotime
                                           (trust['expires_at']))
                except ValueError:
                    raise exception.ValidationTimeStampError()
            trust_id = uuid.uuid4().hex
            new_trust = self.trust_api.create_trust(trust_id,
                                                    trust,
                                                    clean_roles)
            self._fill_in_roles(context, new_trust, all_roles)
            return TrustV3.wrap_member(context, new_trust)
        except KeyError as e:
            raise exception.ValidationError(attribute=e.args[0],
                                            target='trust')
Ejemplo n.º 15
0
    def _issue_v3_token(self, **kwargs):
        user_id = kwargs.get('user_id')
        method_names = kwargs.get('method_names')
        expires_at = kwargs.get('expires_at')
        project_id = kwargs.get('project_id')
        domain_id = kwargs.get('domain_id')
        auth_context = kwargs.get('auth_context')
        trust = kwargs.get('trust')
        metadata_ref = kwargs.get('metadata_ref')
        # for V2, trust is stashed in metadata_ref
        if (CONF.trust.enabled and not trust and metadata_ref and
                'trust_id' in metadata_ref):
            trust = self.trust_api.get_trust(metadata_ref['trust_id'])
        token_data = self.v3_token_data_helper.get_token_data(
            user_id,
            method_names,
            auth_context.get('extras') if auth_context else None,
            domain_id=domain_id,
            project_id=project_id,
            expires=expires_at,
            trust=trust)

        token_id = self._get_token_id(token_data)
        try:
            expiry = token_data['token']['expires_at']
            if isinstance(expiry, basestring):
                expiry = timeutils.normalize_time(
                    timeutils.parse_isotime(expiry))
            # FIXME(gyee): is there really a need to store roles in metadata?
            role_ids = []
            metadata_ref = kwargs.get('metadata_ref', {})
            if 'project' in token_data['token']:
                # project-scoped token, fill in the v2 token data
                # all we care are the role IDs
                role_ids = [r['id'] for r in token_data['token']['roles']]
                metadata_ref = {'roles': role_ids}
            if trust:
                metadata_ref.setdefault('trust_id', trust['id'])
                metadata_ref.setdefault('trustee_user_id',
                                        trust['trustee_user_id'])
            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)
            self.token_api.create_token(token_id, data)
        except Exception:
            exc_info = sys.exc_info()
            # 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(token_id)
            except exception.TokenNotFound:
                raise exc_info[0], exc_info[1], exc_info[2]

        return (token_id, token_data)
Ejemplo n.º 16
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.º 17
0
def build_token_values_v2(access, default_domain_id):
    token_data = access['token']

    token_expires_at = timeutils.parse_isotime(token_data['expires'])

    # Trim off the microseconds because the revocation event only has
    # expirations accurate to the second.
    token_expires_at = token_expires_at.replace(microsecond=0)

    token_values = {
        'expires_at': timeutils.normalize_time(token_expires_at),
        'issued_at': timeutils.normalize_time(
            timeutils.parse_isotime(token_data['issued_at']))}

    token_values['user_id'] = access.get('user', {}).get('id')

    project = token_data.get('tenant')
    if project is not None:
        token_values['project_id'] = project['id']
    else:
        token_values['project_id'] = None

    token_values['identity_domain_id'] = default_domain_id
    token_values['assignment_domain_id'] = default_domain_id

    trust = token_data.get('trust')
    if trust is None:
        token_values['trust_id'] = None
        token_values['trustor_id'] = None
        token_values['trustee_id'] = None
    else:
        token_values['trust_id'] = trust['id']
        token_values['trustor_id'] = trust['trustor_id']
        token_values['trustee_id'] = trust['trustee_id']

    token_values['consumer_id'] = None
    token_values['access_token_id'] = None

    role_list = []
    # Roles are by ID in metadata and by name in the user section
    roles = access.get('metadata', {}).get('roles', [])
    for role in roles:
        role_list.append(role)
    token_values['roles'] = role_list
    return token_values
Ejemplo n.º 18
0
    def assertEqualTokens(self, a, b):
        """Assert that two tokens are equal.

        Compare two tokens except for their ids. This also truncates
        the time in the comparison.
        """
        def normalize(token):
            del token['expires']
            del token['issued_at']
            return token

        self.assertCloseEnoughForGovernmentWork(
            timeutils.parse_isotime(a['expires']),
            timeutils.parse_isotime(b['expires']))
        self.assertCloseEnoughForGovernmentWork(
            timeutils.parse_isotime(a['issued_at']),
            timeutils.parse_isotime(b['issued_at']))
        return self.assertDictEqual(normalize(a), normalize(b))
Ejemplo n.º 19
0
    def authorize_request_token(self, context, request_token_id, roles):
        """An authenticated user is going to authorize a request token.

        As a security precaution, the requested roles must match those in
        the request token. Because this is in a CLI-only world at the moment,
        there is not another easy way to make sure the user knows which roles
        are being requested before authorizing.
        """

        req_token = self.oauth_api.get_request_token(request_token_id)

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

        # put the roles in a set for easy comparison
        authed_roles = set()
        for role in roles:
            authed_roles.add(role['id'])

        # verify the authorizing user has the roles
        user_token = self.token_api.get_token(context['token_id'])
        user_id = user_token['user'].get('id')
        project_id = req_token['requested_project_id']
        user_roles = self.assignment_api.get_roles_for_user_and_project(
            user_id, project_id)
        cred_set = set(user_roles)

        if not cred_set.issuperset(authed_roles):
            msg = _('authorizing user does not have role required')
            raise exception.Unauthorized(message=msg)

        # create list of just the id's for the backend
        role_list = list(authed_roles)

        # verify the user has the project too
        req_project_id = req_token['requested_project_id']
        user_projects = self.assignment_api.list_projects_for_user(user_id)
        found = False
        for user_project in user_projects:
            if user_project['id'] == req_project_id:
                found = True
                break
        if not found:
            msg = _("User is not a member of the requested project")
            raise exception.Unauthorized(message=msg)

        # finally authorize the token
        authed_token = self.oauth_api.authorize_request_token(
            request_token_id, user_id, role_list)

        to_return = {'token': {'oauth_verifier': authed_token['verifier']}}
        return to_return
Ejemplo n.º 20
0
 def _parse_expiration_date(self, expiration_date):
     if expiration_date is None:
         return None
     if not expiration_date.endswith('Z'):
         expiration_date += 'Z'
     try:
         return timeutils.parse_isotime(expiration_date)
     except ValueError:
         raise exception.ValidationTimeStampError()
Ejemplo n.º 21
0
 def assertReporteEventMatchesRecorded(self, event, sample, before_time):
     after_time = timeutils.utcnow()
     event_issued_before = timeutils.normalize_time(
         timeutils.parse_isotime(event['issued_before']))
     self.assertTrue(before_time < event_issued_before,
                     'invalid event issued_before time; Too early')
     self.assertTrue(event_issued_before < after_time,
                     'invalid event issued_before time; too late')
     del (event['issued_before'])
     self.assertEqual(sample, event)
Ejemplo n.º 22
0
    def authorize(self, context, request_token_id):
        """An authenticated user is going to authorize a request token.

        As a security precaution, the requested roles must match those in
        the request token. Because this is in a CLI-only world at the moment,
        there is not another easy way to make sure the user knows which roles
        are being requested before authorizing.
        """

        req_token = self.oauth_api.get_request_token(request_token_id)

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

        req_roles = req_token['requested_roles']
        req_roles_list = jsonutils.loads(req_roles)

        req_set = set()
        for x in req_roles_list:
            req_set.add(x['id'])

        # verify the authorizing user has the roles
        user_token = self.token_api.get_token(context['token_id'])
        credentials = user_token['metadata'].copy()
        user_roles = credentials.get('roles')
        user_id = user_token['user'].get('id')
        cred_set = set(user_roles)

        if not cred_set.issuperset(req_set):
            msg = _('authorizing user does not have role required')
            raise exception.Unauthorized(message=msg)

        # verify the user has the project too
        req_project_id = req_token['requested_project_id']
        user_projects = self.assignment_api.list_user_projects(user_id)
        found = False
        for user_project in user_projects:
            if user_project['id'] == req_project_id:
                found = True
                break
        if not found:
            msg = _("User is not a member of the requested project")
            raise exception.Unauthorized(message=msg)

        # finally authorize the token
        authed_token = self.oauth_api.authorize_request_token(
            request_token_id, user_id)

        to_return = {'token': {'oauth_verifier': authed_token['verifier']}}
        return to_return
Ejemplo n.º 23
0
    def authorize_request_token(self, context, request_token_id, roles):
        """An authenticated user is going to authorize a request token.

        As a security precaution, the requested roles must match those in
        the request token. Because this is in a CLI-only world at the moment,
        there is not another easy way to make sure the user knows which roles
        are being requested before authorizing.
        """
        auth_context = context.get("environment", {}).get("KEYSTONE_AUTH_CONTEXT", {})
        if auth_context.get("is_delegated_auth"):
            raise exception.Forbidden(_("Cannot authorize a request token" " with a token issued via delegation."))

        req_token = self.oauth_api.get_request_token(request_token_id)

        expires_at = req_token["expires_at"]
        if expires_at:
            now = timeutils.utcnow()
            expires = timeutils.normalize_time(timeutils.parse_isotime(expires_at))
            if now > expires:
                raise exception.Unauthorized(_("Request token is expired"))

        # put the roles in a set for easy comparison
        authed_roles = set()
        for role in roles:
            authed_roles.add(role["id"])

        # verify the authorizing user has the roles
        user_token = self.token_api.get_token(context["token_id"])
        user_id = user_token["user"].get("id")
        project_id = req_token["requested_project_id"]
        user_roles = self.assignment_api.get_roles_for_user_and_project(user_id, project_id)
        cred_set = set(user_roles)

        if not cred_set.issuperset(authed_roles):
            msg = _("authorizing user does not have role required")
            raise exception.Unauthorized(message=msg)

        # create list of just the id's for the backend
        role_list = list(authed_roles)

        # verify the user has the project too
        req_project_id = req_token["requested_project_id"]
        user_projects = self.assignment_api.list_projects_for_user(user_id)
        for user_project in user_projects:
            if user_project["id"] == req_project_id:
                break
        else:
            msg = _("User is not a member of the requested project")
            raise exception.Unauthorized(message=msg)

        # finally authorize the token
        authed_token = self.oauth_api.authorize_request_token(request_token_id, user_id, role_list)

        to_return = {"token": {"oauth_verifier": authed_token["verifier"]}}
        return to_return
Ejemplo n.º 24
0
    def assertEqualTokens(self, a, b):
        """Assert that two tokens are equal.

        Compare two tokens except for their ids. This also truncates
        the time in the comparison.
        """

        def normalize(token):
            token["access"]["token"]["id"] = "dummy"
            del token["access"]["token"]["expires"]
            del token["access"]["token"]["issued_at"]
            return token

        self.assertCloseEnoughForGovernmentWork(
            timeutils.parse_isotime(a["access"]["token"]["expires"]),
            timeutils.parse_isotime(b["access"]["token"]["expires"]),
        )
        self.assertCloseEnoughForGovernmentWork(
            timeutils.parse_isotime(a["access"]["token"]["issued_at"]),
            timeutils.parse_isotime(b["access"]["token"]["issued_at"]),
        )
        return self.assertDictEqual(normalize(a), normalize(b))
Ejemplo n.º 25
0
def build_token_values_v2(access, default_domain_id):
    token_data = access["token"]
    token_values = {
        "expires_at": timeutils.normalize_time(timeutils.parse_isotime(token_data["expires"])),
        "issued_at": timeutils.normalize_time(timeutils.parse_isotime(token_data["issued_at"])),
    }

    token_values["user_id"] = access.get("user", {}).get("id")

    project = token_data.get("tenant")
    if project is not None:
        token_values["project_id"] = project["id"]
    else:
        token_values["project_id"] = None

    token_values["identity_domain_id"] = default_domain_id
    token_values["assignment_domain_id"] = default_domain_id

    trust = token_data.get("trust")
    if trust is None:
        token_values["trust_id"] = None
        token_values["trustor_id"] = None
        token_values["trustee_id"] = None
    else:
        token_values["trust_id"] = trust["id"]
        token_values["trustor_id"] = trust["trustor_id"]
        token_values["trustee_id"] = trust["trustee_id"]

    token_values["consumer_id"] = None
    token_values["access_token_id"] = None

    role_list = []
    # Roles are by ID in metadata and by name in the user section
    roles = access.get("metadata", {}).get("roles", [])
    for role in roles:
        role_list.append(role)
    token_values["roles"] = role_list
    return token_values
 def create_user(self, context, user):
     ref = self._assign_unique_id(self._normalize_dict(user))
     user_id = user.get('id', None)
     if user_id is not None:
         ref['id'] = user_id
     expires = user.get('expires', None)
     if expires is not None:
         try:
             ref['expires'] = timeutils.parse_strtime(expires)
         except ValueError:
             ref['expires'] = timeutils.parse_isotime(expires)
     ref = self._normalize_domain_id(context, ref)
     ref = self.identity_api.create_user(context, ref['id'], ref)
     return UserV3.wrap_member(context, ref)
Ejemplo n.º 27
0
 def _create_token(self, token_id, token_data):
     try:
         if isinstance(token_data['expires'], six.string_types):
             token_data['expires'] = timeutils.normalize_time(
                 timeutils.parse_isotime(token_data['expires']))
         self.token_api.create_token(token_id, token_data)
     except Exception:
         exc_info = sys.exc_info()
         # 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(token_id)
         except exception.TokenNotFound:
             six.reraise(*exc_info)
Ejemplo n.º 28
0
    def create_trust(self, context, trust=None):
        """Create a new trust.

        The user creating the trust must be the trustor.

        """

        # TODO(ayoung): instead of raising ValidationError on the first
        # problem, return a collection of all the problems.
        if not trust:
            raise exception.ValidationError(attribute='trust',
                                            target='request')
        try:
            user_id = self._get_user_id(context)
            _trustor_only(context, trust, user_id)
            #confirm that the trustee exists
            trustee_ref = self.identity_api.get_user(trust['trustee_user_id'])
            if not trustee_ref:
                raise exception.UserNotFound(user_id=trust['trustee_user_id'])
            all_roles = self.assignment_api.list_roles()
            clean_roles = self._clean_role_list(context, trust, all_roles)
            if trust.get('project_id'):
                user_role = self.assignment_api.get_roles_for_user_and_project(
                    user_id,
                    trust['project_id'])
            else:
                user_role = []
            for trust_role in clean_roles:
                matching_roles = [x for x in user_role
                                  if x == trust_role['id']]
                if not matching_roles:
                    raise exception.RoleNotFound(role_id=trust_role['id'])
            if trust.get('expires_at') is not None:
                if not trust['expires_at'].endswith('Z'):
                    trust['expires_at'] += 'Z'
                try:
                    trust['expires_at'] = (timeutils.parse_isotime
                                           (trust['expires_at']))
                except ValueError:
                    raise exception.ValidationTimeStampError()
            trust_id = uuid.uuid4().hex
            new_trust = self.trust_api.create_trust(trust_id,
                                                    trust,
                                                    clean_roles)
            self._fill_in_roles(context, new_trust, all_roles)
            return TrustV3.wrap_member(context, new_trust)
        except KeyError as e:
            raise exception.ValidationError(attribute=e.args[0],
                                            target='trust')
Ejemplo n.º 29
0
 def assertReportedEventMatchesRecorded(self, event, sample, before_time):
     after_time = timeutils.utcnow()
     event_issued_before = timeutils.normalize_time(
         timeutils.parse_isotime(event['issued_before']))
     self.assertTrue(
         before_time <= event_issued_before,
         'invalid event issued_before time; %s is not later than %s.' % (
             timeutils.isotime(event_issued_before, subsecond=True),
             timeutils.isotime(before_time, subsecond=True)))
     self.assertTrue(
         event_issued_before <= after_time,
         'invalid event issued_before time; %s is not earlier than %s.' % (
             timeutils.isotime(event_issued_before, subsecond=True),
             timeutils.isotime(after_time, subsecond=True)))
     del (event['issued_before'])
     self.assertEqual(sample, event)
Ejemplo n.º 30
0
    def authenticate(self, context, auth_info, auth_context):
        """Turn a signed request with an access key into a keystone token."""
        headers = context['headers']
        oauth_headers = oauth.get_oauth_headers(headers)
        consumer_id = oauth_headers.get('oauth_consumer_key')
        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)
        consumer = self.oauth_api.get_consumer_with_secret(consumer_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'))

        consumer_obj = oauth1.Consumer(key=consumer['id'],
                                       secret=consumer['secret'])
        acc_token_obj = oauth1.Token(key=acc_token['id'],
                                     secret=acc_token['access_secret'])

        url = oauth.rebuild_url(context['path'])
        oauth_request = oauth1.Request.from_request(
            http_method='POST',
            http_url=url,
            headers=context['headers'],
            query_string=context['query_string'])
        oauth_server = oauth1.Server()
        oauth_server.add_signature_method(oauth1.SignatureMethod_HMAC_SHA1())
        params = oauth_server.verify_request(oauth_request,
                                             consumer_obj,
                                             token=acc_token_obj)

        if params:
            msg = _('There should not be any non-oauth parameters')
            raise exception.Unauthorized(message=msg)

        auth_context['user_id'] = acc_token['authorizing_user_id']
        auth_context['access_token_id'] = access_token_id
        auth_context['project_id'] = acc_token['project_id']
Ejemplo n.º 31
0
def build_token_values(token_data):

    token_expires_at = timeutils.parse_isotime(token_data['expires_at'])

    # Trim off the microseconds because the revocation event only has
    # expirations accurate to the second.
    token_expires_at = token_expires_at.replace(microsecond=0)

    token_values = {
        'expires_at':
        timeutils.normalize_time(token_expires_at),
        'issued_at':
        timeutils.normalize_time(
            timeutils.parse_isotime(token_data['issued_at']))
    }

    user = token_data.get('user')
    if user is not None:
        token_values['user_id'] = user['id']
        token_values['identity_domain_id'] = user['domain']['id']
    else:
        token_values['user_id'] = None
        token_values['identity_domain_id'] = None

    project = token_data.get('project', token_data.get('tenant'))
    if project is not None:
        token_values['project_id'] = project['id']
        token_values['assignment_domain_id'] = project['domain']['id']
    else:
        token_values['project_id'] = None

        domain = token_data.get('domain')
        if domain is not None:
            token_values['assignment_domain_id'] = domain['id']
        else:
            token_values['assignment_domain_id'] = None

    role_list = []
    roles = token_data.get('roles')
    if roles is not None:
        for role in roles:
            role_list.append(role['id'])
    token_values['roles'] = role_list

    trust = token_data.get('OS-TRUST:trust')
    if trust is None:
        token_values['trust_id'] = None
        token_values['trustor_id'] = None
        token_values['trustee_id'] = None
    else:
        token_values['trust_id'] = trust['id']
        token_values['trustor_id'] = trust['trustor_user']['id']
        token_values['trustee_id'] = trust['trustee_user']['id']

    oauth1 = token_data.get('OS-OAUTH1')
    if oauth1 is None:
        token_values['consumer_id'] = None
        token_values['access_token_id'] = None
    else:
        token_values['consumer_id'] = oauth1['consumer_id']
        token_values['access_token_id'] = oauth1['access_token_id']
    return token_values
Ejemplo n.º 32
0
    def _authenticate_token(self, context, auth):
        """Try to authenticate using an already existing token.

        Returns auth_token_data, (user_ref, tenant_ref, metadata_ref)
        """
        if 'token' not in auth:
            raise exception.ValidationError(
                attribute='token', target='auth')

        if "id" not in auth['token']:
            raise exception.ValidationError(
                attribute="id", target="token")

        old_token = auth['token']['id']
        if len(old_token) > CONF.max_token_size:
            raise exception.ValidationSizeError(attribute='token',
                                                size=CONF.max_token_size)

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

        #A trust token cannot be used to get another token
        if 'trust' in old_token_ref:
            raise exception.Forbidden()
        if 'trust_id' in old_token_ref['metadata']:
            raise exception.Forbidden()

        user_ref = old_token_ref['user']
        user_id = user_ref['id']
        if not CONF.trust.enabled and 'trust_id' in auth:
            raise exception.Forbidden('Trusts are disabled.')
        elif CONF.trust.enabled and 'trust_id' in auth:
            trust_ref = self.trust_api.get_trust(context, auth['trust_id'])
            if trust_ref is None:
                raise exception.Forbidden()
            if user_id != trust_ref['trustee_user_id']:
                raise exception.Forbidden()
            if ('expires' in trust_ref) and (trust_ref['expires']):
                expiry = trust_ref['expires']
                if expiry < timeutils.parse_isotime(timeutils.isotime()):
                    raise exception.Forbidden()()
            user_id = trust_ref['trustor_user_id']
            trustor_user_ref = (self.identity_api.get_user(
                                context=context,
                                user_id=trust_ref['trustor_user_id']))
            if not trustor_user_ref['enabled']:
                raise exception.Forbidden()()
            trustee_user_ref = self.identity_api.get_user(
                context, trust_ref['trustee_user_id'])
            if not trustee_user_ref['enabled']:
                raise exception.Forbidden()()
            if trust_ref['impersonation'] == 'True':
                current_user_ref = trustor_user_ref
            else:
                current_user_ref = trustee_user_ref

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

        tenant_id = self._get_project_id_from_auth(context, auth)

        tenant_ref = self._get_project_ref(context, user_id, tenant_id)
        metadata_ref = self._get_metadata_ref(context, user_id, tenant_id)

        # TODO (henry-nash) If no tenant was specified, instead check
        # for a domain and find any related user/group roles

        self._append_roles(metadata_ref,
                           self._get_group_metadata_ref(
                               context, user_id, tenant_id))

        expiry = old_token_ref['expires']
        if CONF.trust.enabled and 'trust_id' in auth:
            trust_id = auth['trust_id']
            trust_roles = []
            for role in trust_ref['roles']:
                if not 'roles' in metadata_ref:
                    raise exception.Forbidden()()
                if role['id'] in metadata_ref['roles']:
                    trust_roles.append(role['id'])
                else:
                    raise exception.Forbidden()
            if 'expiry' in trust_ref and trust_ref['expiry']:
                trust_expiry = timeutils.parse_isotime(trust_ref['expiry'])
                if trust_expiry < expiry:
                    expiry = trust_expiry
            metadata_ref['roles'] = trust_roles
            metadata_ref['trustee_user_id'] = trust_ref['trustee_user_id']
            metadata_ref['trust_id'] = trust_id

        return (current_user_ref, tenant_ref, metadata_ref, expiry)
Ejemplo n.º 33
0
    def _update_user_list_with_cas(self, user_key, token_id):
        cas_retry = 0
        max_cas_retry = CONF.memcache.max_compare_and_set_retry
        current_time = timeutils.normalize_time(
            timeutils.parse_isotime(timeutils.isotime()))

        self.client.reset_cas()

        while cas_retry <= max_cas_retry:
            # NOTE(morganfainberg): cas or "compare and set" is a function of
            # memcache. It will return false if the value has changed since the
            # last call to client.gets(). This is the memcache supported method
            # of avoiding race conditions on set().  Memcache is already atomic
            # on the back-end and serializes operations.
            #
            # cas_retry is for tracking our iterations before we give up (in
            # case memcache is down or something horrible happens we don't
            # iterate forever trying to compare and set the new value.
            cas_retry += 1
            record = self.client.gets(user_key)
            filtered_list = []

            if record is not None:
                token_list = jsonutils.loads('[%s]' % record)
                for token_i in token_list:
                    ptk = self._prefix_token_id(token_i)
                    token_ref = self.client.get(ptk)
                    if not token_ref:
                        # skip tokens that do not exist in memcache
                        continue

                    if 'expires' in token_ref:
                        expires_at = timeutils.normalize_time(
                            token_ref['expires'])
                        if expires_at < current_time:
                            # skip tokens that are expired.
                            continue

                    # Add the still valid token_id to the list.
                    filtered_list.append(jsonutils.dumps(token_i))
            # Add the new token_id to the list.
            filtered_list.append(token_id)

            # Use compare-and-set (cas) to set the new value for the
            # token-index-list for the user-key. Cas is used to prevent race
            # conditions from causing the loss of valid token ids from this
            # list.
            if self.client.cas(user_key, ','.join(filtered_list)):
                msg = _('Successful set of token-index-list for user-key '
                        '"%(user_key)s", #%(count)d records')
                LOG.debug(msg, {
                    'user_key': user_key,
                    'count': len(filtered_list)
                })
                return filtered_list

            # The cas function will return true if it succeeded or false if it
            # failed for any reason, including memcache server being down, cas
            # id changed since gets() called (the data changed between when
            # this loop started and this point, etc.
            error_msg = _('Failed to set token-index-list for user-key '
                          '"%(user_key)s". Attempt %(cas_retry)d of '
                          '%(cas_retry_max)d')
            LOG.debug(
                error_msg, {
                    'user_key': user_key,
                    'cas_retry': cas_retry,
                    'cas_retry_max': max_cas_retry
                })

        # Exceeded the maximum retry attempts.
        error_msg = _('Unable to add token user list')
        raise exception.UnexpectedError(error_msg)
Ejemplo n.º 34
0
    def _authenticate_token(self, context, auth):
        """Try to authenticate using an already existing token.

        Returns auth_token_data, (user_ref, tenant_ref, metadata_ref)
        """
        if 'token' not in auth:
            raise exception.ValidationError(attribute='token', target='auth')

        if "id" not in auth['token']:
            raise exception.ValidationError(attribute="id", target="token")

        old_token = auth['token']['id']
        if len(old_token) > CONF.max_token_size:
            raise exception.ValidationSizeError(attribute='token',
                                                size=CONF.max_token_size)

        try:
            old_token_ref = self.token_api.get_token(old_token)
        except exception.NotFound as e:
            raise exception.Unauthorized(e)

        wsgi.validate_token_bind(context, old_token_ref)

        #A trust token cannot be used to get another token
        if 'trust' in old_token_ref:
            raise exception.Forbidden()
        if 'trust_id' in old_token_ref['metadata']:
            raise exception.Forbidden()

        user_ref = old_token_ref['user']
        user_id = user_ref['id']
        if not CONF.trust.enabled and 'trust_id' in auth:
            raise exception.Forbidden('Trusts are disabled.')
        elif CONF.trust.enabled and 'trust_id' in auth:
            trust_ref = self.trust_api.get_trust(auth['trust_id'])
            if trust_ref is None:
                raise exception.Forbidden()
            if user_id != trust_ref['trustee_user_id']:
                raise exception.Forbidden()
            if ('expires' in trust_ref) and (trust_ref['expires']):
                expiry = trust_ref['expires']
                if expiry < timeutils.parse_isotime(timeutils.isotime()):
                    raise exception.Forbidden()()
            user_id = trust_ref['trustor_user_id']
            trustor_user_ref = self.identity_api.get_user(
                trust_ref['trustor_user_id'])
            if not trustor_user_ref['enabled']:
                raise exception.Forbidden()()
            trustee_user_ref = self.identity_api.get_user(
                trust_ref['trustee_user_id'])
            if not trustee_user_ref['enabled']:
                raise exception.Forbidden()()
            self.trust_api.consume_use(auth['trust_id'])

            if trust_ref['impersonation'] is True:
                current_user_ref = trustor_user_ref
            else:
                current_user_ref = trustee_user_ref

        else:
            current_user_ref = self.identity_api.get_user(user_id)

        metadata_ref = {}
        tenant_id = self._get_project_id_from_auth(auth)
        tenant_ref, metadata_ref['roles'] = self._get_project_roles_and_ref(
            user_id, tenant_id)

        expiry = old_token_ref['expires']
        if CONF.trust.enabled and 'trust_id' in auth:
            trust_id = auth['trust_id']
            trust_roles = []
            for role in trust_ref['roles']:
                if 'roles' not in metadata_ref:
                    raise exception.Forbidden()()
                if role['id'] in metadata_ref['roles']:
                    trust_roles.append(role['id'])
                else:
                    raise exception.Forbidden()
            if 'expiry' in trust_ref and trust_ref['expiry']:
                trust_expiry = timeutils.parse_isotime(trust_ref['expiry'])
                if trust_expiry < expiry:
                    expiry = trust_expiry
            metadata_ref['roles'] = trust_roles
            metadata_ref['trustee_user_id'] = trust_ref['trustee_user_id']
            metadata_ref['trust_id'] = trust_id

        bind = old_token_ref.get('bind')

        return (current_user_ref, tenant_ref, metadata_ref, expiry, bind)
Ejemplo n.º 35
0
    def create_access_token(self, context):
        headers = context['headers']
        oauth_headers = oauth1.get_oauth_headers(headers)
        consumer_id = oauth_headers.get('oauth_consumer_key')
        request_token_id = oauth_headers.get('oauth_token')
        oauth_verifier = oauth_headers.get('oauth_verifier')

        if not consumer_id:
            raise exception.ValidationError(attribute='oauth_consumer_key',
                                            target='request')
        if not request_token_id:
            raise exception.ValidationError(attribute='oauth_token',
                                            target='request')
        if not oauth_verifier:
            raise exception.ValidationError(attribute='oauth_verifier',
                                            target='request')

        req_token = self.oauth_api.get_request_token(request_token_id)

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

        url = self.base_url(context, context['path'])

        access_verifier = oauth1.AccessTokenEndpoint(
            request_validator=validator.OAuthValidator(),
            token_generator=oauth1.token_generator)
        h, b, s = access_verifier.create_access_token_response(
            url,
            http_method='POST',
            body=context['query_string'],
            headers=headers)
        params = oauth1.extract_non_oauth_params(b)
        if len(params) != 0:
            msg = _('There should not be any non-oauth parameters')
            raise exception.Unauthorized(message=msg)

        if req_token['consumer_id'] != consumer_id:
            msg = _('provided consumer key does not match stored consumer key')
            raise exception.Unauthorized(message=msg)

        if req_token['verifier'] != oauth_verifier:
            msg = _('provided verifier does not match stored verifier')
            raise exception.Unauthorized(message=msg)

        if req_token['id'] != request_token_id:
            msg = _('provided request key does not match stored request key')
            raise exception.Unauthorized(message=msg)

        if not req_token.get('authorizing_user_id'):
            msg = _('Request Token does not have an authorizing user id')
            raise exception.Unauthorized(message=msg)

        access_token_duration = CONF.oauth1.access_token_duration
        token_ref = self.oauth_api.create_access_token(request_token_id,
                                                       access_token_duration)

        result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s' % {
            'key': token_ref['id'],
            'secret': token_ref['access_secret']
        })

        if CONF.oauth1.access_token_duration:
            expiry_bit = '&oauth_expires_at=%s' % (token_ref['expires_at'])
            result += expiry_bit

        headers = [('Content-Type', 'application/x-www-urlformencoded')]
        response = wsgi.render_response(result,
                                        status=(201, 'Created'),
                                        headers=headers)

        return response
Ejemplo n.º 36
0
    def authorize_request_token(self, context, request_token_id, roles):
        """An authenticated user is going to authorize a request token.

        As a security precaution, the requested roles must match those in
        the request token. Because this is in a CLI-only world at the moment,
        there is not another easy way to make sure the user knows which roles
        are being requested before authorizing.
        """
        auth_context = context.get('environment',
                                   {}).get('KEYSTONE_AUTH_CONTEXT', {})
        if auth_context.get('is_delegated_auth'):
            raise exception.Forbidden(
                _('Cannot authorize a request token'
                  ' with a token issued via delegation.'))

        req_token = self.oauth_api.get_request_token(request_token_id)

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

        # put the roles in a set for easy comparison
        authed_roles = set()
        for role in roles:
            authed_roles.add(role['id'])

        # verify the authorizing user has the roles
        user_token = self.token_api.get_token(context['token_id'])
        user_id = user_token['user'].get('id')
        project_id = req_token['requested_project_id']
        user_roles = self.assignment_api.get_roles_for_user_and_project(
            user_id, project_id)
        cred_set = set(user_roles)

        if not cred_set.issuperset(authed_roles):
            msg = _('authorizing user does not have role required')
            raise exception.Unauthorized(message=msg)

        # create list of just the id's for the backend
        role_list = list(authed_roles)

        # verify the user has the project too
        req_project_id = req_token['requested_project_id']
        user_projects = self.assignment_api.list_projects_for_user(user_id)
        for user_project in user_projects:
            if user_project['id'] == req_project_id:
                break
        else:
            msg = _("User is not a member of the requested project")
            raise exception.Unauthorized(message=msg)

        # finally authorize the token
        authed_token = self.oauth_api.authorize_request_token(
            request_token_id, user_id, role_list)

        to_return = {'token': {'oauth_verifier': authed_token['verifier']}}
        return to_return
Ejemplo n.º 37
0
    def create_access_token(self, context):
        headers = context['headers']
        oauth_headers = oauth1.get_oauth_headers(headers)
        consumer_id = oauth_headers.get('oauth_consumer_key')
        request_token_id = oauth_headers.get('oauth_token')
        oauth_verifier = oauth_headers.get('oauth_verifier')

        if not consumer_id:
            raise exception.ValidationError(
                attribute='oauth_consumer_key', target='request')
        if not request_token_id:
            raise exception.ValidationError(
                attribute='oauth_token', target='request')
        if not oauth_verifier:
            raise exception.ValidationError(
                attribute='oauth_verifier', target='request')

        consumer = self.oauth_api.get_consumer_with_secret(consumer_id)
        req_token = self.oauth_api.get_request_token(
            request_token_id)

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

        consumer_obj = oauth1.Consumer(key=consumer['id'],
                                       secret=consumer['secret'])
        req_token_obj = oauth1.Token(key=req_token['id'],
                                     secret=req_token['request_secret'])
        req_token_obj.set_verifier(oauth_verifier)

        url = oauth1.rebuild_url(context['path'])
        oauth_request = oauth1.Request.from_request(
            http_method='POST',
            http_url=url,
            headers=context['headers'],
            query_string=context['query_string'])
        oauth_server = oauth1.Server()
        oauth_server.add_signature_method(oauth1.SignatureMethod_HMAC_SHA1())
        params = oauth_server.verify_request(oauth_request,
                                             consumer_obj,
                                             token=req_token_obj)

        if len(params) != 0:
            msg = _('There should not be any non-oauth parameters')
            raise exception.Unauthorized(message=msg)

        if req_token['consumer_id'] != consumer_id:
            msg = _('provided consumer key does not match stored consumer key')
            raise exception.Unauthorized(message=msg)

        if req_token['verifier'] != oauth_verifier:
            msg = _('provided verifier does not match stored verifier')
            raise exception.Unauthorized(message=msg)

        if req_token['id'] != request_token_id:
            msg = _('provided request key does not match stored request key')
            raise exception.Unauthorized(message=msg)

        if not req_token.get('authorizing_user_id'):
            msg = _('Request Token does not have an authorizing user id')
            raise exception.Unauthorized(message=msg)

        access_token_duration = CONF.oauth1.access_token_duration
        token_ref = self.oauth_api.create_access_token(request_token_id,
                                                       access_token_duration)

        result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s'
                  % {'key': token_ref['id'],
                     'secret': token_ref['access_secret']})

        if CONF.oauth1.access_token_duration:
            expiry_bit = '&oauth_expires_at=%s' % (token_ref['expires_at'])
            result += expiry_bit

        headers = [('Content-Type', 'application/x-www-urlformencoded')]
        response = wsgi.render_response(result,
                                        status=(201, 'Created'),
                                        headers=headers)

        return response
Ejemplo n.º 38
0
    def issue_v3_token(self,
                       user_id,
                       method_names,
                       expires_at=None,
                       project_id=None,
                       domain_id=None,
                       auth_context=None,
                       trust=None,
                       metadata_ref=None,
                       include_catalog=True):
        # for V2, trust is stashed in metadata_ref
        if (CONF.trust.enabled and not trust and metadata_ref
                and 'trust_id' in metadata_ref):
            trust = self.trust_api.get_trust(metadata_ref['trust_id'])

        access_token = None
        if 'oauth1' in method_names:
            if self.oauth_api:
                access_token_id = auth_context['access_token_id']
                access_token = self.oauth_api.get_access_token(access_token_id)
            else:
                raise exception.Forbidden(_('Oauth is disabled.'))

        token_data = self.v3_token_data_helper.get_token_data(
            user_id,
            method_names,
            auth_context.get('extras') if auth_context else None,
            domain_id=domain_id,
            project_id=project_id,
            expires=expires_at,
            trust=trust,
            bind=auth_context.get('bind') if auth_context else None,
            include_catalog=include_catalog,
            access_token=access_token)

        token_id = self._get_token_id(token_data)
        try:
            expiry = token_data['token']['expires_at']
            if isinstance(expiry, six.string_types):
                expiry = timeutils.normalize_time(
                    timeutils.parse_isotime(expiry))
            # FIXME(gyee): is there really a need to store roles in metadata?
            role_ids = []
            if metadata_ref is None:
                metadata_ref = {}
            if 'project' in token_data['token']:
                # project-scoped token, fill in the v2 token data
                # all we care are the role IDs
                role_ids = [r['id'] for r in token_data['token']['roles']]
                metadata_ref = {'roles': role_ids}
            if trust:
                metadata_ref.setdefault('trust_id', trust['id'])
                metadata_ref.setdefault('trustee_user_id',
                                        trust['trustee_user_id'])
            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_version=token.provider.V3)
            self.token_api.create_token(token_id, data)
        except Exception:
            exc_info = sys.exc_info()
            # 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(token_id)
            except exception.TokenNotFound:
                raise exc_info[0], exc_info[1], exc_info[2]

        return (token_id, token_data)
Ejemplo n.º 39
0
    def _issue_v3_token(self, **kwargs):
        user_id = kwargs.get('user_id')
        method_names = kwargs.get('method_names')
        expires_at = kwargs.get('expires_at')
        project_id = kwargs.get('project_id')
        domain_id = kwargs.get('domain_id')
        auth_context = kwargs.get('auth_context')
        trust = kwargs.get('trust')
        metadata_ref = kwargs.get('metadata_ref')
        include_catalog = kwargs.get('include_catalog')
        # for V2, trust is stashed in metadata_ref
        if (CONF.trust.enabled and not trust and metadata_ref
                and 'trust_id' in metadata_ref):
            trust = self.trust_api.get_trust(metadata_ref['trust_id'])
        token_data = self.v3_token_data_helper.get_token_data(
            user_id,
            method_names,
            auth_context.get('extras') if auth_context else None,
            domain_id=domain_id,
            project_id=project_id,
            expires=expires_at,
            trust=trust,
            bind=auth_context.get('bind') if auth_context else None,
            include_catalog=include_catalog)

        token_id = self._get_token_id(token_data)
        try:
            expiry = token_data['token']['expires_at']
            if isinstance(expiry, basestring):
                expiry = timeutils.normalize_time(
                    timeutils.parse_isotime(expiry))
            # FIXME(gyee): is there really a need to store roles in metadata?
            role_ids = []
            metadata_ref = kwargs.get('metadata_ref', {})
            if 'project' in token_data['token']:
                # project-scoped token, fill in the v2 token data
                # all we care are the role IDs
                role_ids = [r['id'] for r in token_data['token']['roles']]
                metadata_ref = {'roles': role_ids}
            if trust:
                metadata_ref.setdefault('trust_id', trust['id'])
                metadata_ref.setdefault('trustee_user_id',
                                        trust['trustee_user_id'])
            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)
            self.token_api.create_token(token_id, data)
        except Exception:
            exc_info = sys.exc_info()
            # 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(token_id)
            except exception.TokenNotFound:
                raise exc_info[0], exc_info[1], exc_info[2]

        return (token_id, token_data)