Add checks for domain scoped data creep

Previously, the assertValidDomainScopedTokenResponse method only ensured
specific attributes were in the token response. These checks didn't ensure
that the token scope never grew.

This change makes it so that the assertion will fail if extra attributes are
added to the token response. This should help us be more aware of changes that
have token response data creep by building the check into the tests.

Change-Id: I43c86837f465f813da0985033a5af9d15d76eddc
Partial-Bug: 1224273
This commit is contained in:
Lance Bragstad 2015-12-07 22:21:36 +00:00
parent f7eecbfa30
commit 8a5343c8c2
2 changed files with 115 additions and 59 deletions

View File

@ -122,6 +122,97 @@ class AuthTestMixin(object):
class RestfulTestCase(unit.SQLDriverOverrides, rest.RestfulTestCase,
common_auth.AuthTestMixin):
def generate_token_schema(self, domain_scoped=False):
"""Return a dictionary of token properties to validate against."""
properties = {
'audit_ids': {
'type': 'array',
'items': {
'type': 'string',
},
'minItems': 1,
'maxItems': 2,
},
'bind': {
'type': 'object',
'properties': {
'kerberos': {
'type': 'string',
},
},
'required': ['kerberos'],
'additionalProperties': False,
},
'expires_at': {'type': 'string'},
'issued_at': {'type': 'string'},
'methods': {
'type': 'array',
'items': {
'type': 'string',
},
},
'user': {
'type': 'object',
'required': ['id', 'name', 'domain'],
'properties': {
'id': {'type': 'string'},
'name': {'type': 'string'},
'domain': {
'type': 'object',
'properties': {
'id': {'type': 'string'},
'name': {'type': 'string'}
},
'required': ['id', 'name'],
'additonalProperties': False,
}
},
'additionalProperties': False,
}
}
if domain_scoped:
properties['catalog'] = {'type': 'array'}
properties['roles'] = {
'type': 'array',
'items': {
'type': 'object',
'properties': {
'id': {'type': 'string', },
'name': {'type': 'string', },
},
'required': ['id', 'name', ],
'additionalProperties': False,
},
'minItems': 1,
}
properties['domain'] = {
'domain': {
'type': 'object',
'required': ['id', 'name'],
'properties': {
'id': {'type': 'string'},
'name': {'type': 'string'}
},
'additionalProperties': False
}
}
schema = {
'type': 'object',
'properties': properties,
'required': ['audit_ids', 'expires_at', 'issued_at', 'methods',
'user'],
'optional': ['bind'],
'additionalProperties': False
}
if domain_scoped:
schema['required'].extend(['domain', 'roles'])
schema['optional'].append('catalog')
return schema
def config_files(self):
config_files = super(RestfulTestCase, self).config_files()
config_files.append(unit.dirs.tests_conf('backend_sql.conf'))
@ -535,62 +626,9 @@ class RestfulTestCase(unit.SQLDriverOverrides, rest.RestfulTestCase,
def assertValidUnscopedTokenResponse(self, r, *args, **kwargs):
token = self.assertValidTokenResponse(r, *args, **kwargs)
unscoped_properties = {
'audit_ids': {
'type': 'array',
'items': {
'type': 'string',
},
'minItems': 1,
'maxItems': 2,
},
'bind': {
'type': 'object',
'properties': {
'kerberos': {
'type': 'string',
},
},
'required': ['kerberos', ],
'additionalProperties': False,
},
'expires_at': {'type': 'string'},
'issued_at': {'type': 'string'},
'methods': {
'type': 'array',
'items': {
'type': 'string',
},
},
'user': {
'type': 'object',
'required': ['id', 'name', 'domain'],
'properties': {
'id': {'type': 'string'},
'name': {'type': 'string'},
'domain': {
'type': 'object',
'properties': {
'id': {'type': 'string'},
'name': {'type': 'string'}
},
'required': ['id', 'name'],
'additonalProperties': False,
}
},
'additionalProperties': False,
}
}
unscoped_token_schema = {
'type': 'object',
'properties': unscoped_properties,
'required': ['audit_ids', 'expires_at', 'issued_at', 'methods',
'user'],
'optional': ['bind'],
'additionalProperties': False
}
validator_object = validators.SchemaValidator(unscoped_token_schema)
validator_object = validators.SchemaValidator(
self.generate_token_schema()
)
validator_object.validate(token)
return token
@ -664,9 +702,10 @@ class RestfulTestCase(unit.SQLDriverOverrides, rest.RestfulTestCase,
def assertValidDomainScopedTokenResponse(self, r, *args, **kwargs):
token = self.assertValidScopedTokenResponse(r, *args, **kwargs)
self.assertIn('domain', token)
self.assertIn('id', token['domain'])
self.assertIn('name', token['domain'])
validator_object = validators.SchemaValidator(
self.generate_token_schema(domain_scoped=True)
)
validator_object.validate(token)
return token

View File

@ -490,6 +490,23 @@ class TokenDataTests(object):
r = self.get('/auth/tokens', headers=self.headers)
self.assertValidUnscopedTokenResponse(r)
def test_domain_scoped_token_format(self):
# ensure the domain scoped token response contains the appropriate data
self.assignment_api.create_grant(
self.role['id'],
user_id=self.default_domain_user['id'],
domain_id=self.domain['id'])
domain_scoped_token = self.get_requested_token(
self.build_authentication_request(
user_id=self.default_domain_user['id'],
password=self.default_domain_user['password'],
domain_id=self.domain['id'])
)
self.headers['X-Subject-Token'] = domain_scoped_token
r = self.get('/auth/tokens', headers=self.headers)
self.assertValidDomainScopedTokenResponse(r)
class AllowRescopeScopedTokenDisabledTests(test_v3.RestfulTestCase):
def config_overrides(self):