def test_cleanup_user_index_on_create(self):
        valid_token_id = uuid.uuid4().hex
        second_valid_token_id = uuid.uuid4().hex
        expired_token_id = uuid.uuid4().hex
        user_id = unicode(uuid.uuid4().hex)

        expire_delta = datetime.timedelta(seconds=86400)

        valid_data = {'id': valid_token_id, 'a': 'b',
                      'user': {'id': user_id}}
        second_valid_data = {'id': second_valid_token_id, 'a': 'b',
                             'user': {'id': user_id}}
        expired_data = {'id': expired_token_id, 'a': 'b',
                        'user': {'id': user_id}}
        self.token_api.create_token(valid_token_id, valid_data)
        self.token_api.create_token(expired_token_id, expired_data)
        # NOTE(morganfainberg): Directly access the data cache since we need to
        # get expired tokens as well as valid tokens. token_api.list_tokens()
        # will not return any expired tokens in the list.
        user_key = self.token_api.driver._prefix_user_id(user_id)
        user_record = self.token_api.driver.client.get(user_key)
        user_token_list = jsonutils.loads('[%s]' % user_record)
        self.assertEquals(len(user_token_list), 2)
        expired_token_ptk = self.token_api.driver._prefix_token_id(
            expired_token_id)
        expired_token = self.token_api.driver.client.get(expired_token_ptk)
        expired_token['expires'] = (timeutils.utcnow() - expire_delta)
        self.token_api.driver.client.set(expired_token_ptk, expired_token)

        self.token_api.create_token(second_valid_token_id, second_valid_data)
        user_record = self.token_api.driver.client.get(user_key)
        user_token_list = jsonutils.loads('[%s]' % user_record)
        self.assertEquals(len(user_token_list), 2)
Esempio n. 2
0
    def get_ticket(self, source, target, crypto, key):

        # prepare metadata
        md = {'requestor': source,
              'target': target,
              'timestamp': time.time(),
              'nonce': struct.unpack('Q', os.urandom(8))[0]}
        metadata = base64.b64encode(jsonutils.dumps(md))

        # sign metadata
        signature = crypto.sign(key, metadata)

        # HTTP request
        reply = self._get_ticket({'metadata': metadata,
                                  'signature': signature})

        # verify reply
        signature = crypto.sign(key, (reply['metadata'] + reply['ticket']))
        if signature != reply['signature']:
            raise InvalidEncryptedTicket(md['source'], md['destination'])
        md = jsonutils.loads(base64.b64decode(reply['metadata']))
        if ((md['source'] != source or
             md['destination'] != target or
             md['expiration'] < time.time())):
            raise InvalidEncryptedTicket(md['source'], md['destination'])

        # return ticket data
        tkt = jsonutils.loads(crypto.decrypt(key, reply['ticket']))

        return tkt, md['expiration']
Esempio n. 3
0
    def test_v3_disabled(self):
        self.stubs.Set(controllers, '_VERSIONS', ['v2.0'])
        client = self.client(self.public_app)
        # request to /v3 should fail
        resp = client.get('/v3/')
        self.assertEqual(resp.status_int, 404)

        # request to /v2.0 should pass
        resp = client.get('/v2.0/')
        self.assertEqual(resp.status_int, 200)
        data = jsonutils.loads(resp.body)
        expected = v2_VERSION_RESPONSE
        self._paste_in_port(expected['version'],
                            'http://localhost:%s/v2.0/' % CONF.public_port)
        self.assertEqual(data, expected)

        # only v2 information should be displayed by requests to /
        v2_only_response = {
            "versions": {
                "values": [
                    v2_EXPECTED_RESPONSE
                ]
            }
        }
        self._paste_in_port(v2_only_response['versions']['values'][0],
                            'http://localhost:%s/v2.0/' % CONF.public_port)
        resp = client.get('/')
        self.assertEqual(resp.status_int, 300)
        data = jsonutils.loads(resp.body)
        self.assertEqual(data, v2_only_response)
