Only confirm token binding on one token

When using service tokens and kerberos, the REMOTE_USER will be the
service user, and hence the token bind confirmation will always fail to
validate the client user's token, making it impossible to use token
binding with service tokens. This patch adds a test to expose the issue
and fixes the problem by only validating the token binding for the
service token when both tokens are in the request.

Change-Id: I7ba2283e8e58b89f1e42bc738c7e77284321e3a5
Closes-bug: #1413433
This commit is contained in:
Colleen Murphy 2016-04-11 19:13:56 -07:00
parent 53335aaf49
commit 5ba835f3e1
3 changed files with 71 additions and 2 deletions

View File

@ -491,7 +491,8 @@ class BaseAuthProtocol(object):
try:
data, user_auth_ref = self._do_fetch_token(request.user_token)
self._validate_token(user_auth_ref)
self._confirm_token_bind(user_auth_ref, request)
if not request.service_token:
self._confirm_token_bind(user_auth_ref, request)
except ksm_exceptions.InvalidToken:
self.log.info(_LI('Invalid user token'))
request.user_token_valid = False

View File

@ -2049,6 +2049,35 @@ class CommonCompositeAuthTests(object):
expected_status=403)
self.assertEqual(FakeApp.FORBIDDEN, resp.body)
def assert_kerberos_composite_bind(self, user_token, service_token,
bind_level):
conf = {
'enforce_token_bind': bind_level,
'auth_version': self.auth_version,
}
self.set_middleware(conf=conf)
req = webob.Request.blank('/')
req.headers['X-Auth-Token'] = user_token
req.headers['X-Service-Token'] = service_token
req.environ['REMOTE_USER'] = self.examples.SERVICE_KERBEROS_BIND
req.environ['AUTH_TYPE'] = 'Negotiate'
resp = req.get_response(self.middleware)
self.assertEqual(200, resp.status_int)
self.assertEqual(FakeApp.SUCCESS, resp.body)
self.assertIn('keystone.token_info', req.environ)
def test_composite_auth_with_bind(self):
token = self.token_dict['uuid_token_bind']
service_token = self.token_dict['uuid_service_token_bind']
self.assert_kerberos_composite_bind(token,
service_token,
bind_level='required')
class v2CompositeAuthTests(BaseAuthTokenMiddlewareTest,
CommonCompositeAuthTests,
@ -2069,9 +2098,13 @@ class v2CompositeAuthTests(BaseAuthTokenMiddlewareTest,
uuid_token_default = self.examples.UUID_TOKEN_DEFAULT
uuid_service_token_default = self.examples.UUID_SERVICE_TOKEN_DEFAULT
uuid_token_bind = self.examples.UUID_TOKEN_BIND
uuid_service_token_bind = self.examples.UUID_SERVICE_TOKEN_BIND
self.token_dict = {
'uuid_token_default': uuid_token_default,
'uuid_service_token_default': uuid_service_token_default,
'uuid_token_bind': uuid_token_bind,
'uuid_service_token_bind': uuid_service_token_bind,
}
self.requests_mock.get(BASE_URI,
@ -2086,7 +2119,9 @@ class v2CompositeAuthTests(BaseAuthTokenMiddlewareTest,
status_code=200)
for token in (self.examples.UUID_TOKEN_DEFAULT,
self.examples.UUID_SERVICE_TOKEN_DEFAULT,):
self.examples.UUID_SERVICE_TOKEN_DEFAULT,
self.examples.UUID_TOKEN_BIND,
self.examples.UUID_SERVICE_TOKEN_BIND):
text = self.examples.JSON_TOKEN_RESPONSES[token]
self.requests_mock.get('%s/v2.0/tokens/%s' % (BASE_URI, token),
text=text)
@ -2120,9 +2155,13 @@ class v3CompositeAuthTests(BaseAuthTokenMiddlewareTest,
uuid_token_default = self.examples.v3_UUID_TOKEN_DEFAULT
uuid_serv_token_default = self.examples.v3_UUID_SERVICE_TOKEN_DEFAULT
uuid_token_bind = self.examples.v3_UUID_TOKEN_BIND
uuid_service_token_bind = self.examples.v3_UUID_SERVICE_TOKEN_BIND
self.token_dict = {
'uuid_token_default': uuid_token_default,
'uuid_service_token_default': uuid_serv_token_default,
'uuid_token_bind': uuid_token_bind,
'uuid_service_token_bind': uuid_service_token_bind,
}
self.requests_mock.get(BASE_URI, json=VERSION_LIST_v3, status_code=300)

View File

@ -105,6 +105,7 @@ class Examples(fixtures.Fixture):
self.SIGNING_CERT = f.read()
self.KERBEROS_BIND = 'USER@REALM'
self.SERVICE_KERBEROS_BIND = 'SERVICE_USER@SERVICE_REALM'
self.SIGNING_KEY_FILE = os.path.join(KEYDIR, 'signing_key.pem')
with open(self.SIGNING_KEY_FILE) as f:
@ -127,7 +128,9 @@ class Examples(fixtures.Fixture):
self.v3_UUID_TOKEN_UNKNOWN_BIND = '7ed9781b62cd4880b8d8c6788ab1d1e2'
self.UUID_SERVICE_TOKEN_DEFAULT = 'fe4c0710ec2f492748596c1b53ab124'
self.UUID_SERVICE_TOKEN_BIND = '5e43439613d34a13a7e03b2762bd08ab'
self.v3_UUID_SERVICE_TOKEN_DEFAULT = 'g431071bbc2f492748596c1b53cb229'
self.v3_UUID_SERVICE_TOKEN_BIND = 'be705e4426d0449a89e35ae21c380a05'
revoked_token = self.REVOKED_TOKEN
if isinstance(revoked_token, six.text_type):
@ -321,6 +324,17 @@ class Examples(fixtures.Fixture):
token['access']['token']['bind'] = {'kerberos': self.KERBEROS_BIND}
self.TOKEN_RESPONSES[self.UUID_TOKEN_BIND] = token
token = fixture.V2Token(token_id=self.UUID_SERVICE_TOKEN_BIND,
tenant_id=SERVICE_PROJECT_ID,
tenant_name=SERVICE_PROJECT_NAME,
user_id=SERVICE_USER_ID,
user_name=SERVICE_USER_NAME)
token.add_role(SERVICE_ROLE_NAME1)
token.add_role(SERVICE_ROLE_NAME2)
token['access']['token']['bind'] = {
'kerberos': self.SERVICE_KERBEROS_BIND}
self.TOKEN_RESPONSES[self.UUID_SERVICE_TOKEN_BIND] = token
token = fixture.V2Token(token_id=self.UUID_TOKEN_UNKNOWN_BIND,
tenant_id=PROJECT_ID,
tenant_name=PROJECT_NAME,
@ -405,6 +419,21 @@ class Examples(fixtures.Fixture):
token['token']['bind'] = {'kerberos': self.KERBEROS_BIND}
self.TOKEN_RESPONSES[self.v3_UUID_TOKEN_BIND] = token
token = fixture.V3Token(user_id=SERVICE_USER_ID,
user_name=SERVICE_USER_NAME,
user_domain_id=SERVICE_DOMAIN_ID,
user_domain_name=SERVICE_DOMAIN_NAME,
project_id=SERVICE_PROJECT_ID,
project_name=SERVICE_PROJECT_NAME,
project_domain_id=SERVICE_DOMAIN_ID,
project_domain_name=SERVICE_DOMAIN_NAME)
token.add_role(name=SERVICE_ROLE_NAME1)
token.add_role(name=SERVICE_ROLE_NAME2)
svc = token.add_service(self.SERVICE_TYPE)
svc.add_endpoint('public', self.SERVICE_URL)
token['token']['bind'] = {'kerberos': self.SERVICE_KERBEROS_BIND}
self.TOKEN_RESPONSES[self.v3_UUID_SERVICE_TOKEN_BIND] = token
token = fixture.V3Token(user_id=USER_ID,
user_name=USER_NAME,
user_domain_id=DOMAIN_ID,