From 012b2125fb121f44a1786bbd21f60568c74be367 Mon Sep 17 00:00:00 2001 From: Yogeshwar Srikrishnan Date: Tue, 20 Sep 2011 14:54:53 -0500 Subject: [PATCH] Changing authenticate request content xml as well as json. Change-Id: I26e67facf6cf535f851164c41c8c5efcac85fa50 --- AUTHORS | 1 - keystone/controllers/auth.py | 7 +-- keystone/frontends/legacy_token_auth.py | 4 +- keystone/logic/service.py | 18 ++++--- keystone/logic/types/auth.py | 49 +++++++++++-------- keystone/test/functional/common.py | 7 +-- keystone/test/functional/test_auth.py | 23 +++++---- .../test/functional/test_authentication.py | 16 +++--- keystone/test/unit/test_auth.py | 7 +-- keystone/test/unit/test_server.py | 5 +- 10 files changed, 79 insertions(+), 58 deletions(-) diff --git a/AUTHORS b/AUTHORS index c2ad738601..e3a9830b86 100644 --- a/AUTHORS +++ b/AUTHORS @@ -32,4 +32,3 @@ Vishvananda Ishaya Yogeshwar Srikrishnan Yuriy Taraday Ziad Sawalha - diff --git a/keystone/controllers/auth.py b/keystone/controllers/auth.py index 9de91f9ff2..bd30afb6ae 100644 --- a/keystone/controllers/auth.py +++ b/keystone/controllers/auth.py @@ -12,10 +12,11 @@ class AuthController(wsgi.Controller): @utils.wrap_error def authenticate(self, req): - creds = utils.get_normalized_request_content( - auth.PasswordCredentials, req) + auth_with_credentials = utils.get_normalized_request_content( + auth.AuthWithPasswordCredentials, req) - return utils.send_result(200, req, config.SERVICE.authenticate(creds)) + return utils.send_result(200, req, + config.SERVICE.authenticate(auth_with_credentials)) @utils.wrap_error def authenticate_ec2(self, req): diff --git a/keystone/frontends/legacy_token_auth.py b/keystone/frontends/legacy_token_auth.py index fce2f1140a..fb5f65f096 100644 --- a/keystone/frontends/legacy_token_auth.py +++ b/keystone/frontends/legacy_token_auth.py @@ -61,9 +61,9 @@ class AuthProtocol(object): """ Handle incoming request. Transform. And send downstream. """ request = Request(env) if env['KEYSTONE_API_VERSION'] in ['1.0', '1.1']: - params = {"passwordCredentials": + params = {"auth": {"passwordCredentials": {"username": utils.get_auth_user(request), - "password": utils.get_auth_key(request)}} + "password": utils.get_auth_key(request)}}} #Make request to keystone new_request = Request.blank('/tokens') new_request.method = 'POST' diff --git a/keystone/logic/service.py b/keystone/logic/service.py index ddb97166f8..dba9c56415 100755 --- a/keystone/logic/service.py +++ b/keystone/logic/service.py @@ -41,19 +41,23 @@ class IdentityService(object): # # Token Operations # - def authenticate(self, credentials): - # Check credentials - if not isinstance(credentials, auth.PasswordCredentials): - raise fault.BadRequestFault("Expecting Password Credentials!") + def authenticate(self, auth_with_password_credentials): + # Check auth_with_password_credentials + if not isinstance(auth_with_password_credentials, + auth.AuthWithPasswordCredentials): + raise fault.BadRequestFault( + "Expecting auth_with_password_credentials!") def validate(duser): - return api.USER.check_password(duser, credentials.password) + return api.USER.check_password( + duser, auth_with_password_credentials.password) - user = api.USER.get_by_name(credentials.username) + user = api.USER.get_by_name(auth_with_password_credentials.username) if not user: raise fault.UnauthorizedFault("Unauthorized") - return self._authenticate(validate, user.id, credentials.tenant_id) + return self._authenticate( + validate, user.id, auth_with_password_credentials.tenant_id) def authenticate_ec2(self, credentials): # Check credentials diff --git a/keystone/logic/types/auth.py b/keystone/logic/types/auth.py index 74fb5962ec..5fff98df25 100755 --- a/keystone/logic/types/auth.py +++ b/keystone/logic/types/auth.py @@ -19,11 +19,7 @@ from lxml import etree from keystone.logic.types import fault -class PasswordCredentials(object): - """Credentials based on username, password, and (optional) tenant_id. - To handle multiple token for a user depending on tenants. - """ - +class AuthWithPasswordCredentials(object): def __init__(self, username, password, tenant_id): self.username = username self.password = password @@ -35,31 +31,48 @@ class PasswordCredentials(object): dom = etree.Element("root") dom.append(etree.fromstring(xml_str)) root = dom.find("{http://docs.openstack.org/identity/api/v2.0}" - "passwordCredentials") + "auth") if root == None: + raise fault.BadRequestFault("Expecting auth") + tenant_id = root.get("tenantId") + password_credentials = \ + root.find("{http://docs.openstack.org/identity/api/v2.0}" + "passwordCredentials") + if password_credentials == None: raise fault.BadRequestFault("Expecting passwordCredentials") - username = root.get("username") + username = password_credentials.get("username") if username == None: raise fault.BadRequestFault("Expecting a username") - password = root.get("password") + password = password_credentials.get("password") if password == None: raise fault.BadRequestFault("Expecting a password") - tenant_id = root.get("tenantId") - return PasswordCredentials(username, password, tenant_id) + return AuthWithPasswordCredentials(username, password, tenant_id) except etree.LxmlError as e: - raise fault.BadRequestFault("Cannot parse password credentials", + raise fault.BadRequestFault("Cannot parse password access", str(e)) @staticmethod def from_json(json_str): try: obj = json.loads(json_str) - if not "passwordCredentials" in obj: + if not "auth" in obj: + raise fault.BadRequestFault("Expecting auth") + auth = obj["auth"] + invalid = [key for key in auth if key not in\ + ['tenantId', 'passwordCredentials']] + if invalid != []: + raise fault.BadRequestFault("Invalid attribute(s): %s" + % invalid) + if "tenantId" in auth: + tenant_id = auth["tenantId"] + else: + tenant_id = None + if not "passwordCredentials" in auth: raise fault.BadRequestFault("Expecting passwordCredentials") - cred = obj["passwordCredentials"] + cred = auth["passwordCredentials"] # Check that fields are valid invalid = [key for key in cred if key not in\ - ['username', 'tenantId', 'password']] + ['username', 'password']] if invalid != []: raise fault.BadRequestFault("Invalid attribute(s): %s" % invalid) @@ -69,13 +82,9 @@ class PasswordCredentials(object): if not "password" in cred: raise fault.BadRequestFault("Expecting a password") password = cred["password"] - if "tenantId" in cred: - tenant_id = cred["tenantId"] - else: - tenant_id = None - return PasswordCredentials(username, password, tenant_id) + return AuthWithPasswordCredentials(username, password, tenant_id) except (ValueError, TypeError) as e: - raise fault.BadRequestFault("Cannot parse password credentials", + raise fault.BadRequestFault("Cannot parse auth", str(e)) diff --git a/keystone/test/functional/common.py b/keystone/test/functional/common.py index bc4bf60d7c..1cc1615a29 100644 --- a/keystone/test/functional/common.py +++ b/keystone/test/functional/common.py @@ -463,12 +463,13 @@ class FunctionalTestCase(ApiTestCase): user_password = optional_str(user_password) data = { - "passwordCredentials": { + "auth": { + "passwordCredentials": { "username": user_name, - "password": user_password}} + "password": user_password}}} if tenant_id: - data["passwordCredentials"]["tenantId"] = tenant_id + data["auth"]["tenantId"] = tenant_id return self.post_token(as_json=data, **kwargs) diff --git a/keystone/test/functional/test_auth.py b/keystone/test/functional/test_auth.py index a8d25cf962..d192959c7f 100644 --- a/keystone/test/functional/test_auth.py +++ b/keystone/test/functional/test_auth.py @@ -53,9 +53,10 @@ class TestServiceAuthentication(common.FunctionalTestCase): """Admin should be able to validate a user's token""" # Authenticate as user to get a token self.service_token = self.post_token(as_json={ + 'auth': { 'passwordCredentials': { 'username': self.user['name'], - 'password': self.user['password']}}).\ + 'password': self.user['password']}}}).\ json['auth']['token']['id'] # In the real world, the service user would then pass his/her token @@ -87,42 +88,44 @@ class TestServiceAuthentication(common.FunctionalTestCase): """Authenticating with an unknown username returns a 401""" # Authenticate as user to get a token self.post_token(assert_status=401, as_json={ - 'passwordCredentials': { + 'auth': {'passwordCredentials': { 'username': 'this-is-completely-wrong', - 'password': self.user['password']}}) + 'password': self.user['password']}}}) def test_user_auth_with_no_name(self): """Authenticating without a username returns a 401""" # Authenticate as user to get a token self.post_token(assert_status=401, as_json={ - 'passwordCredentials': { + 'auth': {'passwordCredentials': { 'username': None, - 'password': self.user['password']}}) + 'password': self.user['password']}}}) def test_user_auth_with_wrong_password(self): """Authenticating with an invalid password returns a 401""" # Authenticate as user to get a token self.post_token(assert_status=401, as_json={ - 'passwordCredentials': { + 'auth': {'passwordCredentials': { 'username': self.user['name'], - 'password': 'this-is-completely-wrong'}}) + 'password': 'this-is-completely-wrong'}}}) def test_user_auth_with_no_password(self): """Authenticating with an invalid password returns a 401""" # Authenticate as user to get a token self.post_token(assert_status=401, as_json={ - 'passwordCredentials': { + 'auth': {'passwordCredentials': { 'username': self.user['name'], - 'password': None}}) + 'password': None}}}) def test_user_auth_with_invalid_tenant(self): """Authenticating with an invalid password returns a 401""" # Authenticate as user to get a token self.post_token(assert_status=401, as_json={ + 'auth': { 'passwordCredentials': { 'username': self.user['name'], 'password': self.user['password'], - 'tenantId': 'this-is-completely-wrong'}}) + }, + 'tenantId': 'this-is-completely-wrong'}}) if __name__ == '__main__': diff --git a/keystone/test/functional/test_authentication.py b/keystone/test/functional/test_authentication.py index 24dbe7e5eb..485477ea5b 100755 --- a/keystone/test/functional/test_authentication.py +++ b/keystone/test/functional/test_authentication.py @@ -48,10 +48,11 @@ class AuthenticationTest(common.FunctionalTestCase): def test_authorize_xml(self): data = (' ' - ' ') % ( - self.xmlns, self.user['name'], self.user['password'], - self.tenant['id']) + '' + ' ') % ( + self.xmlns, self.tenant['id'], + self.user['name'], self.user['password']) r = self.post_token(as_xml=data, assert_status=200) self.assertEquals(r.xml.tag, '{%s}auth' % self.xmlns) @@ -74,9 +75,10 @@ class AuthenticationTest(common.FunctionalTestCase): def test_authorize_user_wrong(self): data = { - "passwordCredentials": { - "username-field-completely-wrong": self.user['name'], - "password": self.user['password'], + "auth": { + "passwordCredentials": { + "username-field-completely-wrong": self.user['name'], + "password": self.user['password']}, "tenantId": self.tenant['id']}} self.post_token(as_json=data, assert_status=400) diff --git a/keystone/test/unit/test_auth.py b/keystone/test/unit/test_auth.py index 7ea9e36758..4242ce8c4f 100755 --- a/keystone/test/unit/test_auth.py +++ b/keystone/test/unit/test_auth.py @@ -5,14 +5,15 @@ import keystone.logic.types.auth as auth class TestAuth(unittest.TestCase): '''Unit tests for auth.py.''' - pwd_xml = ' \ + pwd_xml = '\ + \ ' + />' def test_pwd_cred_marshall(self): - creds = auth.PasswordCredentials.from_xml(self.pwd_xml) + creds = auth.AuthWithPasswordCredentials.from_xml(self.pwd_xml) self.assertTrue(creds.password, "secret") self.assertTrue(creds.username, "username") diff --git a/keystone/test/unit/test_server.py b/keystone/test/unit/test_server.py index 9ec0dc03b5..aba0b487f8 100755 --- a/keystone/test/unit/test_server.py +++ b/keystone/test/unit/test_server.py @@ -70,12 +70,13 @@ class TestServer(unittest.TestCase): def test_get_normalized_request_content_xml(self): self.request.environ["CONTENT_TYPE"] = "application/xml" - auth.PasswordCredentials("username", "password", "1") + auth.AuthWithPasswordCredentials("username", "password", "1") body = ' \ + \ ' + />' str = StringIO() str.write(body) self.request.environ["wsgi.input"] = str