Esempio n. 4
0
def _migrate_enabled_from_extra(migrate_engine, endpoint_table):
    """Remove `enabled` from `extra`, put it in the `enabled` column."""

    eps = list(endpoint_table.select().execute())

    for ep in eps:
        extra_dict = jsonutils.loads(ep.extra)

        if 'enabled' not in extra_dict:
            # `enabled` and `extra` are already as expected.
            continue

        enabled = extra_dict.pop('enabled')

        if enabled is None:
            enabled = True
        else:
            enabled = strutils.bool_from_string(enabled, default=True)

        new_values = {
            'enabled': enabled,
            'extra': jsonutils.dumps(extra_dict),
        }
        f = endpoint_table.c.id == ep.id
        update = endpoint_table.update().where(f).values(new_values)
        migrate_engine.execute(update)
Esempio n. 5
0
def _migrate_enabled_to_extra(migrate_engine, endpoint_table):
    """Get enabled value from 'enabled' column and put it in 'extra' JSON.

    Only put the enabled value to the 'extra' JSON if it's False, since the
    default is True.

    """

    eps = list(endpoint_table.select().execute())

    for ep in eps:

        if ep.enabled:
            # Nothing to do since the endpoint is enabled.
            continue

        extra_dict = jsonutils.loads(ep.extra)
        extra_dict['enabled'] = False

        new_values = {
            'extra': jsonutils.dumps(extra_dict),
        }
        f = endpoint_table.c.id == ep.id
        update = endpoint_table.update().where(f).values(new_values)
        migrate_engine.execute(update)
Esempio n. 6
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)
        user_record = self.client.get(user_key) or ""
        token_list = jsonutils.loads("[%s]" % user_record)
        for token_id 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

                tokens.append(token_id)
        return tokens
Esempio n. 7
0
 def has_attributes(self, body, attr):
     body_dict = jsonutils.loads(body)
     try:
         self._require_attributes(body_dict, attr)
         return True
     except exception.ValidationError as ex:
         return (False, ex.message)
Esempio n. 8
0
 def _assign_unique_id(self, ref, trust_id=None):
     # Generates and assigns a unique identifier to
     # a credential reference.
     if ref.get('type', '').lower() == 'ec2':
         try:
             blob = jsonutils.loads(ref.get('blob'))
         except (ValueError, TypeError):
             raise exception.ValidationError(
                 message=_('Invalid blob in credential'))
         if not blob or not isinstance(blob, dict):
             raise exception.ValidationError(attribute='blob',
                                             target='credential')
         if blob.get('access') is None:
             raise exception.ValidationError(attribute='access',
                                             target='blob')
         ret_ref = ref.copy()
         ret_ref['id'] = hashlib.sha256(blob['access']).hexdigest()
         # Update the blob with the trust_id, so credentials created
         # with a trust scoped token will result in trust scoped
         # tokens when authentication via ec2tokens happens
         if trust_id is not None:
             blob['trust_id'] = trust_id
             ret_ref['blob'] = jsonutils.dumps(blob)
         return ret_ref
     else:
         return super(CredentialV3, self)._assign_unique_id(ref)
    def test_fetch_revocation_list_with_expire(self):
        # first response to revocation list should return 401 Unauthorized
        # to pretend to be an expired token
        resp1 = FakeHTTPResponse(200, jsonutils.dumps({
            'access': {
                'token': {'id': 'admin_token2'},
            },
        }))
        resp2 = FakeHTTPResponse(401, jsonutils.dumps(''))
        resp3 = FakeHTTPResponse(200, jsonutils.dumps({
            'access': {
                'token': {'id': 'admin_token2'},
            },
        }))
        resp4 = FakeHTTPResponse(200, SIGNED_REVOCATION_LIST)

        # first get_admin_token() call
        FAKE_RESPONSE_STACK.append(resp1)
        # request revocation list, get "unauthorized" due to simulated expired
        # token
        FAKE_RESPONSE_STACK.append(resp2)
        # request a new admin_token
        FAKE_RESPONSE_STACK.append(resp3)
        # request revocation list, get the revocation list properly
        FAKE_RESPONSE_STACK.append(resp4)

        fetched_list = jsonutils.loads(self.middleware.fetch_revocation_list())
        self.assertEqual(fetched_list, REVOCATION_LIST)
