Glance api to pass identity headers to registry v1
This patch introduces the send_identity_headers config option that allows glance-api to pass auth identity headers when making calls to the registry v1. docImpact Fixes bug 1199990 Change-Id: Ie5f07ed6dfeaa8428de4f79c4d40d182328e6ab4
This commit is contained in:
parent
c13692f27d
commit
3fa3891595
@ -90,6 +90,13 @@ workers = 1
|
||||
# The default value is false.
|
||||
#show_image_direct_url = False
|
||||
|
||||
# Send headers containing user and tenant information when making requests to
|
||||
# the v1 glance registry. This allows the registry to function as if a user is
|
||||
# authenticated without the need to authenticate a user itself using the
|
||||
# auth_token middleware.
|
||||
# The default value is false.
|
||||
#send_identity_headers = False
|
||||
|
||||
# ================= Syslog Options ============================
|
||||
|
||||
# Send logs to syslog (/dev/log) instead of to file specified
|
||||
|
@ -6,6 +6,12 @@ pipeline = unauthenticated-context registryapp
|
||||
[pipeline:glance-registry-keystone]
|
||||
pipeline = authtoken context registryapp
|
||||
|
||||
# Use this pipeline for authZ only. This means that the registry will treat a
|
||||
# user as authenticated without making requests to keystone to reauthenticate
|
||||
# the user.
|
||||
[pipeline:glance-registry-trusted-auth]
|
||||
pipeline = context registryapp
|
||||
|
||||
[app:registryapp]
|
||||
paste.app_factory = glance.registry.api.v1:API.factory
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
Registry's Client API
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
|
||||
from oslo.config import cfg
|
||||
@ -55,6 +56,16 @@ registry_client_ctx_opts = [
|
||||
cfg.BoolOpt('use_user_token', default=True,
|
||||
help=_('Whether to pass through the user token when '
|
||||
'making requests to the registry.')),
|
||||
cfg.BoolOpt('send_identity_headers', default=False,
|
||||
help=_('Whether to pass through headers containing user '
|
||||
'and tenant information when making requests to '
|
||||
'the registry. This allows the registry to use the '
|
||||
'context middleware without the keystoneclients\' '
|
||||
'auth_token middleware, removing calls to the keystone '
|
||||
'auth service. It is recommended that when using this '
|
||||
'option, secure communication between glance api and '
|
||||
'glance registry is ensured by means other than '
|
||||
'auth_token middleware.')),
|
||||
cfg.StrOpt('admin_user', secret=True,
|
||||
help=_('The administrators user name.')),
|
||||
cfg.StrOpt('admin_password', secret=True,
|
||||
@ -141,6 +152,16 @@ def get_registry_client(cxt):
|
||||
kwargs['auth_tok'] = cxt.auth_tok
|
||||
if _CLIENT_CREDS:
|
||||
kwargs['creds'] = _CLIENT_CREDS
|
||||
|
||||
if CONF.send_identity_headers:
|
||||
identity_headers = {
|
||||
'X-User-Id': cxt.user,
|
||||
'X-Tenant-Id': cxt.tenant,
|
||||
'X-Roles': ','.join(cxt.roles),
|
||||
'X-Identity-Status': 'Confirmed',
|
||||
'X-Service-Catalog': json.dumps(cxt.service_catalog),
|
||||
}
|
||||
kwargs['identity_headers'] = identity_headers
|
||||
return client.RegistryClient(_CLIENT_HOST, _CLIENT_PORT,
|
||||
_METADATA_ENCRYPTION_KEY, **kwargs)
|
||||
|
||||
|
@ -37,7 +37,7 @@ class RegistryClient(BaseClient):
|
||||
DEFAULT_PORT = 9191
|
||||
|
||||
def __init__(self, host=None, port=None, metadata_encryption_key=None,
|
||||
**kwargs):
|
||||
identity_headers=None, **kwargs):
|
||||
"""
|
||||
:param metadata_encryption_key: Key used to encrypt 'location' metadata
|
||||
"""
|
||||
@ -45,6 +45,7 @@ class RegistryClient(BaseClient):
|
||||
# NOTE (dprince): by default base client overwrites host and port
|
||||
# settings when using keystone. configure_via_auth=False disables
|
||||
# this behaviour to ensure we still send requests to the Registry API
|
||||
self.identity_headers = identity_headers
|
||||
BaseClient.__init__(self, host, port, configure_via_auth=False,
|
||||
**kwargs)
|
||||
|
||||
@ -85,6 +86,8 @@ class RegistryClient(BaseClient):
|
||||
|
||||
def do_request(self, method, action, **kwargs):
|
||||
try:
|
||||
kwargs['headers'] = kwargs.get('headers', {})
|
||||
kwargs['headers'].update(self.identity_headers or {})
|
||||
res = super(RegistryClient, self).do_request(method,
|
||||
action,
|
||||
**kwargs)
|
||||
|
@ -1215,6 +1215,7 @@ class TestRegistryV1ClientApi(base.IsolatedUnitTest):
|
||||
"""Establish a clean test environment"""
|
||||
super(TestRegistryV1ClientApi, self).setUp()
|
||||
self.mox = mox.Mox()
|
||||
self.context = context.RequestContext()
|
||||
reload(rapi)
|
||||
|
||||
def tearDown(self):
|
||||
@ -1222,6 +1223,23 @@ class TestRegistryV1ClientApi(base.IsolatedUnitTest):
|
||||
super(TestRegistryV1ClientApi, self).tearDown()
|
||||
self.mox.UnsetStubs()
|
||||
|
||||
def test_get_registry_client(self):
|
||||
actual_client = rapi.get_registry_client(self.context)
|
||||
self.assertEqual(actual_client.identity_headers, None)
|
||||
|
||||
def test_get_registry_client_with_identity_headers(self):
|
||||
self.config(send_identity_headers=True)
|
||||
expected_identity_headers = {
|
||||
'X-User-Id': self.context.user,
|
||||
'X-Tenant-Id': self.context.tenant,
|
||||
'X-Roles': ','.join(self.context.roles),
|
||||
'X-Identity-Status': 'Confirmed',
|
||||
'X-Service-Catalog': 'null',
|
||||
}
|
||||
actual_client = rapi.get_registry_client(self.context)
|
||||
self.assertEqual(actual_client.identity_headers,
|
||||
expected_identity_headers)
|
||||
|
||||
def test_configure_registry_client_not_using_use_user_token(self):
|
||||
self.config(use_user_token=False)
|
||||
self.mox.StubOutWithMock(rapi, 'configure_registry_admin_creds')
|
||||
@ -1273,3 +1291,48 @@ class TestRegistryV1ClientApi(base.IsolatedUnitTest):
|
||||
self.assertEquals(rapi._CLIENT_CREDS, None)
|
||||
rapi.configure_registry_admin_creds()
|
||||
self.assertEquals(rapi._CLIENT_CREDS, expected)
|
||||
|
||||
|
||||
class FakeResponse():
|
||||
status = 202
|
||||
|
||||
def getheader(*args, **kwargs):
|
||||
return None
|
||||
|
||||
|
||||
class TestRegistryV1ClientRequests(base.IsolatedUnitTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestRegistryV1ClientRequests, self).setUp()
|
||||
self.mox = mox.Mox()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestRegistryV1ClientRequests, self).tearDown()
|
||||
self.mox.UnsetStubs()
|
||||
|
||||
def test_do_request_with_identity_headers(self):
|
||||
identity_headers = {'foo': 'bar'}
|
||||
self.client = rclient.RegistryClient("0.0.0.0",
|
||||
identity_headers=identity_headers)
|
||||
|
||||
self.mox.StubOutWithMock(test_client.BaseClient, 'do_request')
|
||||
test_client.BaseClient.do_request("GET", "/images",
|
||||
headers=identity_headers).AndReturn(
|
||||
FakeResponse())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.client.do_request("GET", "/images")
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_do_request(self):
|
||||
self.client = rclient.RegistryClient("0.0.0.0")
|
||||
|
||||
self.mox.StubOutWithMock(test_client.BaseClient, 'do_request')
|
||||
test_client.BaseClient.do_request("GET", "/images",
|
||||
headers={}).AndReturn(FakeResponse())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.client.do_request("GET", "/images")
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
Loading…
Reference in New Issue
Block a user