Increase test coverage for token APIs
The token API tests were not calling our rather exhaustive jsonschema-based validators to ensure that the API responses were correctly structured. Instead, they were simply ensuring that things like validate token didn't blow up. This makes all those tests much stronger. Relatedly, it also introduces a regex pattern for the two timestamp fields in tokens (expires_at and created_at). Change-Id: Idd5de04ef333c0b03a31f445ddd1f52e3a7b9b03 Related-Bug: 1597077
This commit is contained in:
parent
5f7377f5ab
commit
b577af9bca
|
@ -78,7 +78,10 @@ log.register_options(CONF)
|
|||
|
||||
IN_MEM_DB_CONN_STRING = 'sqlite://'
|
||||
|
||||
# Strictly matches ISO 8601 timestamps with subsecond precision like:
|
||||
# 2016-06-28T20:48:56.000000Z
|
||||
TIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
|
||||
TIME_FORMAT_REGEX = '^\d{4}-[0-1]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d{6}Z$'
|
||||
|
||||
exception._FATAL_EXCEPTION_FORMAT_ERRORS = True
|
||||
os.makedirs(TMPDIR)
|
||||
|
|
|
@ -147,8 +147,14 @@ class RestfulTestCase(unit.SQLDriverOverrides, rest.RestfulTestCase,
|
|||
'required': ['kerberos'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
'expires_at': {'type': 'string'},
|
||||
'issued_at': {'type': 'string'},
|
||||
'expires_at': {
|
||||
'type': 'string',
|
||||
'pattern': unit.TIME_FORMAT_REGEX,
|
||||
},
|
||||
'issued_at': {
|
||||
'type': 'string',
|
||||
'pattern': unit.TIME_FORMAT_REGEX,
|
||||
},
|
||||
'methods': {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
|
|
|
@ -159,37 +159,40 @@ class TokenAPITests(object):
|
|||
self.v3_token = r.headers.get('X-Subject-Token')
|
||||
self.headers = {'X-Subject-Token': r.headers.get('X-Subject-Token')}
|
||||
|
||||
def _make_auth_request(self, auth_data):
|
||||
resp = self.post('/auth/tokens', body=auth_data)
|
||||
token = resp.headers.get('X-Subject-Token')
|
||||
return token
|
||||
|
||||
def _get_unscoped_token(self):
|
||||
auth_data = self.build_authentication_request(
|
||||
user_id=self.user['id'],
|
||||
password=self.user['password'])
|
||||
return self._make_auth_request(auth_data)
|
||||
r = self.post('/auth/tokens', body=auth_data)
|
||||
self.assertValidUnscopedTokenResponse(r)
|
||||
return r.headers.get('X-Subject-Token')
|
||||
|
||||
def _get_domain_scoped_token(self):
|
||||
auth_data = self.build_authentication_request(
|
||||
user_id=self.user['id'],
|
||||
password=self.user['password'],
|
||||
domain_id=self.domain_id)
|
||||
return self._make_auth_request(auth_data)
|
||||
r = self.post('/auth/tokens', body=auth_data)
|
||||
self.assertValidDomainScopedTokenResponse(r)
|
||||
return r.headers.get('X-Subject-Token')
|
||||
|
||||
def _get_project_scoped_token(self):
|
||||
auth_data = self.build_authentication_request(
|
||||
user_id=self.user['id'],
|
||||
password=self.user['password'],
|
||||
project_id=self.project_id)
|
||||
return self._make_auth_request(auth_data)
|
||||
r = self.post('/auth/tokens', body=auth_data)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
return r.headers.get('X-Subject-Token')
|
||||
|
||||
def _get_trust_scoped_token(self, trustee_user, trust):
|
||||
auth_data = self.build_authentication_request(
|
||||
user_id=trustee_user['id'],
|
||||
password=trustee_user['password'],
|
||||
trust_id=trust['id'])
|
||||
return self._make_auth_request(auth_data)
|
||||
r = self.post('/auth/tokens', body=auth_data)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
return r.headers.get('X-Subject-Token')
|
||||
|
||||
def _create_trust(self, impersonation=False):
|
||||
# Create a trustee user
|
||||
|
@ -307,11 +310,13 @@ class TokenAPITests(object):
|
|||
|
||||
def test_validate_unscoped_token(self):
|
||||
unscoped_token = self._get_unscoped_token()
|
||||
self._validate_token(unscoped_token)
|
||||
r = self._validate_token(unscoped_token)
|
||||
self.assertValidUnscopedTokenResponse(r)
|
||||
|
||||
def test_revoke_unscoped_token(self):
|
||||
unscoped_token = self._get_unscoped_token()
|
||||
self._validate_token(unscoped_token)
|
||||
r = self._validate_token(unscoped_token)
|
||||
self.assertValidUnscopedTokenResponse(r)
|
||||
self._revoke_token(unscoped_token)
|
||||
self._validate_token(unscoped_token,
|
||||
expected_status=http_client.NOT_FOUND)
|
||||
|
@ -373,7 +378,8 @@ class TokenAPITests(object):
|
|||
def test_unscoped_token_is_invalid_after_disabling_user(self):
|
||||
unscoped_token = self._get_unscoped_token()
|
||||
# Make sure the token is valid
|
||||
self._validate_token(unscoped_token)
|
||||
r = self._validate_token(unscoped_token)
|
||||
self.assertValidUnscopedTokenResponse(r)
|
||||
# Disable the user
|
||||
self._set_user_enabled(self.user, enabled=False)
|
||||
# Ensure validating a token for a disabled user fails
|
||||
|
@ -384,7 +390,8 @@ class TokenAPITests(object):
|
|||
def test_unscoped_token_is_invalid_after_enabling_disabled_user(self):
|
||||
unscoped_token = self._get_unscoped_token()
|
||||
# Make sure the token is valid
|
||||
self._validate_token(unscoped_token)
|
||||
r = self._validate_token(unscoped_token)
|
||||
self.assertValidUnscopedTokenResponse(r)
|
||||
# Disable the user
|
||||
self._set_user_enabled(self.user, enabled=False)
|
||||
# Ensure validating a token for a disabled user fails
|
||||
|
@ -401,7 +408,8 @@ class TokenAPITests(object):
|
|||
def test_unscoped_token_is_invalid_after_disabling_user_domain(self):
|
||||
unscoped_token = self._get_unscoped_token()
|
||||
# Make sure the token is valid
|
||||
self._validate_token(unscoped_token)
|
||||
r = self._validate_token(unscoped_token)
|
||||
self.assertValidUnscopedTokenResponse(r)
|
||||
# Disable the user's domain
|
||||
self.domain['enabled'] = False
|
||||
self.resource_api.update_domain(self.domain['id'], self.domain)
|
||||
|
@ -413,7 +421,8 @@ class TokenAPITests(object):
|
|||
def test_unscoped_token_is_invalid_after_changing_user_password(self):
|
||||
unscoped_token = self._get_unscoped_token()
|
||||
# Make sure the token is valid
|
||||
self._validate_token(unscoped_token)
|
||||
r = self._validate_token(unscoped_token)
|
||||
self.assertValidUnscopedTokenResponse(r)
|
||||
# Change user's password
|
||||
self.user['password'] = 'Password1'
|
||||
self.identity_api.update_user(self.user['id'], self.user)
|
||||
|
@ -576,8 +585,9 @@ class TokenAPITests(object):
|
|||
user_id=self.user['id'],
|
||||
domain_id=self.domain['id'])
|
||||
domain_scoped_token = self._get_domain_scoped_token()
|
||||
resp = self._validate_token(domain_scoped_token)
|
||||
resp_json = json.loads(resp.body)
|
||||
r = self._validate_token(domain_scoped_token)
|
||||
self.assertValidDomainScopedTokenResponse(r)
|
||||
resp_json = json.loads(r.body)
|
||||
self.assertIsNotNone(resp_json['token']['catalog'])
|
||||
self.assertIsNotNone(resp_json['token']['roles'])
|
||||
self.assertIsNotNone(resp_json['token']['domain'])
|
||||
|
@ -589,7 +599,8 @@ class TokenAPITests(object):
|
|||
domain_id=self.domain['id'])
|
||||
domain_scoped_token = self._get_domain_scoped_token()
|
||||
# Make sure the token is valid
|
||||
self._validate_token(domain_scoped_token)
|
||||
r = self._validate_token(domain_scoped_token)
|
||||
self.assertValidDomainScopedTokenResponse(r)
|
||||
# Disable user
|
||||
self._set_user_enabled(self.user, enabled=False)
|
||||
# Ensure validating a token for a disabled user fails
|
||||
|
@ -604,7 +615,8 @@ class TokenAPITests(object):
|
|||
domain_id=self.domain['id'])
|
||||
domain_scoped_token = self._get_domain_scoped_token()
|
||||
# Make sure the token is valid
|
||||
self._validate_token(domain_scoped_token)
|
||||
r = self._validate_token(domain_scoped_token)
|
||||
self.assertValidDomainScopedTokenResponse(r)
|
||||
# Delete access to domain
|
||||
self.assignment_api.delete_grant(self.role['id'],
|
||||
user_id=self.user['id'],
|
||||
|
@ -621,7 +633,8 @@ class TokenAPITests(object):
|
|||
domain_id=self.domain['id'])
|
||||
domain_scoped_token = self._get_domain_scoped_token()
|
||||
# Make sure the token is valid
|
||||
self._validate_token(domain_scoped_token)
|
||||
r = self._validate_token(domain_scoped_token)
|
||||
self.assertValidDomainScopedTokenResponse(r)
|
||||
# Disable domain
|
||||
self.domain['enabled'] = False
|
||||
self.resource_api.update_domain(self.domain['id'], self.domain)
|
||||
|
@ -653,11 +666,13 @@ class TokenAPITests(object):
|
|||
|
||||
def test_validate_project_scoped_token(self):
|
||||
project_scoped_token = self._get_project_scoped_token()
|
||||
self._validate_token(project_scoped_token)
|
||||
r = self._validate_token(project_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
|
||||
def test_revoke_project_scoped_token(self):
|
||||
project_scoped_token = self._get_project_scoped_token()
|
||||
self._validate_token(project_scoped_token)
|
||||
r = self._validate_token(project_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
self._revoke_token(project_scoped_token)
|
||||
self._validate_token(project_scoped_token,
|
||||
expected_status=http_client.NOT_FOUND)
|
||||
|
@ -957,7 +972,8 @@ class TokenAPITests(object):
|
|||
def test_project_scoped_token_is_invalid_after_disabling_user(self):
|
||||
project_scoped_token = self._get_project_scoped_token()
|
||||
# Make sure the token is valid
|
||||
self._validate_token(project_scoped_token)
|
||||
r = self._validate_token(project_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
# Disable the user
|
||||
self._set_user_enabled(self.user, enabled=False)
|
||||
# Ensure validating a token for a disabled user fails
|
||||
|
@ -968,7 +984,8 @@ class TokenAPITests(object):
|
|||
def test_project_scoped_token_invalid_after_changing_user_password(self):
|
||||
project_scoped_token = self._get_project_scoped_token()
|
||||
# Make sure the token is valid
|
||||
self._validate_token(project_scoped_token)
|
||||
r = self._validate_token(project_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
# Update user's password
|
||||
self.user['password'] = 'Password1'
|
||||
self.identity_api.update_user(self.user['id'], self.user)
|
||||
|
@ -980,7 +997,8 @@ class TokenAPITests(object):
|
|||
def test_project_scoped_token_invalid_after_disabling_project(self):
|
||||
project_scoped_token = self._get_project_scoped_token()
|
||||
# Make sure the token is valid
|
||||
self._validate_token(project_scoped_token)
|
||||
r = self._validate_token(project_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
# Disable project
|
||||
self.project['enabled'] = False
|
||||
self.resource_api.update_project(self.project['id'], self.project)
|
||||
|
@ -1001,7 +1019,8 @@ class TokenAPITests(object):
|
|||
project_id=self.project['id'])
|
||||
project_scoped_token = self._get_project_scoped_token()
|
||||
# Make sure the token is valid
|
||||
self._validate_token(project_scoped_token)
|
||||
r = self._validate_token(project_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
# Delete access to project
|
||||
self.assignment_api.delete_grant(self.role['id'],
|
||||
user_id=self.user['id'],
|
||||
|
@ -1031,19 +1050,22 @@ class TokenAPITests(object):
|
|||
trustee_user, trust = self._create_trust()
|
||||
trust_scoped_token = self._get_trust_scoped_token(trustee_user, trust)
|
||||
# Validate a trust scoped token
|
||||
self._validate_token(trust_scoped_token)
|
||||
r = self._validate_token(trust_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
|
||||
def test_validate_a_trust_scoped_token_impersonated(self):
|
||||
trustee_user, trust = self._create_trust(impersonation=True)
|
||||
trust_scoped_token = self._get_trust_scoped_token(trustee_user, trust)
|
||||
# Validate a trust scoped token
|
||||
self._validate_token(trust_scoped_token)
|
||||
r = self._validate_token(trust_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
|
||||
def test_revoke_trust_scoped_token(self):
|
||||
trustee_user, trust = self._create_trust()
|
||||
trust_scoped_token = self._get_trust_scoped_token(trustee_user, trust)
|
||||
# Validate a trust scoped token
|
||||
self._validate_token(trust_scoped_token)
|
||||
r = self._validate_token(trust_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
self._revoke_token(trust_scoped_token)
|
||||
self._validate_token(trust_scoped_token,
|
||||
expected_status=http_client.NOT_FOUND)
|
||||
|
@ -1052,7 +1074,8 @@ class TokenAPITests(object):
|
|||
trustee_user, trust = self._create_trust()
|
||||
trust_scoped_token = self._get_trust_scoped_token(trustee_user, trust)
|
||||
# Validate a trust scoped token
|
||||
self._validate_token(trust_scoped_token)
|
||||
r = self._validate_token(trust_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
|
||||
# Disable trustee
|
||||
trustee_update_ref = dict(enabled=False)
|
||||
|
@ -1066,7 +1089,8 @@ class TokenAPITests(object):
|
|||
trustee_user, trust = self._create_trust()
|
||||
trust_scoped_token = self._get_trust_scoped_token(trustee_user, trust)
|
||||
# Validate a trust scoped token
|
||||
self._validate_token(trust_scoped_token)
|
||||
r = self._validate_token(trust_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
# Change trustee's password
|
||||
trustee_update_ref = dict(password='Password1')
|
||||
self.identity_api.update_user(trustee_user['id'], trustee_update_ref)
|
||||
|
@ -1079,7 +1103,8 @@ class TokenAPITests(object):
|
|||
trustee_user, trust = self._create_trust()
|
||||
trust_scoped_token = self._get_trust_scoped_token(trustee_user, trust)
|
||||
# Validate a trust scoped token
|
||||
self._validate_token(trust_scoped_token)
|
||||
r = self._validate_token(trust_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
|
||||
# Disable the trustor
|
||||
trustor_update_ref = dict(enabled=False)
|
||||
|
@ -1093,7 +1118,8 @@ class TokenAPITests(object):
|
|||
trustee_user, trust = self._create_trust()
|
||||
trust_scoped_token = self._get_trust_scoped_token(trustee_user, trust)
|
||||
# Validate a trust scoped token
|
||||
self._validate_token(trust_scoped_token)
|
||||
r = self._validate_token(trust_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
|
||||
# Change trustor's password
|
||||
trustor_update_ref = dict(password='Password1')
|
||||
|
@ -1107,7 +1133,8 @@ class TokenAPITests(object):
|
|||
trustee_user, trust = self._create_trust()
|
||||
trust_scoped_token = self._get_trust_scoped_token(trustee_user, trust)
|
||||
# Validate a trust scoped token
|
||||
self._validate_token(trust_scoped_token)
|
||||
r = self._validate_token(trust_scoped_token)
|
||||
self.assertValidProjectScopedTokenResponse(r)
|
||||
|
||||
# Disable trustor's domain
|
||||
self.domain['enabled'] = False
|
||||
|
|
Loading…
Reference in New Issue