Esempio n. 10
0
    def test_tokens_after_user_update_passwd(self):
        from keystoneclient import exceptions as client_exceptions

        client = self.get_client(self.user_two)

        token_id = client.auth_token
        new_password = uuid.uuid4().hex

        # TODO(derekh) : Update to use keystoneclient when available
        class FakeResponse(object):
            def start_fake_response(self, status, headers):
                self.response_status = int(status.split(' ', 1)[0])
                self.response_headers = dict(headers)
        responseobject = FakeResponse()

        req = webob.Request.blank(
            '/v2.0/OS-KSCRUD/users/%s' % self.user_two['id'],
            headers={'X-Auth-Token': token_id})
        req.method = 'PATCH'
        req.body = ('{"user":{"password":"******","original_password":"******"}}' %
                    (new_password, self.user_two['password']))

        rv = self.public_server.application(
            req.environ,
            responseobject.start_fake_response)
        responce_json = jsonutils.loads(rv.next())
        new_token_id = responce_json['access']['token']['id']

        self.assertRaises(client_exceptions.Unauthorized, client.tenants.list)
        client.auth_token = new_token_id
        client.tenants.list()
Esempio n. 11
0
    def _decode_esek(self, key, source, target, timestamp, esek):
        """This function decrypts the esek buffer passed in and returns a
        KeyStore to be used to check and decrypt the received message.

        :param key: The key to use to decrypt the ticket (esek)
        :param source: The name of the source service
        :param traget: The name of the target service
        :param timestamp: The incoming message timestamp
        :param esek: a base64 encoded encrypted block containing a JSON string
        """
        rkey = None

        try:
            s = self._crypto.decrypt(key, esek)
            j = jsonutils.loads(s)

            rkey = base64.b64decode(j['key'])
            expiration = j['timestamp'] + j['ttl']
            if j['timestamp'] > timestamp or timestamp > expiration:
                raise InvalidExpiredTicket(source, target)

        except Exception:
            raise InvalidEncryptedTicket(source, target)

        info = '%s,%s,%s' % (source, target, str(j['timestamp']))

        sek = self._hkdf.expand(rkey, info, len(key) * 2)

        return self._split_key(sek, len(key))
Esempio n. 12
0
 def main(self):
     from keystone.common.sql import nova
     if len(self.argv) < 2:
         return self.missing_param('dump_file')
     dump_file = self.argv[1]
     dump_data = jsonutils.loads(open(dump_file).read())
     nova.import_auth(dump_data)
Esempio n. 13
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. 14
0
    def process_request(self, request):
        # Abort early if we don't have any work to do
        params_json = request.body
        if not params_json:
            return

        # Reject unrecognized content types. Empty string indicates
        # the client did not explicitly set the header
        if request.content_type not in ('application/json', ''):
            e = exception.ValidationError(attribute='application/json',
                                          target='Content-Type header')
            return wsgi.render_exception(e)

        params_parsed = {}
        try:
            params_parsed = jsonutils.loads(params_json)
        except ValueError:
            e = exception.ValidationError(attribute='valid JSON',
                                          target='request body')
            return wsgi.render_exception(e)
        finally:
            if not params_parsed:
                params_parsed = {}

        params = {}
        for k, v in params_parsed.iteritems():
            if k in ('self', 'context'):
                continue
            if k.startswith('_'):
                continue
            params[k] = v

        request.environ[PARAMS_ENV] = params
Esempio n. 15
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)
        user_record = self.client.get(user_key) or ""
        token_list = jsonutils.loads('[%s]' % user_record)
        for token_id 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

                tokens.append(token_id)
        return tokens
Esempio n. 16
0
 def test_query_string_available(self):
     class FakeApp(wsgi.Application):
         def index(self, context):
             return context['query_string']
     req = self._make_request(url='/?1=2')
     resp = req.get_response(FakeApp())
     self.assertEqual(jsonutils.loads(resp.body), {'1': '2'})
