From 9dcd6c1cd2d6f3f25b97f16ea405a0f3b1c9073f Mon Sep 17 00:00:00 2001 From: Dolph Mathews Date: Tue, 19 Jul 2011 15:25:21 -0500 Subject: - System test framework can now assert specific response codes automatically - Revised system test for issue #85 based on clarification from Ziad - Added system test to attempt admin action using a service token --- keystone/test/system/common.py | 26 +++++++------- keystone/test/system/test_auth.py | 54 +++++++++++++++++++++++++++++- keystone/test/system/test_issue_85.py | 21 +++++++----- keystone/test/system/test_request_specs.py | 2 +- 4 files changed, 79 insertions(+), 24 deletions(-) diff --git a/keystone/test/system/common.py b/keystone/test/system/common.py index b33537b2..1e2fd206 100644 --- a/keystone/test/system/common.py +++ b/keystone/test/system/common.py @@ -5,7 +5,7 @@ class HttpTestCase(unittest.TestCase): """Performs generic HTTP request testing""" def request(self, host='127.0.0.1', port=80, method='GET', path='/', - headers={}, body=None, expect_exception=False,): + headers={}, body=None, assert_status=None): """Perform request and fetch httplib.HTTPResponse from the server""" # Initialize a connection @@ -22,26 +22,26 @@ class HttpTestCase(unittest.TestCase): connection.close() # Automatically assert HTTP status code - if not expect_exception: - self.assertSuccessfulResponse(response) + if assert_status: + self.assertResponseStatus(response, assert_status) else: - self.assertExceptionalResponse(response) + self.assertResponseSuccessful(response) # Contains the response headers, body, etc return response - - def assertSuccessfulResponse(self, response): + + def assertResponseSuccessful(self, response): """Asserts that a status code lies inside the 2xx range""" self.assertTrue(response.status >= 200 and response.status <= 299, - 'Status code %d is outside of the expected range (2xx) \n\n%s' % - (response.status, response.body)) - - def assertExceptionalResponse(self, response): - """Asserts that a status code lies outside the 2xx range""" - self.assertFalse(response.status >= 200 and response.status <= 299, - 'Status code %d is outside of the expected range (not 2xx)\n\n%s' % + 'Status code %d is outside of the expected range (2xx)\n\n%s' % (response.status, response.body)) + def assertResponseStatus(self, response, assert_status): + """Asserts a specific status code on the response""" + self.assertEqual(response.status, assert_status, + 'Status code %s is not %s, as expected)\n\n%s' % + (response.status, assert_status, response.body)) + class RestfulTestCase(HttpTestCase): """Performs restful HTTP request testing""" diff --git a/keystone/test/system/test_auth.py b/keystone/test/system/test_auth.py index 697c928a..b11eb3e8 100644 --- a/keystone/test/system/test_auth.py +++ b/keystone/test/system/test_auth.py @@ -18,6 +18,58 @@ class TestAdminAuthentication(KeystoneTestCase): self.assertTrue(r.json['auth']['token']['id']) self.assertTrue(r.json['auth']['token']['expires']) +class TestAdminAuthenticationNegative(KeystoneTestCase): + """Negative test admin-side user authentication""" + + user_id = KeystoneTestCase._uuid() + user_id2 = KeystoneTestCase._uuid() + + def test_service_token_as_admin_token(self): + """Admin actions should fail for mere service tokens""" + + # Admin create a user + self.admin_request(method='PUT', path='/users', + json={ + 'user': { + 'id': self.user_id, + 'password': 'secrete', + 'email': self.user_id + '@openstack.org', + 'enabled': True, + } + }) + + # User authenticates to get a token + r = self.service_request(method='POST', path='/tokens', + json={ + 'passwordCredentials': { + 'username': self.user_id, + 'password': 'secrete', + } + }) + self.service_token = r.json['auth']['token']['id'] + + # Prepare to use the service token as an admin token + self.admin_token_backup = self.admin_token + self.admin_token = self.service_token + + # Try creating another user + self.admin_request(method='PUT', path='/users', assert_status=401, + json={ + 'user': { + 'id': self.user_id2, + 'password': 'secrete', + 'email': self.user_id2 + '@openstack.org', + 'enabled': True, + } + }) + + def tearDown(self): + # Restore our admin token so we can clean up + self.admin_token = self.admin_token_backup + + # Delete user + self.admin_request(method='DELETE', path='/users/%s' % self.user_id) + class TestServiceAuthentication(KeystoneTestCase): """Test service-side user authentication""" @@ -32,7 +84,7 @@ class TestServiceAuthentication(KeystoneTestCase): 'user': { 'id': self.user_id, 'password': 'secrete', - 'email': 'user@openstack.org', + 'email': self.user_id + '@openstack.org', 'enabled': True, } }) diff --git a/keystone/test/system/test_issue_85.py b/keystone/test/system/test_issue_85.py index 76490232..f9ec8066 100644 --- a/keystone/test/system/test_issue_85.py +++ b/keystone/test/system/test_issue_85.py @@ -20,7 +20,7 @@ class TestIssue85(KeystoneTestCase): } }) - # Create a user + # Create a user for a specific tenant self.admin_request(method='PUT', path='/users', json={ 'user':{ @@ -28,7 +28,7 @@ class TestIssue85(KeystoneTestCase): 'password': 'secrete', 'email': 'user@openstack.org', 'enabled': True, - 'tenant_id': 'tenant', + 'tenantId': self.tenant_id } }) @@ -43,18 +43,20 @@ class TestIssue85(KeystoneTestCase): def test_disabling_tenant_disables_token(self): """Disabling a tenant should invalidate previously-issued tokens""" - # Authenticate as user to get a token + # Authenticate as user to get a token *for a specific tenant* r = self.service_request(method='POST', path='/tokens', json={ 'passwordCredentials': { 'username': self.user_id, 'password': 'secrete', + 'tenantId': self.tenant_id } }) self.service_token = r.json['auth']['token']['id'] - # Validate tenant token - self.admin_request(path='/tokens/%s' % self.service_token) + # Validate and check that token belongs to tenant + self.admin_request(path='/tokens/%s?belongsTo=%s' % + (self.service_token, self.tenant_id)) # Disable tenant r = self.admin_request(method='PUT', @@ -67,10 +69,11 @@ class TestIssue85(KeystoneTestCase): }) self.assertEqual(r.json['tenant']['enabled'], False) - # Assert tenant token invalidated - # Commented this out because it will fail this test -# self.admin_request(path='/tokens/%s' % self.service_token, -# expect_exception=True) + # Assert that token belonging to disabled tenant is invalid + r = self.admin_request(path='/tokens/%s?belongsTo=%s' % + (self.service_token, self.tenant_id), + assert_status=403) + self.assertTrue(r.json['tenantDisabled'], 'Tenant is disabled') if __name__ == '__main__': unittest.main() diff --git a/keystone/test/system/test_request_specs.py b/keystone/test/system/test_request_specs.py index 549181a5..04e390c7 100644 --- a/keystone/test/system/test_request_specs.py +++ b/keystone/test/system/test_request_specs.py @@ -56,7 +56,7 @@ class TestContentTypes(KeystoneTestCase): """Content-Type should be honored even on 404 errors (Issue #13)""" _r = self.service_request(path='/completely-invalid-path', headers={'Accept': 'application/xml'}, - expect_exception=True) + assert_status=404) # Commenting this assertion out, as it currently fails # self.assertTrue('application/xml' in r.getheader('Content-Type'), -- cgit