def request(self, method, path, **kwargs): """Fakes out several http responses. If a POST request is made, we assume the calling code is trying to get a new admin token. If a GET request is made to validate a token, return success if the token is 'token1'. If a different token is provided, return a 404, indicating an unknown (therefore unauthorized) token. """ FakeHTTPConnection.last_requested_url = path if method == 'POST': status = 200 body = jsonutils.dumps({ 'access': { 'token': {'id': 'admin_token2'}, }, }) else: token_id = path.rsplit('/', 1)[1] if token_id in TOKEN_RESPONSES.keys(): status = 200 body = jsonutils.dumps(TOKEN_RESPONSES[token_id]) elif token_id == "revoked": status = 200 body = SIGNED_REVOCATION_LIST else: status = 404 body = str() self.resp = FakeHTTPResponse(status, body)
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, client_fixtures.REVOCATION_LIST)
def test_discovery_uses_plugin_cache(self): # register responses such that if the discovery URL is hit more than # once then the response will be invalid and not point to COMPUTE_ADMIN disc_body = jsonutils.dumps(self.TEST_DISCOVERY) disc_responses = [ httpretty.Response(body=disc_body, status=200), httpretty.Response(body='', status=500) ] httpretty.register_uri(httpretty.GET, self.TEST_COMPUTE_ADMIN, responses=disc_responses) body = 'SUCCESS' self.stub_url(httpretty.GET, ['path'], body=body, status=200) # now either of the two sessions I use, it should not cause a second # request to the discovery url. sa = session.Session() sb = session.Session() auth = self.create_auth_plugin() for sess in (sa, sb): resp = sess.get('/path', auth=auth, endpoint_filter={ 'service_type': 'compute', 'interface': 'admin', 'version': self.version }) self.assertEqual(200, resp.status_code) self.assertEqual(body, resp.text)
def test_send_authn_response_to_sp(self): self.simple_http( 'POST', self.SHIB_CONSUMER_URL, body=jsonutils.dumps(saml2_fixtures.UNSCOPED_TOKEN), content_type='application/json', status=200, headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER}) self.saml2plugin.relay_state = etree.XML( saml2_fixtures.SP_SOAP_RESPONSE).xpath( self.ECP_RELAY_STATE, namespaces=self.ECP_SAML2_NAMESPACES)[0] self.saml2plugin.saml2_idp_authn_response = etree.XML( saml2_fixtures.SAML2_ASSERTION) self.saml2plugin.idp_response_consumer_url = self.SHIB_CONSUMER_URL self.saml2plugin._send_service_provider_saml2_authn_response( self.session) token_json = self.saml2plugin.authenticated_response.json()['token'] token = self.saml2plugin.authenticated_response.headers[ 'X-Subject-Token'] self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN['token'], token_json) self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN_HEADER, token)
def setUpModule(self): signing_path = CMSDIR with open(os.path.join(signing_path, 'auth_token_scoped.pem')) as f: self.SIGNED_TOKEN_SCOPED = cms.cms_to_token(f.read()) with open(os.path.join(signing_path, 'auth_token_unscoped.pem')) as f: self.SIGNED_TOKEN_UNSCOPED = cms.cms_to_token(f.read()) with open(os.path.join(signing_path, 'auth_token_revoked.pem')) as f: self.REVOKED_TOKEN = cms.cms_to_token(f.read()) self.REVOKED_TOKEN_HASH = utils.hash_signed_token(self.REVOKED_TOKEN) with open(os.path.join(signing_path, 'revocation_list.json')) as f: self.REVOCATION_LIST = jsonutils.loads(f.read()) with open(os.path.join(signing_path, 'revocation_list.pem')) as f: self.VALID_SIGNED_REVOCATION_LIST = jsonutils.dumps( {'signed': f.read()}) self.SIGNED_TOKEN_SCOPED_KEY =\ cms.cms_hash_token(self.SIGNED_TOKEN_SCOPED) self.SIGNED_TOKEN_UNSCOPED_KEY =\ cms.cms_hash_token(self.SIGNED_TOKEN_UNSCOPED) self.TOKEN_RESPONSES[self.SIGNED_TOKEN_SCOPED_KEY] = { 'access': { 'token': { 'id': self.SIGNED_TOKEN_SCOPED_KEY, }, 'user': { 'id': 'user_id1', 'name': 'user_name1', 'tenantId': 'tenant_id1', 'tenantName': 'tenant_name1', 'roles': [ { 'name': 'role1' }, { 'name': 'role2' }, ], }, }, } self.TOKEN_RESPONSES[SIGNED_TOKEN_UNSCOPED_KEY] = { 'access': { 'token': { 'id': SIGNED_TOKEN_UNSCOPED_KEY, }, 'user': { 'id': 'user_id1', 'name': 'user_name1', 'roles': [ { 'name': 'role1' }, { 'name': 'role2' }, ], }, }, },
def test_lesser_version_than_required(self): versions = fixture.DiscoveryList(BASE_URL, v3_id='v3.4') httpretty.register_uri(httpretty.GET, BASE_URL, status=200, body=jsonutils.dumps(versions)) self.assertVersionNotAvailable(auth_url=BASE_URL, version=(3, 6))
def test_create_access_token_expires_at(self): verifier = uuid.uuid4().hex consumer_key = uuid.uuid4().hex consumer_secret = uuid.uuid4().hex request_key = uuid.uuid4().hex request_secret = uuid.uuid4().hex t = self._new_oauth_token_with_expires_at() access_key, access_secret, expires_at, resp_ref = t # NOTE(stevemar) The server expects the body to be JSON. Even though # the resp_ref is a string it is not a JSON string. self.stub_url(httpretty.POST, [self.path_prefix, 'access_token'], status=201, body=jsonutils.dumps(resp_ref), content_type='application/x-www-form-urlencoded') # Assert that the manager creates an access token object access_token = self.manager.create(consumer_key, consumer_secret, request_key, request_secret, verifier) self.assertIsInstance(access_token, self.model) self.assertEqual(access_key, access_token.key) self.assertEqual(access_secret, access_token.secret) self.assertEqual(expires_at, access_token.expires) req_headers = httpretty.last_request().headers oauth_client = oauth1.Client(consumer_key, client_secret=consumer_secret, resource_owner_key=request_key, resource_owner_secret=request_secret, signature_method=oauth1.SIGNATURE_HMAC, verifier=verifier, timestamp=expires_at) self._validate_oauth_headers(req_headers['Authorization'], oauth_client)
def _http_log_response(self, response=None, json=None, status_code=None, headers=None, text=None): if not _logger.isEnabledFor(logging.DEBUG): return if response: if not status_code: status_code = response.status_code if not headers: headers = response.headers if not text: text = response.text if json: text = jsonutils.dumps(json) string_parts = ['RESP:'] if status_code: string_parts.append('[%s]' % status_code) if headers: for header in six.iteritems(headers): string_parts.append('%s: %s' % Session.process_header(header)) if text: string_parts.append('\nRESP BODY: %s\n' % text) _logger.debug(' '.join(string_parts))
def _json_request(self, method, path, body=None, additional_headers=None): """HTTP request helper used to make json requests. :param method: http method :param path: relative request url :param body: dict to encode to json as request body. Optional. :param additional_headers: dict of additional headers to send with http request. Optional. :return (http response object, response body parsed as json) :raise ServerError when unable to communicate with keystone """ conn = self._get_http_connection() kwargs = { 'headers': { 'Content-type': 'application/json', 'Accept': 'application/json', }, } if additional_headers: kwargs['headers'].update(additional_headers) if body: kwargs['body'] = jsonutils.dumps(body) full_path = self.auth_admin_prefix + path try: conn.request(method, full_path, **kwargs) response = conn.getresponse() body = response.read() except Exception, e: self.logger.error('HTTP connection exception: %s' % e) raise ServiceError('Unable to communicate with keystone')
def _http_log_request(self, url, method=None, data=None, json=None, headers=None): if not _logger.isEnabledFor(logging.DEBUG): # NOTE(morganfainberg): This whole debug section is expensive, # there is no need to do the work if we're not going to emit a # debug log. return string_parts = ['REQ: curl -i'] # NOTE(jamielennox): None means let requests do its default validation # so we need to actually check that this is False. if self.verify is False: string_parts.append('--insecure') if method: string_parts.extend(['-X', method]) string_parts.append(url) if headers: for header in six.iteritems(headers): string_parts.append('-H "%s: %s"' % Session.process_header(header)) if json: data = jsonutils.dumps(json) if data: string_parts.append("-d '%s'" % data) _logger.debug(' '.join(string_parts))
def test_available_cinder_data(self): body = jsonutils.dumps(CINDER_EXAMPLES) httpretty.register_uri(httpretty.GET, BASE_URL, status=300, body=body) v1_url = "%sv1/" % BASE_URL v2_url = "%sv2/" % BASE_URL disc = discover.Discover(auth_url=BASE_URL) versions = disc.version_data() self.assertEqual((1, 0), versions[0]['version']) self.assertEqual('CURRENT', versions[0]['raw_status']) self.assertEqual(v1_url, versions[0]['url']) self.assertEqual((2, 0), versions[1]['version']) self.assertEqual('CURRENT', versions[1]['raw_status']) self.assertEqual(v2_url, versions[1]['url']) version = disc.data_for('v2.0') self.assertEqual((2, 0), version['version']) self.assertEqual('CURRENT', version['raw_status']) self.assertEqual(v2_url, version['url']) version = disc.data_for(1) self.assertEqual((1, 0), version['version']) self.assertEqual('CURRENT', version['raw_status']) self.assertEqual(v1_url, version['url']) self.assertIsNone(disc.url_for('v3')) self.assertEqual(v2_url, disc.url_for('v2')) self.assertEqual(v1_url, disc.url_for('v1'))
def test_is_signed_token_revoked_returns_false(self): #explicitly setting an empty revocation list here to document intent self.middleware.token_revocation_list = jsonutils.dumps( {"revoked": [], "extra": "success"}) result = self.middleware.is_signed_token_revoked( self.token_dict['revoked_token']) self.assertFalse(result)
def _cache_store(self, token_id, data): """Store value into memcache. data may be the string 'invalid' or a tuple like (data, expires) """ serialized_data = jsonutils.dumps(data) if self._memcache_security_strategy is None: cache_key = CACHE_KEY_TEMPLATE % token_id data_to_store = serialized_data else: keys = memcache_crypt.derive_keys( token_id, self._memcache_secret_key, self._memcache_security_strategy) cache_key = CACHE_KEY_TEMPLATE % memcache_crypt.get_cache_key(keys) data_to_store = memcache_crypt.protect_data(keys, serialized_data) # Historically the swift cache conection used the argument # timeout= for the cache timeout, but this has been unified # with the official python memcache client with time= since # grizzly, we still need to handle folsom for a while until # this could get removed. try: self._cache.set(cache_key, data_to_store, time=self.token_cache_time) except(TypeError): self._cache.set(cache_key, data_to_store, timeout=self.token_cache_time)
def test_allow_experimental(self): status = 'experimental' version_list = [{ 'id': 'v3.0', 'links': [{ 'href': V3_URL, 'rel': 'self' }], 'media-types': V3_MEDIA_TYPES, 'status': status, 'updated': UPDATED }] body = jsonutils.dumps({'versions': version_list}) httpretty.register_uri(httpretty.GET, BASE_URL, status=200, body=body) disc = discover.Discover(auth_url=BASE_URL) versions = disc.version_data() self.assertEqual(0, len(versions)) versions = disc.version_data(allow_experimental=True) self.assertEqual(1, len(versions)) self.assertEqual(status, versions[0]['raw_status']) self.assertEqual(V3_URL, versions[0]['url']) self.assertEqual((3, 0), versions[0]['version'])
def _http_log_request(self, url, method=None, data=None, json=None, headers=None): if not _logger.isEnabledFor(logging.DEBUG): # NOTE(morganfainberg): This whole debug section is expensive, # there is no need to do the work if we're not going to emit a # debug log. return string_parts = ['REQ: curl -i'] # NOTE(jamielennox): None means let requests do its default validation # so we need to actually check that this is False. if self.verify is False: string_parts.append('--insecure') if method: string_parts.extend(['-X', method]) string_parts.append(url) if headers: for header in six.iteritems(headers): string_parts.append('-H "%s: %s"' % Session.process_header(header)) if json: data = jsonutils.dumps(json) if data: string_parts.append("-d '%s'" % data) _logger.debug(' '.join(string_parts))
def test_ignoring_invalid_lnks(self): version_list = [{'id': 'v3.0', 'links': [{'href': V3_URL, 'rel': 'self'}], 'media-types': V3_MEDIA_TYPES, 'status': 'stable', 'updated': UPDATED}, {'id': 'v3.1', 'media-types': V3_MEDIA_TYPES, 'status': 'stable', 'updated': UPDATED}, {'media-types': V3_MEDIA_TYPES, 'status': 'stable', 'updated': UPDATED, 'links': [{'href': V3_URL, 'rel': 'self'}], }] body = jsonutils.dumps({'versions': version_list}) httpretty.register_uri(httpretty.GET, BASE_URL, status=200, body=body) disc = discover.Discover(auth_url=BASE_URL) # raw_version_data will return all choices, even invalid ones versions = disc.raw_version_data() self.assertEqual(3, len(versions)) # only the version with both id and links will be actually returned versions = disc.version_data() self.assertEqual(1, len(versions))
def test_discovery_uses_plugin_cache(self): # register responses such that if the discovery URL is hit more than # once then the response will be invalid and not point to COMPUTE_ADMIN disc_body = jsonutils.dumps(self.TEST_DISCOVERY) disc_responses = [httpretty.Response(body=disc_body, status=200), httpretty.Response(body='', status=500)] httpretty.register_uri(httpretty.GET, self.TEST_COMPUTE_ADMIN, responses=disc_responses) body = 'SUCCESS' self.stub_url(httpretty.GET, ['path'], body=body, status=200) # now either of the two sessions I use, it should not cause a second # request to the discovery url. sa = session.Session() sb = session.Session() auth = self.create_auth_plugin() for sess in (sa, sb): resp = sess.get('/path', auth=auth, endpoint_filter={'service_type': 'compute', 'interface': 'admin', 'version': self.version}) self.assertEqual(200, resp.status_code) self.assertEqual(body, resp.text)
def test_available_versions_basics(self): examples = {'keystone': V3_VERSION_LIST, 'cinder': jsonutils.dumps(CINDER_EXAMPLES), 'glance': jsonutils.dumps(GLANCE_EXAMPLES)} for path, ex in six.iteritems(examples): url = "%s%s" % (BASE_URL, path) httpretty.register_uri(httpretty.GET, url, status=300, body=ex) versions = discover.available_versions(url) for v in versions: for n in ('id', 'status', 'links'): msg = '%s missing from %s version data' % (n, path) self.assertThat(v, matchers.Annotate(msg, matchers.Contains(n)))
def test_create_request_token(self): project_id = uuid.uuid4().hex consumer_key = uuid.uuid4().hex consumer_secret = uuid.uuid4().hex request_key, request_secret, resp_ref = self._new_oauth_token() # NOTE(stevemar) The server expects the body to be JSON. Even though # the resp_ref is a string it is not a JSON string. self.stub_url(httpretty.POST, [self.path_prefix, 'request_token'], status=201, body=jsonutils.dumps(resp_ref), content_type='application/x-www-form-urlencoded') # Assert the manager is returning request token object request_token = self.manager.create(consumer_key, consumer_secret, project_id) self.assertIsInstance(request_token, self.model) self.assertEqual(request_key, request_token.key) self.assertEqual(request_secret, request_token.secret) # Assert that the project id is in the header self.assertRequestHeaderEqual('requested_project_id', project_id) req_headers = httpretty.last_request().headers oauth_client = oauth1.Client(consumer_key, client_secret=consumer_secret, signature_method=oauth1.SIGNATURE_HMAC, callback_uri="oob") self._validate_oauth_headers(req_headers['Authorization'], oauth_client)
def test_allow_deprecated(self): status = 'deprecated' version_list = [{ 'id': 'v3.0', 'links': [{ 'href': V3_URL, 'rel': 'self' }], 'media-types': V3_MEDIA_TYPES, 'status': status, 'updated': UPDATED }] text = jsonutils.dumps({'versions': version_list}) self.requests.register_uri('GET', BASE_URL, status_code=200, text=text) disc = discover.Discover(auth_url=BASE_URL) # deprecated is allowed by default versions = disc.version_data(allow_deprecated=False) self.assertEqual(0, len(versions)) versions = disc.version_data(allow_deprecated=True) self.assertEqual(1, len(versions)) self.assertEqual(status, versions[0]['raw_status']) self.assertEqual(V3_URL, versions[0]['url']) self.assertEqual((3, 0), versions[0]['version'])
def test_available_cinder_data(self): body = jsonutils.dumps(CINDER_EXAMPLES) httpretty.register_uri(httpretty.GET, BASE_URL, status=300, body=body) v1_url = "%sv1/" % BASE_URL v2_url = "%sv2/" % BASE_URL disc = discover.Discover(auth_url=BASE_URL) versions = disc.version_data() self.assertEqual((1, 0), versions[0]['version']) self.assertEqual('CURRENT', versions[0]['raw_status']) self.assertEqual(v1_url, versions[0]['url']) self.assertEqual((2, 0), versions[1]['version']) self.assertEqual('CURRENT', versions[1]['raw_status']) self.assertEqual(v2_url, versions[1]['url']) version = disc.data_for('v2.0') self.assertEqual((2, 0), version['version']) self.assertEqual('CURRENT', version['raw_status']) self.assertEqual(v2_url, version['url']) version = disc.data_for(1) self.assertEqual((1, 0), version['version']) self.assertEqual('CURRENT', version['raw_status']) self.assertEqual(v1_url, version['url']) self.assertIsNone(disc.url_for('v3')) self.assertEqual(v2_url, disc.url_for('v2')) self.assertEqual(v1_url, disc.url_for('v1'))
def test_greater_version_than_required(self): versions = fixture.DiscoveryList(BASE_URL, v3_id='v3.6') httpretty.register_uri(httpretty.GET, BASE_URL, status=200, body=jsonutils.dumps(versions)) self.assertCreatesV3(auth_url=BASE_URL, version=(3, 4))
def _http_log_response(self, response=None, json=None, status_code=None, headers=None, text=None): if not _logger.isEnabledFor(logging.DEBUG): return if response: if not status_code: status_code = response.status_code if not headers: headers = response.headers if not text: text = response.text if json: text = jsonutils.dumps(json) string_parts = ['RESP:'] if status_code: string_parts.append('[%s]' % status_code) if headers: string_parts.append('%s' % headers) if text: string_parts.append('\nRESP BODY: %s\n' % text) _logger.debug(' '.join(string_parts))
def test_list(self, ref_list=None, expected_path=None, expected_query=None, **filter_kwargs): ref_list = ref_list or [self.new_ref(), self.new_ref()] expected_path = self._get_expected_path(expected_path) httpretty.register_uri(httpretty.GET, urlparse.urljoin(self.TEST_URL, expected_path), body=jsonutils.dumps(self.encode(ref_list))) returned_list = self.manager.list(**filter_kwargs) self.assertEqual(len(ref_list), len(returned_list)) [self.assertIsInstance(r, self.model) for r in returned_list] # register_uri doesn't match the querystring component, so we have to # explicitly test the querystring component passed by the manager qs_args = httpretty.last_request().querystring qs_args_expected = expected_query or filter_kwargs for key, value in six.iteritems(qs_args_expected): self.assertIn(key, qs_args) # The httppretty.querystring value is a list # Note we convert the value to a string, as the query string # is always a string and the filter_kwargs may contain non-string # values, for example a boolean, causing the comaprison to fail. self.assertIn(str(value), qs_args[key]) # Also check that no query string args exist which are not expected for key in qs_args: self.assertIn(key, qs_args_expected)
def test_list(self, ref_list=None, expected_path=None, expected_query=None, **filter_kwargs): ref_list = ref_list or [self.new_ref(), self.new_ref()] expected_path = self._get_expected_path(expected_path) httpretty.register_uri(httpretty.GET, urlparse.urljoin(self.TEST_URL, expected_path), body=jsonutils.dumps(self.encode(ref_list))) returned_list = self.manager.list(**filter_kwargs) self.assertEqual(len(ref_list), len(returned_list)) [self.assertIsInstance(r, self.model) for r in returned_list] # register_uri doesn't match the querystring component, so we have to # explicitly test the querystring component passed by the manager qs_args = httpretty.last_request().querystring qs_args_expected = expected_query or filter_kwargs for key, value in six.iteritems(qs_args_expected): self.assertIn(key, qs_args) # The httppretty.querystring value is a list # Note we convert the value to a string, as the query string # is always a string and the filter_kwargs may contain non-string # values, for example a boolean, causing the comaprison to fail. self.assertIn(str(value), qs_args[key]) # Also check that no query string args exist which are not expected for key in qs_args: self.assertIn(key, qs_args_expected)
def setUp(self, expected_env=None): expected_env = expected_env or {} conf = { 'admin_token': 'admin_token1', 'auth_host': 'keystone.example.com', 'auth_port': 1234, 'auth_admin_prefix': '/testadmin', 'signing_dir': CERTDIR, } self.middleware = auth_token.AuthProtocol(FakeApp(expected_env), conf) self.middleware.http_client_class = FakeHTTPConnection self.middleware._iso8601 = iso8601 self.response_status = None self.response_headers = None self.middleware.revoked_file_name = tempfile.mkstemp()[1] cache_timeout = datetime.timedelta(days=1) self.middleware.token_revocation_list_cache_timeout = cache_timeout self.middleware.token_revocation_list = jsonutils.dumps( {"revoked": [], "extra": "success"}) signed_list = 'SIGNED_REVOCATION_LIST' valid_signed_list = 'VALID_SIGNED_REVOCATION_LIST' globals()[signed_list] = globals()[valid_signed_list] super(BaseAuthTokenMiddlewareTest, self).setUp()
def test_create_request_token(self): project_id = uuid.uuid4().hex consumer_key = uuid.uuid4().hex consumer_secret = uuid.uuid4().hex request_key, request_secret, resp_ref = self._new_oauth_token() # NOTE(stevemar) The server expects the body to be JSON. Even though # the resp_ref is a string it is not a JSON string. self.stub_url(httpretty.POST, [self.path_prefix, 'request_token'], status=201, body=jsonutils.dumps(resp_ref), content_type='application/x-www-form-urlencoded') # Assert the manager is returning request token object request_token = self.manager.create(consumer_key, consumer_secret, project_id) self.assertIsInstance(request_token, self.model) self.assertEqual(request_key, request_token.key) self.assertEqual(request_secret, request_token.secret) # Assert that the project id is in the header self.assertRequestHeaderEqual('requested_project_id', project_id) req_headers = httpretty.last_request().headers oauth_client = oauth1.Client(consumer_key, client_secret=consumer_secret, signature_method=oauth1.SIGNATURE_HMAC, callback_uri="oob") self._validate_oauth_headers(req_headers['Authorization'], oauth_client)
def test_is_signed_token_revoked_returns_false(self): #explicitly setting an empty revocation list here to document intent self.middleware.token_revocation_list = jsonutils.dumps( {"revoked": [], "extra": "success"}) result = self.middleware.is_signed_token_revoked( self.token_dict['revoked_token']) self.assertFalse(result)
def request(self, method, path, **kwargs): """Fakes out several http responses. Support the following requests: - Create admin token ('POST /testadmin/v2.0/tokens') - Get versions ('GET /testadmin/') - Get v2 user token responses (see fake_v2_responses) - Get v3 user token responses (see fake_v3_responses) """ v3FakeHTTPConnection.last_requested_url = path if method == 'POST' and path == '/testadmin/v2.0/tokens': status, body = self.fake_v2_admin_token(path) else: if path == '/testadmin/': # It's a GET versions call status = 300 body = jsonutils.dumps(VERSION_LIST_v3) elif path.split('/')[2] == 'v2.0': status, body = self.fake_v2_responses(path) else: status, body = self.fake_v3_responses(path, **kwargs) self.resp = FakeHTTPResponse(status, body)
def _cache_store(self, policy): """Store value into memcache. data may be the string 'invalid' or a tuple like (data, expires) """ serialized_data = jsonutils.dumps(policy['blob']) if self._memcache_security_strategy is None: cache_key = CACHE_KEY_TEMPLATE data_to_store = (policy['timestamp'],serialized_data) else: keys = memcache_crypt.derive_keys( token, self._memcache_secret_key, self._memcache_security_strategy) cache_key = CACHE_KEY_TEMPLATE % memcache_crypt.get_cache_key(keys) data_to_store = memcache_crypt.protect_data(keys, serialized_data) try: self._cache.set(cache_key, data_to_store, time=self.policy_cache_time) except(TypeError): self._cache.set(cache_key, data_to_store, timeout=self.policy_cache_time)
def _http_log_request(self, url, method=None, data=None, json=None, headers=None): if not _logger.isEnabledFor(logging.DEBUG): # NOTE(morganfainberg): This whole debug section is expensive, # there is no need to do the work if we're not going to emit a # debug log. return def process_header(header): secure_headers = ("authorization", "x-auth-token", "x-subject-token") if header[0].lower() in secure_headers: return (header[0], "TOKEN_REDACTED") return header string_parts = ["REQ: curl -i"] # NOTE(jamielennox): None means let requests do its default validation # so we need to actually check that this is False. if self.verify is False: string_parts.append("--insecure") if method: string_parts.extend(["-X", method]) string_parts.append(url) if headers: for header in six.iteritems(headers): string_parts.append('-H "%s: %s"' % process_header(header)) if json: data = jsonutils.dumps(json) if data: string_parts.append("-d '%s'" % data) _logger.debug(" ".join(string_parts))
def _cache_store(self, token_id, data): """Store value into memcache. data may be the string 'invalid' or a tuple like (data, expires) """ serialized_data = jsonutils.dumps(data) if self._memcache_security_strategy is None: cache_key = CACHE_KEY_TEMPLATE % token_id data_to_store = serialized_data else: keys = memcache_crypt.derive_keys(token_id, self._memcache_secret_key, self._memcache_security_strategy) cache_key = CACHE_KEY_TEMPLATE % memcache_crypt.get_cache_key(keys) data_to_store = memcache_crypt.protect_data(keys, serialized_data) # Historically the swift cache conection used the argument # timeout= for the cache timeout, but this has been unified # with the official python memcache client with time= since # grizzly, we still need to handle folsom for a while until # this could get removed. try: self._cache.set(cache_key, data_to_store, time=self.token_cache_time) except (TypeError): self._cache.set(cache_key, data_to_store, timeout=self.token_cache_time)
def test_discover_unstable_versions(self): version_list = fixture.DiscoveryList(BASE_URL, v3_status='beta') httpretty.register_uri(httpretty.GET, BASE_URL, status=300, body=jsonutils.dumps(version_list)) self.assertCreatesV2(auth_url=BASE_URL) self.assertVersionNotAvailable(auth_url=BASE_URL, version=3) self.assertCreatesV3(auth_url=BASE_URL, unstable=True)
def test_discovery_fail_for_missing_v3(self): versions = fixture.DiscoveryList(v2=True, v3=False) httpretty.register_uri(httpretty.GET, BASE_URL, status=300, body=jsonutils.dumps(versions)) disc = discover.Discover(auth_url=BASE_URL) self.assertRaises(exceptions.DiscoveryFailure, disc.create_client, version=(3, 0))
def setUpModule(self): signing_path = CMSDIR with open(os.path.join(signing_path, "auth_token_scoped.pem")) as f: self.SIGNED_TOKEN_SCOPED = cms.cms_to_token(f.read()) with open(os.path.join(signing_path, "auth_token_unscoped.pem")) as f: self.SIGNED_TOKEN_UNSCOPED = cms.cms_to_token(f.read()) with open(os.path.join(signing_path, "auth_v3_token_scoped.pem")) as f: self.SIGNED_v3_TOKEN_SCOPED = cms.cms_to_token(f.read()) with open(os.path.join(signing_path, "auth_token_revoked.pem")) as f: self.REVOKED_TOKEN = cms.cms_to_token(f.read()) self.REVOKED_TOKEN_HASH = utils.hash_signed_token(self.REVOKED_TOKEN) with open(os.path.join(signing_path, "auth_v3_token_revoked.pem")) as f: self.REVOKED_v3_TOKEN = cms.cms_to_token(f.read()) self.REVOKED_v3_TOKEN_HASH = utils.hash_signed_token(self.REVOKED_v3_TOKEN) with open(os.path.join(signing_path, "revocation_list.json")) as f: self.REVOCATION_LIST = jsonutils.loads(f.read()) with open(os.path.join(signing_path, "revocation_list.pem")) as f: self.VALID_SIGNED_REVOCATION_LIST = jsonutils.dumps({"signed": f.read()}) self.SIGNED_TOKEN_SCOPED_KEY = cms.cms_hash_token(self.SIGNED_TOKEN_SCOPED) self.SIGNED_TOKEN_UNSCOPED_KEY = cms.cms_hash_token(self.SIGNED_TOKEN_UNSCOPED) self.SIGNED_v3_TOKEN_SCOPED_KEY = cms.cms_hash_token(self.SIGNED_v3_TOKEN_SCOPED) self.TOKEN_RESPONSES[self.SIGNED_TOKEN_SCOPED_KEY] = { "access": { "token": {"id": self.SIGNED_TOKEN_SCOPED_KEY}, "user": { "id": "user_id1", "name": "user_name1", "tenantId": "tenant_id1", "tenantName": "tenant_name1", "roles": [{"name": "role1"}, {"name": "role2"}], }, } } self.TOKEN_RESPONSES[SIGNED_TOKEN_UNSCOPED_KEY] = ( { "access": { "token": {"id": SIGNED_TOKEN_UNSCOPED_KEY}, "user": {"id": "user_id1", "name": "user_name1", "roles": [{"name": "role1"}, {"name": "role2"}]}, } }, ) self.TOKEN_RESPONSES[self.SIGNED_v3_TOKEN_SCOPED_KEY] = { "token": { "expires": "2999-01-01T00:00:10Z", "user": {"id": "user_id1", "name": "user_name1", "domain": {"id": "domain_id1", "name": "domain_name1"}}, "project": { "id": "tenant_id1", "name": "tenant_name1", "domain": {"id": "domain_id1", "name": "domain_name1"}, }, "roles": [{"name": "role1"}, {"name": "role2"}], "catalog": {}, } }
def test_get_unscoped_token_when_authenticated(self): headers = {'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER} self.simple_http('GET', self.FEDERATION_AUTH_URL, body=jsonutils.dumps(saml2_fixtures.UNSCOPED_TOKEN), headers=headers) token, token_body = self.saml2plugin._get_unscoped_token(self.session) self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN['token'], token_body) self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN_HEADER, token)
def fake_v2_admin_token(self, path): status = 200 body = jsonutils.dumps({ 'access': { 'token': {'id': 'admin_token2', 'expires': '2022-10-03T16:58:01Z'} }, }) return status, body
def test_available_versions_basics(self): examples = { 'keystone': V3_VERSION_LIST, 'cinder': jsonutils.dumps(CINDER_EXAMPLES), 'glance': jsonutils.dumps(GLANCE_EXAMPLES) } for path, ex in six.iteritems(examples): url = "%s%s" % (BASE_URL, path) httpretty.register_uri(httpretty.GET, url, status=300, body=ex) versions = discover.available_versions(url) for v in versions: for n in ('id', 'status', 'links'): msg = '%s missing from %s version data' % (n, path) self.assertThat( v, matchers.Annotate(msg, matchers.Contains(n)))
def get_revocation_list_json(self, token_ids=None): if token_ids is None: token_ids = [REVOKED_TOKEN_HASH] revocation_list = { 'revoked': [{ 'id': x, 'expires': timeutils.utcnow() } for x in token_ids] } return jsonutils.dumps(revocation_list)
def getresponse(self): # If self.resp is set then this is just the response to # the earlier request. If it is not set, then we expect # a stack of responses to have been pre-prepared if self.resp: return self.resp else: if len(FAKE_RESPONSE_STACK): return FAKE_RESPONSE_STACK.pop() return FakeHTTPResponse(500, jsonutils.dumps("UNEXPECTED RESPONSE"))
def test_discover_unstable_versions(self): version_list = fixture.DiscoveryList(BASE_URL, v3_status='beta') httpretty.register_uri(httpretty.GET, BASE_URL, status=300, body=jsonutils.dumps(version_list)) self.assertCreatesV2(auth_url=BASE_URL) self.assertVersionNotAvailable(auth_url=BASE_URL, version=3) self.assertCreatesV3(auth_url=BASE_URL, unstable=True)
def test_scope_saml2_token_to_domain(self): self.simple_http('POST', self.TEST_URL + '/auth/tokens', body=jsonutils.dumps(self.DOMAIN_SCOPED_TOKEN_JSON), content_type='application/json', headers=client_fixtures.AUTH_RESPONSE_HEADERS) token = self.saml2_scope_plugin.get_auth_ref(self.session) self.assertTrue(token.domain_scoped, "Received token is not scoped") self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, token.auth_token) self.assertEqual(self.TEST_DOMAIN_ID, token.domain_id) self.assertEqual(self.TEST_DOMAIN_NAME, token.domain_name)
def test_list(self, ref_list=None, expected_path=None, **filter_kwargs): ref_list = ref_list or [self.new_ref(), self.new_ref()] expected_path = self._get_expected_path(expected_path) httpretty.register_uri(httpretty.GET, urlparse.urljoin(self.TEST_URL, expected_path), body=jsonutils.dumps(self.encode(ref_list))) returned_list = self.manager.list(**filter_kwargs) self.assertEqual(len(ref_list), len(returned_list)) [self.assertIsInstance(r, self.model) for r in returned_list]
def test_list_params(self): ref_list = [self.new_ref()] filter_kwargs = {uuid.uuid4().hex: uuid.uuid4().hex} expected_path = self._get_expected_path() httpretty.register_uri(httpretty.GET, urlparse.urljoin(self.TEST_URL, expected_path), body=jsonutils.dumps(self.encode(ref_list))) self.manager.list(**filter_kwargs) self.assertQueryStringContains(**filter_kwargs)
def test_list_params(self): ref_list = [self.new_ref()] filter_kwargs = {uuid.uuid4().hex: uuid.uuid4().hex} expected_path = self._get_expected_path() httpretty.register_uri(httpretty.GET, urlparse.urljoin(self.TEST_URL, expected_path), body=jsonutils.dumps(self.encode(ref_list))) self.manager.list(**filter_kwargs) self.assertQueryStringContains(**filter_kwargs)
def test_list(self, ref_list=None, expected_path=None, **filter_kwargs): ref_list = ref_list or [self.new_ref(), self.new_ref()] expected_path = self._get_expected_path(expected_path) httpretty.register_uri(httpretty.GET, urlparse.urljoin(self.TEST_URL, expected_path), body=jsonutils.dumps(self.encode(ref_list))) returned_list = self.manager.list(**filter_kwargs) self.assertEqual(len(ref_list), len(returned_list)) [self.assertIsInstance(r, self.model) for r in returned_list]
def getresponse(self): # If self.resp is set then this is just the response to # the earlier request. If it is not set, then we expect # a stack of responses to have been pre-prepared if self.resp: return self.resp else: if len(FAKE_RESPONSE_STACK): return FAKE_RESPONSE_STACK.pop() return FakeHTTPResponse( 500, jsonutils.dumps('UNEXPECTED RESPONSE'))
def test_discovery_fail_for_missing_v3(self): versions = fixture.DiscoveryList(v2=True, v3=False) httpretty.register_uri(httpretty.GET, BASE_URL, status=300, body=jsonutils.dumps(versions)) disc = discover.Discover(auth_url=BASE_URL) self.assertRaises(exceptions.DiscoveryFailure, disc.create_client, version=(3, 0))
def test_invalidate_response(self): resp_data1 = copy.deepcopy(self.TEST_RESPONSE_DICT) resp_data2 = copy.deepcopy(self.TEST_RESPONSE_DICT) resp_data1['access']['token']['id'] = 'token1' resp_data2['access']['token']['id'] = 'token2' auth_responses = [httpretty.Response(body=jsonutils.dumps(resp_data1), status=200), httpretty.Response(body=jsonutils.dumps(resp_data2), status=200)] self.stub_auth(responses=auth_responses) a = v2.Password(self.TEST_URL, username=self.TEST_USER, password=self.TEST_PASS) s = session.Session(auth=a) self.assertEqual('token1', s.get_token()) a.invalidate() self.assertEqual('token2', s.get_token())
def setUpModule(self): signing_path = CMSDIR with open(os.path.join(signing_path, 'auth_token_scoped.pem')) as f: self.SIGNED_TOKEN_SCOPED = cms.cms_to_token(f.read()) with open(os.path.join(signing_path, 'auth_token_unscoped.pem')) as f: self.SIGNED_TOKEN_UNSCOPED = cms.cms_to_token(f.read()) with open(os.path.join(signing_path, 'auth_token_revoked.pem')) as f: self.REVOKED_TOKEN = cms.cms_to_token(f.read()) self.REVOKED_TOKEN_HASH = utils.hash_signed_token(self.REVOKED_TOKEN) with open(os.path.join(signing_path, 'revocation_list.json')) as f: self.REVOCATION_LIST = jsonutils.loads(f.read()) with open(os.path.join(signing_path, 'revocation_list.pem')) as f: self.VALID_SIGNED_REVOCATION_LIST = jsonutils.dumps( {'signed': f.read()}) self.SIGNED_TOKEN_SCOPED_KEY =\ cms.cms_hash_token(self.SIGNED_TOKEN_SCOPED) self.SIGNED_TOKEN_UNSCOPED_KEY =\ cms.cms_hash_token(self.SIGNED_TOKEN_UNSCOPED) self.TOKEN_RESPONSES[self.SIGNED_TOKEN_SCOPED_KEY] = { 'access': { 'token': { 'id': self.SIGNED_TOKEN_SCOPED_KEY, }, 'user': { 'id': 'user_id1', 'name': 'user_name1', 'tenantId': 'tenant_id1', 'tenantName': 'tenant_name1', 'roles': [ {'name': 'role1'}, {'name': 'role2'}, ], }, }, } self.TOKEN_RESPONSES[SIGNED_TOKEN_UNSCOPED_KEY] = { 'access': { 'token': { 'id': SIGNED_TOKEN_UNSCOPED_KEY, }, 'user': { 'id': 'user_id1', 'name': 'user_name1', 'roles': [ {'name': 'role1'}, {'name': 'role2'}, ], }, }, },
def test_invalidate_response(self): resp_data1 = copy.deepcopy(self.TEST_RESPONSE_DICT) resp_data2 = copy.deepcopy(self.TEST_RESPONSE_DICT) resp_data1['access']['token']['id'] = 'token1' resp_data2['access']['token']['id'] = 'token2' auth_responses = [ httpretty.Response(body=jsonutils.dumps(resp_data1), status=200), httpretty.Response(body=jsonutils.dumps(resp_data2), status=200) ] self.stub_auth(responses=auth_responses) a = v2.Password(self.TEST_URL, username=self.TEST_USER, password=self.TEST_PASS) s = session.Session(auth=a) self.assertEqual('token1', s.get_token()) a.invalidate() self.assertEqual('token2', s.get_token())
def test_unauthorized_token(self): ret = {"error": {"message": "EC2 access key not found.", "code": 401, "title": "Unauthorized"}} httpretty.register_uri(httpretty.POST, self.TEST_URL, status=403, body=jsonutils.dumps(ret)) req = webob.Request.blank('/v1/AUTH_cfa/c/o') req.headers['Authorization'] = 'access:signature' req.headers['X-Storage-Token'] = 'token' resp = req.get_response(self.middleware) s3_denied_req = self.middleware.deny_request('AccessDenied') self.assertEqual(resp.body, s3_denied_req.body) self.assertEqual(resp.status_int, s3_denied_req.status_int)
def test_available_glance_data(self): text = jsonutils.dumps(GLANCE_EXAMPLES) self.requests.register_uri('GET', BASE_URL, status_code=200, text=text) versions = discover.available_versions(BASE_URL) self.assertEqual(5, len(versions)) for v in versions: if v['id'] in ('v2.2', 'v1.1'): self.assertEqual(v['status'], 'CURRENT') elif v['id'] in ('v2.1', 'v2.0', 'v1.0'): self.assertEqual(v['status'], 'SUPPORTED') else: self.fail("Invalid version found")
def stub_url(self, method, parts=None, base_url=None, json=None, **kwargs): if not base_url: base_url = self.TEST_URL if json: kwargs['body'] = jsonutils.dumps(json) kwargs['content_type'] = 'application/json' if parts: url = '/'.join([p.strip('/') for p in [base_url] + parts]) else: url = base_url httpretty.register_uri(method, url, **kwargs)
def test_available_glance_data(self): body = jsonutils.dumps(GLANCE_EXAMPLES) httpretty.register_uri(httpretty.GET, BASE_URL, status=200, body=body) versions = discover.available_versions(BASE_URL) self.assertEqual(5, len(versions)) for v in versions: if v['id'] in ('v2.2', 'v1.1'): self.assertEqual(v['status'], 'CURRENT') elif v['id'] in ('v2.1', 'v2.0', 'v1.0'): self.assertEqual(v['status'], 'SUPPORTED') else: self.fail("Invalid version found")