Esempio n. 17
0
    def process_request(self, request):
        # Abort early if we don't have any work to do
        params_json = request.body
        if not params_json:
            return

        # Reject unrecognized content types. Empty string indicates
        # the client did not explicitly set the header
        if request.content_type not in ("application/json", ""):
            e = exception.ValidationError(attribute="application/json", target="Content-Type header")
            return wsgi.render_exception(e, request=request)

        params_parsed = {}
        try:
            params_parsed = jsonutils.loads(params_json)
        except ValueError:
            e = exception.ValidationError(attribute="valid JSON", target="request body")
            return wsgi.render_exception(e, request=request)
        finally:
            if not params_parsed:
                params_parsed = {}

        if not isinstance(params_parsed, dict):
            e = exception.ValidationError(attribute="valid JSON object", target="request body")
            return wsgi.render_exception(e, request=request)

        params = {}
        for k, v in six.iteritems(params_parsed):
            if k in ("self", "context"):
                continue
            if k.startswith("_"):
                continue
            params[k] = v

        request.environ[PARAMS_ENV] = params
Esempio n. 18
0
    def load_json(cls, data, default_rule=None):
        """Allow loading of JSON rule data."""

        # Suck in the JSON data and parse the rules
        rules = dict((k, parse_rule(v)) for k, v in jsonutils.loads(data).items())

        return cls(rules, default_rule)
Esempio n. 19
0
    def test_localized_message(self):
        # If the accept-language header is set on the request, the localized
        # message is returned by calling get_localized_message.

        LANG_ID = uuid.uuid4().hex
        ORIGINAL_TEXT = uuid.uuid4().hex
        TRANSLATED_TEXT = uuid.uuid4().hex

        self._set_expected_languages(all_locales=[LANG_ID])

        def fake_get_localized_message(message, user_locale):
            if (user_locale == LANG_ID and
                    message == ORIGINAL_TEXT):
                return TRANSLATED_TEXT

        self.stubs.Set(gettextutils, 'get_localized_message',
                       fake_get_localized_message)

        error = exception.NotFound(message=ORIGINAL_TEXT)
        resp = wsgi.render_exception(error, user_locale=LANG_ID)
        result = jsonutils.loads(resp.body)

        exp = {'error': {'message': TRANSLATED_TEXT,
                         'code': 404,
                         'title': 'Not Found'}}

        self.assertEqual(exp, result)
Esempio n. 20
0
 def test_admin_version_v3(self):
     client = self.client(self.public_app)
     resp = client.get("/v3/")
     self.assertEqual(resp.status_int, 200)
     data = jsonutils.loads(resp.body)
     expected = v3_VERSION_RESPONSE
     self._paste_in_port(expected["version"], "http://localhost:%s/v3/" % CONF.admin_port)
     self.assertEqual(data, expected)
Esempio n. 21
0
 def list_access_token_roles(self, context, user_id, access_token_id):
     access_token = self.oauth_api.get_access_token(access_token_id)
     if access_token['authorizing_user_id'] != user_id:
         raise exception.NotFound()
     authed_role_ids = access_token['role_ids']
     authed_role_ids = jsonutils.loads(authed_role_ids)
     refs = ([self._format_role_entity(x) for x in authed_role_ids])
     return AccessTokenRolesV3.wrap_collection(context, refs)
Esempio n. 22
0
 def test_admin_version_v2(self):
     client = self.client(self.admin_app)
     resp = client.get('/v2.0/')
     self.assertEqual(resp.status_int, 200)
     data = jsonutils.loads(resp.body)
     expected = v2_VERSION_RESPONSE
     self._paste_in_port(expected['version'],
                         'http://localhost:%s/v2.0/' % CONF.admin_port)
     self.assertEqual(data, expected)
