Merge "Handle special cases with msgpack and python3"

This commit is contained in:
Zuul 2019-01-30 10:28:48 +00:00 committed by Gerrit Code Review
commit 64ffe8c656
3 changed files with 80 additions and 0 deletions

View File

@ -1912,6 +1912,57 @@ class FederatedTokenTests(test_v3.RestfulTestCase, FederatedSetupMixin):
token_resp = render_token.render_token_response_from_model(r)['token']
self.assertValidMappedUser(token_resp)
def test_default_domain_scoped_token(self):
# Make sure federated users can get tokens scoped to the default
# domain, which has a non-uuid ID by default (e.g., `default`). We want
# to make sure the token provider handles string types properly if the
# ID isn't compressed into byte format during validation. Turn off
# cache on issue so that we validate the token online right after we
# get it to make sure the token provider is called.
self.config_fixture.config(group='token', cache_on_issue=False)
# Grab an unscoped token to get a domain-scoped token with.
token = self._issue_unscoped_token()
# Give the user a direct role assignment on the default domain, so they
# can get a federated domain-scoped token.
PROVIDERS.assignment_api.create_grant(
self.role_admin['id'], user_id=token.user_id,
domain_id=CONF.identity.default_domain_id
)
# Get a token scoped to the default domain with an ID of `default`,
# which isn't a uuid type, but we should be able to handle it
# accordingly in the token formatters/providers.
auth_request = {
'auth': {
'identity': {
'methods': [
'token'
],
'token': {
'id': token.id
}
},
'scope': {
'domain': {
'id': CONF.identity.default_domain_id
}
}
}
}
r = self.v3_create_token(auth_request)
domain_scoped_token_id = r.headers.get('X-Subject-Token')
# Validate the token to make sure the token providers handle non-uuid
# domain IDs properly.
headers = {'X-Subject-Token': domain_scoped_token_id}
self.get(
'/auth/tokens',
token=domain_scoped_token_id,
headers=headers
)
def test_issue_the_same_unscoped_token_with_user_deleted(self):
r = self._issue_unscoped_token()
token = render_token.render_token_response_from_model(r)['token']

View File

@ -611,6 +611,23 @@ class FederatedScopedPayload(FederatedUnscopedPayload):
(is_stored_as_bytes, scope_id) = payload[2]
if is_stored_as_bytes:
scope_id = cls.convert_uuid_bytes_to_hex(scope_id)
else:
# NOTE(lbragstad): We assembled the token payload scope as a tuple
# (False, domain_id) for cases like (False, 'default'), since the
# default domain ID isn't converted to a byte string when it's not
# in UUID format. Despite the boolean indicator in the tuple that
# denotes if the value is stored as a byte string or not, msgpack
# apparently returns the serialized input as byte strings anyway.
# For example, this means what we though we were passing in as
# (False, 'default') during token creation actually comes out as
# (False, b'default') in token validation through msgpack, which
# clearly isn't correct according to our boolean indicator. This
# causes comparison issues due to different string types (e.g.,
# b'default' != 'default') with python 3. See bug 1813085 for
# details. We use this pattern for other strings in the payload
# like idp_id and protocol_id for the same reason.
if six.PY3 and isinstance(scope_id, six.binary_type):
scope_id = scope_id.decode('utf-8')
project_id = (
scope_id
if cls.version == FederatedProjectScopedPayload.version else None)
@ -621,7 +638,12 @@ class FederatedScopedPayload(FederatedUnscopedPayload):
(is_stored_as_bytes, idp_id) = payload[4]
if is_stored_as_bytes:
idp_id = cls.convert_uuid_bytes_to_hex(idp_id)
else:
if six.PY3 and isinstance(idp_id, six.binary_type):
idp_id = idp_id.decode('utf-8')
protocol_id = payload[5]
if six.PY3 and isinstance(protocol_id, six.binary_type):
protocol_id = protocol_id.decode('utf-8')
expires_at_str = cls._convert_float_to_time_string(payload[6])
audit_ids = list(map(cls.base64_encode, payload[7]))
system = None

View File

@ -0,0 +1,7 @@
---
fixes:
- |
[`bug 1813085 <https://bugs.launchpad.net/keystone/+bug/1813085>`]
Validation of federated domain-scoped tokens scoped to the ``default``
domain no longer results in an ``HTTP 404 Domain Not Found`` due
to byte string conversion issues with msgpack in python 3.