From 1ad62ef692b43b28fb96b79a3698bd2a5be85015 Mon Sep 17 00:00:00 2001 From: Lance Bragstad Date: Mon, 7 Dec 2015 15:38:00 +0000 Subject: [PATCH] Add checks for token data creep using jsonschema Previously, the assertValidUnscopedTokenResponse 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. This is implemented using the existing jsonschema work that keystone has for validating API requests. Change-Id: I15acd58a9efaac65ba066fbb7b81f15797b6573c Partial-Bug: 1224273 --- keystone/tests/unit/test_v3.py | 61 +++++++++++++++++++++++++++-- keystone/tests/unit/test_v3_auth.py | 17 ++++++-- 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/keystone/tests/unit/test_v3.py b/keystone/tests/unit/test_v3.py index 526aec221d..d027f77391 100644 --- a/keystone/tests/unit/test_v3.py +++ b/keystone/tests/unit/test_v3.py @@ -25,6 +25,7 @@ import webtest from keystone import auth from keystone.common import authorization from keystone.common import cache +from keystone.common.validation import validators from keystone import exception from keystone import middleware from keystone.policy.backends import rules @@ -534,10 +535,62 @@ class RestfulTestCase(unit.SQLDriverOverrides, rest.RestfulTestCase, def assertValidUnscopedTokenResponse(self, r, *args, **kwargs): token = self.assertValidTokenResponse(r, *args, **kwargs) - self.assertNotIn('roles', token) - self.assertNotIn('catalog', token) - self.assertNotIn('project', token) - self.assertNotIn('domain', token) + 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.validate(token) return token diff --git a/keystone/tests/unit/test_v3_auth.py b/keystone/tests/unit/test_v3_auth.py index 8aa46c48db..551f52da29 100644 --- a/keystone/tests/unit/test_v3_auth.py +++ b/keystone/tests/unit/test_v3_auth.py @@ -481,6 +481,15 @@ class TokenAPITests(object): self.assertValidProjectScopedTokenResponse(r, is_admin_project=False) +class TokenDataTests(object): + """Test the data in specific token types.""" + + def test_unscoped_token_format(self): + # ensure the unscoped token response contains the appropriate data + r = self.get('/auth/tokens', headers=self.headers) + self.assertValidUnscopedTokenResponse(r) + + class AllowRescopeScopedTokenDisabledTests(test_v3.RestfulTestCase): def config_overrides(self): super(AllowRescopeScopedTokenDisabledTests, self).config_overrides() @@ -560,7 +569,7 @@ class AllowRescopeScopedTokenDisabledTests(test_v3.RestfulTestCase): expected_status=http_client.FORBIDDEN) -class TestPKITokenAPIs(test_v3.RestfulTestCase, TokenAPITests): +class TestPKITokenAPIs(test_v3.RestfulTestCase, TokenAPITests, TokenDataTests): def config_overrides(self): super(TestPKITokenAPIs, self).config_overrides() self.config_fixture.config(group='token', provider='pki') @@ -630,7 +639,8 @@ class TestPKIZTokenAPIs(TestPKITokenAPIs): return cms.pkiz_verify(*args, **kwargs) -class TestUUIDTokenAPIs(test_v3.RestfulTestCase, TokenAPITests): +class TestUUIDTokenAPIs(test_v3.RestfulTestCase, TokenAPITests, + TokenDataTests): def config_overrides(self): super(TestUUIDTokenAPIs, self).config_overrides() self.config_fixture.config(group='token', provider='uuid') @@ -650,7 +660,8 @@ class TestUUIDTokenAPIs(test_v3.RestfulTestCase, TokenAPITests): self.assertFalse(cms.is_asn1_token(token_id)) -class TestFernetTokenAPIs(test_v3.RestfulTestCase, TokenAPITests): +class TestFernetTokenAPIs(test_v3.RestfulTestCase, TokenAPITests, + TokenDataTests): def config_overrides(self): super(TestFernetTokenAPIs, self).config_overrides() self.config_fixture.config(group='token', provider='fernet')