Esempio n. 23
0
 def test_convert_token_list_from_json(self):
     token_list = ','.join(['"%s"' % uuid.uuid4().hex for x in xrange(5)])
     token_list_loaded = jsonutils.loads('[%s]' % token_list)
     converted_list = self.token_api.driver._convert_user_index_from_json(
         token_list, 'test-key')
     for idx, item in enumerate(converted_list):
         token_id, expiry = item
         self.assertEqual(token_id, token_list_loaded[idx])
         self.assertIsInstance(expiry, datetime.datetime)
Esempio n. 24
0
 def _apply_mapping_filter(self, identity_provider, protocol, assertion):
     mapping = self.federation_api.get_mapping_from_idp_and_protocol(
         identity_provider, protocol)
     rules = jsonutils.loads(mapping['rules'])
     rule_processor = utils.RuleProcessor(rules)
     mapped_properties = rule_processor.process(assertion)
     utils.validate_groups(mapped_properties['group_ids'],
                           mapping['id'], self.identity_api)
     return mapped_properties
Esempio n. 25
0
    def test_query_string_available(self):
        class FakeApp(wsgi.Application):
            def index(self, context):
                return context["query_string"]

        app = FakeApp()
        req = self._make_request(url="/?1=2")
        resp = req.get_response(app)
        self.assertEqual(jsonutils.loads(resp.body), {"1": "2"})
Esempio n. 26
0
 def test_xml_replaced_by_json(self):
     """XML requests should be replaced by JSON requests."""
     req = make_request(
         body='<container><element attribute="value" /></container>',
         content_type='application/xml',
         method='POST')
     middleware.XmlBodyMiddleware(None).process_request(req)
     self.assertTrue(req.content_type, 'application/json')
     self.assertTrue(jsonutils.loads(req.body))
Esempio n. 27
0
    def _populate_roles(self, token_data, user_id, domain_id, project_id, trust, access_token):
        if "roles" in token_data:
            # no need to repopulate roles
            return

        if access_token:
            filtered_roles = []
            authed_role_ids = jsonutils.loads(access_token["role_ids"])
            all_roles = self.assignment_api.list_roles()
            for role in all_roles:
                for authed_role in authed_role_ids:
                    if authed_role == role["id"]:
                        filtered_roles.append({"id": role["id"], "name": role["name"]})
            token_data["roles"] = filtered_roles
            return

        if CONF.trust.enabled and trust:
            token_user_id = trust["trustor_user_id"]
            token_project_id = trust["project_id"]
            # trusts do not support domains yet
            token_domain_id = None
        else:
            token_user_id = user_id
            token_project_id = project_id
            token_domain_id = domain_id

        if token_domain_id or token_project_id:
            roles = self._get_roles_for_user(token_user_id, token_domain_id, token_project_id)
            filtered_roles = []
            if CONF.trust.enabled and trust:
                for trust_role in trust["roles"]:
                    match_roles = [x for x in roles if x["id"] == trust_role["id"]]
                    if match_roles:
                        filtered_roles.append(match_roles[0])
                    else:
                        raise exception.Forbidden(_("Trustee has no delegated roles."))
            else:
                for role in roles:
                    filtered_roles.append({"id": role["id"], "name": role["name"]})

            # user has no project or domain roles, therefore access denied
            if not filtered_roles:
                if token_project_id:
                    msg = _("User %(user_id)s has no access " "to project %(project_id)s") % {
                        "user_id": user_id,
                        "project_id": token_project_id,
                    }
                else:
                    msg = _("User %(user_id)s has no access " "to domain %(domain_id)s") % {
                        "user_id": user_id,
                        "domain_id": token_domain_id,
                    }
                LOG.debug(msg)
                raise exception.Unauthorized(msg)

            token_data["roles"] = filtered_roles
Esempio n. 28
0
def get_blob_from_credential(credential):
    try:
        blob = jsonutils.loads(credential.blob)
    except (ValueError, TypeError):
        raise exception.ValidationError(
            message=_('Invalid blob in credential'))
    if not blob or not isinstance(blob, dict):
        raise exception.ValidationError(attribute='blob',
                                        target='credential')
    return blob
