Esempio n. 1
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'))
Esempio n. 2
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'))
Esempio n. 3
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
Esempio n. 4
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)
Esempio n. 5
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')
Esempio n. 6
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)
Esempio 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"]
Esempio n. 8
0
    def _convert_user_index_from_json(self, token_list, user_key):
        try:
            # NOTE(morganfainberg): Try loading in the old format
            # of the list.
            token_list = jsonutils.loads('[%s]' % token_list)

            # NOTE(morganfainberg): Build a delta based upon the
            # token TTL configured. Since we are using the old
            # format index-list, we will create a "fake" expiration
            # that should be further in the future than the actual
            # expiry. To avoid locking up keystone trying to
            # communicate to memcached, it is better to use a fake
            # value. The logic that utilizes this list already
            # knows how to handle the case of tokens that are
            # no longer valid being included.
            delta = datetime.timedelta(
                seconds=CONF.token.expiration)
            new_expiry = timeutils.normalize_time(
                timeutils.utcnow()) + delta

            for idx, token_id in enumerate(token_list):
                token_list[idx] = (token_id, new_expiry)

        except Exception:
            # NOTE(morganfainberg): Catch any errors thrown here. There is
            # nothing the admin or operator needs to do in this case, but
            # it should be logged that there was an error and some action was
            # taken to correct it
            LOG.exception(_('Error converting user-token-index to new format; '
                            'clearing user token index record "%s".'),
                          user_key)
            token_list = []
        return token_list
Esempio 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)
Esempio n. 10
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
Esempio n. 11
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)
Esempio n. 12
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)
Esempio n. 13
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
Esempio n. 14
0
    def _list_tokens(self, user_id, tenant_id=None, trust_id=None,
                     consumer_id=None):
        tokens = []
        user_key = self._prefix_user_id(user_id)
        current_time = timeutils.normalize_time(timeutils.utcnow())
        token_list = self.client.get(user_key) or []
        if not isinstance(token_list, list):
            # NOTE(morganfainberg): This is for compatibility for old-format
            # token-lists that were a JSON string of just token_ids. This code
            # will reference the underlying expires directly from the
            # token_ref vs in this list, so setting to none just ensures the
            # loop works as expected.
            token_list = [(i, None) for i in
                          jsonutils.loads('[%s]' % token_list)]
        for token_id, expiry in token_list:
            ptk = self._prefix_token_id(token_id)
            token_ref = self.client.get(ptk)
            if token_ref:
                if tenant_id is not None:
                    tenant = token_ref.get('tenant')
                    if not tenant:
                        continue
                    if tenant.get('id') != tenant_id:
                        continue
                if trust_id is not None:
                    trust = token_ref.get('trust_id')
                    if not trust:
                        continue
                    if trust != trust_id:
                        continue
                if consumer_id is not None:
                    try:
                        oauth = token_ref['token_data']['token']['OS-OAUTH1']
                        if oauth.get('consumer_id') != consumer_id:
                            continue
                    except KeyError:
                        continue

                if (timeutils.normalize_time(token_ref['expires']) <
                        current_time):
                    # Skip expired tokens.
                    continue

                tokens.append(token_id)
        return tokens
Esempio n. 15
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
Esempio n. 16
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)
Esempio n. 17
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
Esempio n. 18
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
Esempio n. 19
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
Esempio n. 20
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)

        # Token is expired, we have a malformed token, or something went wrong.
        raise exception.Unauthorized(_('Failed to validate token'))
Esempio n. 21
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)
Esempio n. 22
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)
Esempio n. 23
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']
Esempio n. 24
0
 def create_trust(self, trust_id, trust, roles):
     with sql.transaction() as session:
         ref = TrustModel.from_dict(trust)
         ref['id'] = trust_id
         if ref.get('expires_at') and ref['expires_at'].tzinfo is not None:
             ref['expires_at'] = timeutils.normalize_time(ref['expires_at'])
         session.add(ref)
         added_roles = []
         for role in roles:
             trust_role = TrustRole()
             trust_role.trust_id = trust_id
             trust_role.role_id = role['id']
             added_roles.append({'id': role['id']})
             session.add(trust_role)
     trust_dict = ref.to_dict()
     trust_dict['roles'] = added_roles
     return trust_dict
Esempio n. 25
0
    def authenticate(self, context, auth_payload, user_context):
        try:
            if 'id' not in auth_payload:
                raise exception.ValidationError(attribute='id',
                                                target=METHOD_NAME)
            token_id = auth_payload['id']
            response = self.provider.validate_token(token_id)
            #for V3 tokens, the essential data is under  the 'token' value.
            #For V2, the comparable data was nested under 'access'
            token_ref = response.get('token', response.get('access'))

            #Do not allow tokens used for delegation to
            #create another token, or perform any changes of
            #state in Keystone. TO do so is to invite elevation of
            #privilege attacks
            if 'OS-TRUST:trust' in token_ref:
                raise exception.Forbidden()
            if 'trust' in token_ref:
                raise exception.Forbidden()
            if 'trust_id' in token_ref.get('metadata', {}):
                raise exception.Forbidden()
            if 'OS-OAUTH1' in token_ref:
                raise exception.Forbidden()

            wsgi.validate_token_bind(context, token_ref)

            #new tokens are not allowed to extend the expiration
            #time of an old token, otherwise, they could be extened
            #forever.   The expiration value was stored at different
            #locations in v2 and v3 tokens.
            expires_at = token_ref.get('expires_at')
            if not expires_at:
                expires_at = token_ref.get('expires')
            if not expires_at:
                expires_at = timeutils.normalize_time(
                    timeutils.parse_isotime(token_ref['token']['expires']))

            user_context.setdefault('expires_at', expires_at)
            user_context.setdefault('user_id', token_ref['user']['id'])
            user_context['extras'].update(token_ref.get('extras', {}))
            user_context['method_names'].extend(token_ref.get('methods', []))

        except AssertionError as e:
            LOG.error(e)
            raise exception.Unauthorized(e)