Esempio n. 29
0
 def test_use_site_url_if_endpoint_unset_v3(self):
     self.config_fixture.config(public_endpoint=None, admin_endpoint=None)
     for app in (self.public_app, self.admin_app):
         client = self.client(app)
         resp = client.get('/v3/')
         self.assertEqual(resp.status_int, 200)
         data = jsonutils.loads(resp.body)
         expected = v3_VERSION_RESPONSE
         self._paste_in_port(expected['version'], 'http://localhost/v3/')
         self.assertEqual(data, expected)
Esempio n. 30
0
 def test_public_version_v3(self):
     print CONF.public_port
     client = self.client(self.public_app)
     resp = client.get('/v3/')
     self.assertEqual(resp.status_int, 200)
     data = jsonutils.loads(resp.body)
     expected = v3_VERSION_RESPONSE
     self._paste_in_port(expected['version'],
                         'http://localhost:%s/v3/' % CONF.public_port)
     self.assertEqual(data, expected)
Esempio n. 31
0
 def main():
     from keystone.common.sql import nova
     dump_data = jsonutils.loads(open(CONF.command.dump_file).read())
     nova.import_auth(dump_data)
Esempio n. 32
0
 def process_result_value(self, value, dialect):
     return jsonutils.loads(value)
Esempio n. 33
0
 def test_403_title(self):
     e = exception.Forbidden()
     resp = wsgi.render_exception(e)
     j = jsonutils.loads(resp.body)
     self.assertEqual('Forbidden', e.title)
     self.assertEqual('Forbidden', j['error'].get('title'))
Esempio n. 34
0
 def assertValidMapping(self, entity, ref=None):
     self.assertIsNotNone(entity.get('id'))
     self.assertIsNotNone(entity.get('rules'))
     if ref:
         self.assertEqual(jsonutils.loads(entity['rules']), ref['rules'])
     return entity
Esempio n. 35
0
 def assert_attributes(self, body, attr):
     """Asserts that the given request has a certain set attributes."""
     ref = jsonutils.loads(body)
     self._require_attributes(ref, attr)
Esempio n. 36
0
 def list_revoked_tokens(self):
     list_json = self.client.get(self.revocation_key)
     if list_json:
         return jsonutils.loads('[%s]' % list_json)
     return []
Esempio n. 37
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. 38
0
    def __call__(self, environ, start_response):
        """Handle incoming request. authenticate and send downstream."""
        req = webob.Request(environ)
        self.logger.debug('Calling S3Token middleware.')

        try:
            parts = swift_utils.split_path(req.path, 1, 4, True)
            version, account, container, obj = parts
        except ValueError:
            msg = 'Not a path query, skipping.'
            self.logger.debug(msg)
            return self.app(environ, start_response)

        # Read request signature and access id.
        if not 'Authorization' in req.headers:
            msg = 'No Authorization header. skipping.'
            self.logger.debug(msg)
            return self.app(environ, start_response)

        token = req.headers.get('X-Auth-Token',
                                req.headers.get('X-Storage-Token'))
        if not token:
            msg = 'You did not specify a auth or a storage token. skipping.'
            self.logger.debug(msg)
            return self.app(environ, start_response)

        auth_header = req.headers['Authorization']
        try:
            access, signature = auth_header.split(' ')[-1].rsplit(':', 1)
        except (ValueError):
            msg = 'You have an invalid Authorization header: %s'
            self.logger.debug(msg % (auth_header))
            return self.deny_request('InvalidURI')(environ, start_response)

        # NOTE(chmou): This is to handle the special case with nova
        # when we have the option s3_affix_tenant. We will force it to
        # connect to another account than the one
        # authenticated. Before people start getting worried about
        # security, I should point that we are connecting with
        # username/token specified by the user but instead of
        # connecting to its own account we will force it to go to an
        # another account. In a normal scenario if that user don't
        # have the reseller right it will just fail but since the
        # reseller account can connect to every account it is allowed
        # by the swift_auth middleware.
        force_tenant = None
        if ':' in access:
            access, force_tenant = access.split(':')

        # Authenticate request.
        creds = {
            'credentials': {
                'access': access,
                'token': token,
                'signature': signature
            }
        }
        creds_json = jsonutils.dumps(creds)
        self.logger.debug('Connecting to Keystone sending this JSON: %s' %
                          creds_json)
        # NOTE(vish): We could save a call to keystone by having
        #             keystone return token, tenant, user, and roles
        #             from this call.
        #
        # NOTE(chmou): We still have the same problem we would need to
        #              change token_auth to detect if we already
        #              identified and not doing a second query and just
        #              pass it thru to swiftauth in this case.
        try:
            resp, output = self._json_request(creds_json)
        except ServiceError as e:
            resp = e.args[0]
            msg = 'Received error, exiting middleware with error: %s'
            self.logger.debug(msg % (resp.status))
            return resp(environ, start_response)

        self.logger.debug('Keystone Reply: Status: %d, Output: %s' %
                          (resp.status, output))

        try:
            identity_info = jsonutils.loads(output)
            token_id = str(identity_info['access']['token']['id'])
            tenant = identity_info['access']['token']['tenant']
        except (ValueError, KeyError):
            error = 'Error on keystone reply: %d %s'
            self.logger.debug(error % (resp.status, str(output)))
            return self.deny_request('InvalidURI')(environ, start_response)

        req.headers['X-Auth-Token'] = token_id
        tenant_to_connect = force_tenant or tenant['id']
        self.logger.debug('Connecting with tenant: %s' % (tenant_to_connect))
        new_tenant_name = '%s%s' % (self.reseller_prefix, tenant_to_connect)
        environ['PATH_INFO'] = environ['PATH_INFO'].replace(
            account, new_tenant_name)
        return self.app(environ, start_response)