Esempio n. 26
0
    def _format_token_index_item(self, item):
        try:
            token_id, expires = item
        except (TypeError, ValueError):
            LOG.debug(('Invalid token entry expected tuple of '
                       '`(<token_id>, <expires>)` got: `%(item)r`'),
                      dict(item=item))
            raise

        try:
            expires = timeutils.normalize_time(
                timeutils.parse_isotime(expires))
        except ValueError:
            LOG.debug(('Invalid expires time on token `%(token_id)s`:'
                       ' %(expires)r'),
                      dict(token_id=token_id, expires=expires))
            raise
        return token_id, expires
Esempio n. 27
0
 def create_trust(self, trust_id, trust, roles):
     session = db_session.get_session()
     with session.begin():
         ref = TrustModel.from_dict(trust)
         ref["id"] = trust_id
         if ref.get("expires_at") and ref["expires_at"].tzinfo is not None:
             ref["expires_at"] = timeutils.normalize_time(ref["expires_at"])
         session.add(ref)
         added_roles = []
         for role in roles:
             trust_role = TrustRole()
             trust_role.trust_id = trust_id
             trust_role.role_id = role["id"]
             added_roles.append({"id": role["id"]})
             session.add(trust_role)
     trust_dict = ref.to_dict()
     trust_dict["roles"] = added_roles
     return trust_dict
Esempio n. 28
0
    def create_trust(self, trust_id, trust, roles):
        trust_ref = trust
        trust_ref["id"] = trust_id
        trust_ref["deleted"] = False
        trust_ref["roles"] = roles
        if trust_ref.get("expires_at") and trust_ref["expires_at"].tzinfo is not None:
            trust_ref["expires_at"] = timeutils.normalize_time(trust_ref["expires_at"])

        self.db.set("trust-%s" % trust_id, trust_ref)
        trustee_user_id = trust_ref["trustee_user_id"]
        trustee_list = self.db.get("trustee-%s" % trustee_user_id, [])
        trustee_list.append(trust_id)
        self.db.set("trustee-%s" % trustee_user_id, trustee_list)
        trustor_user_id = trust_ref["trustor_user_id"]
        trustor_list = self.db.get("trustor-%s" % trustor_user_id, [])
        trustor_list.append(trust_id)
        self.db.set("trustor-%s" % trustor_user_id, trustor_list)
        return copy.deepcopy(trust_ref)
Esempio n. 29
0
    def create_trust(self, trust_id, trust, roles):
        trust_ref = trust
        trust_ref['id'] = trust_id
        trust_ref['deleted'] = False
        trust_ref['roles'] = roles
        if (trust_ref.get('expires_at') and
                trust_ref['expires_at'].tzinfo is not None):
                    trust_ref['expires_at'] = (timeutils.normalize_time
                                               (trust_ref['expires_at']))

        self.db.set('trust-%s' % trust_id, trust_ref)
        trustee_user_id = trust_ref['trustee_user_id']
        trustee_list = self.db.get('trustee-%s' % trustee_user_id, [])
        trustee_list.append(trust_id)
        self.db.set('trustee-%s' % trustee_user_id, trustee_list)
        trustor_user_id = trust_ref['trustor_user_id']
        trustor_list = self.db.get('trustor-%s' % trustor_user_id, [])
        trustor_list.append(trust_id)
        self.db.set('trustor-%s' % trustor_user_id, trustor_list)
        return copy.deepcopy(trust_ref)
Esempio n. 30
0
 def list_revoke_events(self, context):
     since = context['query_string'].get('since')
     last_fetch = None
     if since:
         try:
             last_fetch = timeutils.normalize_time(
                 timeutils.parse_isotime(since))
         except ValueError:
             raise exception.ValidationError(
                 message=_('invalid date format %s') % since)
     events = self.revoke_api.get_events(last_fetch=last_fetch)
     # Build the links by hand as the standard controller calls require ids
     response = {'events': [event.to_dict() for event in events],
                 'links': {
                     'next': None,
                     'self': RevokeController.base_url(
                         path=context['path']) + '/events',
                     'previous': None}
                 }
     return response
Esempio n. 31
0
 def _assert_valid(self, token_id, token_ref):
     """Raise TokenNotFound if the token is expired."""
     current_time = timeutils.normalize_time(timeutils.utcnow())
     expires = token_ref.get('expires')
     if not expires or current_time > timeutils.normalize_time(expires):
         raise exception.TokenNotFound(token_id=token_id)
Esempio n. 32
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
Esempio n. 33
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)
Esempio n. 34
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)
Esempio 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
Esempio n. 36
0
 def _get_current_time(self):
     return timeutils.normalize_time(timeutils.utcnow())
Esempio n. 37
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)
Esempio n. 38
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