Esempio n. 39
0
def _deserialize(data):
    """Deserialization wrapper."""
    LOG.debug(_("Deserializing: %s"), data)
    return jsonutils.loads(data)
Esempio n. 40
0
    def _populate_roles(self, token_data, user_id, domain_id, project_id,
                        trust, access_token):
        if 'roles' in token_data:
            # no need to repopulate roles
            return

        if access_token:
            filtered_roles = []
            authed_role_ids = jsonutils.loads(access_token['role_ids'])
            all_roles = self.assignment_api.list_roles()
            for role in all_roles:
                for authed_role in authed_role_ids:
                    if authed_role == role['id']:
                        filtered_roles.append({
                            'id': role['id'],
                            'name': role['name']
                        })
            token_data['roles'] = filtered_roles
            return

        if CONF.trust.enabled and trust:
            token_user_id = trust['trustor_user_id']
            token_project_id = trust['project_id']
            # trusts do not support domains yet
            token_domain_id = None
        else:
            token_user_id = user_id
            token_project_id = project_id
            token_domain_id = domain_id

        if token_domain_id or token_project_id:
            roles = self._get_roles_for_user(token_user_id, token_domain_id,
                                             token_project_id)
            filtered_roles = []
            if CONF.trust.enabled and trust:
                for trust_role in trust['roles']:
                    match_roles = [
                        x for x in roles if x['id'] == trust_role['id']
                    ]
                    if match_roles:
                        filtered_roles.append(match_roles[0])
                    else:
                        raise exception.Forbidden(
                            _('Trustee has no delegated roles.'))
            else:
                for role in roles:
                    filtered_roles.append({
                        'id': role['id'],
                        'name': role['name']
                    })

            # user has no project or domain roles, therefore access denied
            if not filtered_roles:
                if token_project_id:
                    msg = _('User %(user_id)s has no access '
                            'to project %(project_id)s') % {
                                'user_id': user_id,
                                'project_id': token_project_id
                            }
                else:
                    msg = _('User %(user_id)s has no access '
                            'to domain %(domain_id)s') % {
                                'user_id': user_id,
                                'domain_id': token_domain_id
                            }
                LOG.debug(msg)
                raise exception.Unauthorized(msg)

            token_data['roles'] = filtered_roles