From 18f3684046256529baf1d6eb9ce100c9ac3f8cac Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Thu, 7 Apr 2011 02:07:19 +0900 Subject: [PATCH 1/7] Enable RightAWS style signing on server_string without port number portion. --- nova/auth/manager.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/nova/auth/manager.py b/nova/auth/manager.py index 48684539..b51cc7f4 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -315,6 +315,15 @@ class AuthManager(object): LOG.debug('expected_signature: %s', expected_signature) LOG.debug('signature: %s', signature) if signature != expected_signature: + secondary = utils.get_secondary_server_string(server_string) + if secondary is not '': + secondary_signature = signer.Signer( + user.secret.encode()).generate(params, verb, + secondary, path) + LOG.debug('secondary_signature: %s', secondary_signature) + if signature == secondary_signature: + return (user, project) + # NOTE(itoumsn): RightAWS success case. LOG.audit(_("Invalid signature for user %s"), user.name) raise exception.NotAuthorized(_('Signature does not match')) return (user, project) From e3845e65efb06d777a89e76a4fea8a616fe908a8 Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Thu, 7 Apr 2011 11:42:02 +0900 Subject: [PATCH 2/7] pep8 cleanup. --- nova/auth/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/auth/manager.py b/nova/auth/manager.py index b51cc7f4..f1d4a1e3 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -315,7 +315,7 @@ class AuthManager(object): LOG.debug('expected_signature: %s', expected_signature) LOG.debug('signature: %s', signature) if signature != expected_signature: - secondary = utils.get_secondary_server_string(server_string) + secondary = utils.get_secondary_server_string(server_string) if secondary is not '': secondary_signature = signer.Signer( user.secret.encode()).generate(params, verb, From 1283424a7ba0ea5c2a32ecd5b13b5fe62bbf329c Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Thu, 7 Apr 2011 23:48:00 +0900 Subject: [PATCH 3/7] Blush up a bit. --- nova/auth/manager.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/nova/auth/manager.py b/nova/auth/manager.py index f1d4a1e3..c8a3a46a 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -315,15 +315,15 @@ class AuthManager(object): LOG.debug('expected_signature: %s', expected_signature) LOG.debug('signature: %s', signature) if signature != expected_signature: - secondary = utils.get_secondary_server_string(server_string) - if secondary is not '': - secondary_signature = signer.Signer( + host_only = utils.get_host_only_server_string(server_string) + # If the given server_string contains port num, try without it. + if host_only is not '': + host_only_signature = signer.Signer( user.secret.encode()).generate(params, verb, - secondary, path) - LOG.debug('secondary_signature: %s', secondary_signature) - if signature == secondary_signature: + host_only, path) + LOG.debug('host_only_signature: %s', host_only_signature) + if signature == host_only_signature: return (user, project) - # NOTE(itoumsn): RightAWS success case. LOG.audit(_("Invalid signature for user %s"), user.name) raise exception.NotAuthorized(_('Signature does not match')) return (user, project) From 8e030164de8c1582eee961af0fce1bb74d7a9b2f Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Wed, 13 Apr 2011 02:11:36 +0900 Subject: [PATCH 4/7] Blushed up a little bit. --- nova/auth/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/auth/manager.py b/nova/auth/manager.py index c8a3a46a..01aa87e3 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -317,7 +317,7 @@ class AuthManager(object): if signature != expected_signature: host_only = utils.get_host_only_server_string(server_string) # If the given server_string contains port num, try without it. - if host_only is not '': + if host_only != '': host_only_signature = signer.Signer( user.secret.encode()).generate(params, verb, host_only, path) From 3f8c4d8eef9f1efc577798ce814a22bbc762387a Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Thu, 14 Apr 2011 10:47:37 +0900 Subject: [PATCH 5/7] Updated following to RIck's comments. --- nova/auth/manager.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/nova/auth/manager.py b/nova/auth/manager.py index 01aa87e3..dc37ae06 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -300,9 +300,9 @@ class AuthManager(object): if check_type == 's3': sign = signer.Signer(user.secret.encode()) expected_signature = sign.s3_authorization(headers, verb, path) - LOG.debug('user.secret: %s', user.secret) - LOG.debug('expected_signature: %s', expected_signature) - LOG.debug('signature: %s', signature) + LOG.debug(_('user.secret: %s'), user.secret) + LOG.debug(_('expected_signature: %s'), expected_signature) + LOG.debug(_('signature: %s'), signature) if signature != expected_signature: LOG.audit(_("Invalid signature for user %s"), user.name) raise exception.NotAuthorized(_('Signature does not match')) @@ -311,9 +311,9 @@ class AuthManager(object): # secret isn't unicode expected_signature = signer.Signer(user.secret.encode()).generate( params, verb, server_string, path) - LOG.debug('user.secret: %s', user.secret) - LOG.debug('expected_signature: %s', expected_signature) - LOG.debug('signature: %s', signature) + LOG.debug(_('user.secret: %s'), user.secret) + LOG.debug(_('expected_signature: %s'), expected_signature) + LOG.debug(_('signature: %s'), signature) if signature != expected_signature: host_only = utils.get_host_only_server_string(server_string) # If the given server_string contains port num, try without it. @@ -321,7 +321,8 @@ class AuthManager(object): host_only_signature = signer.Signer( user.secret.encode()).generate(params, verb, host_only, path) - LOG.debug('host_only_signature: %s', host_only_signature) + LOG.debug(_('host_only_signature: %s'), + host_only_signature) if signature == host_only_signature: return (user, project) LOG.audit(_("Invalid signature for user %s"), user.name) From 27662ff3eddc64f69feb69c733fdb2e6d081864b Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Fri, 22 Apr 2011 01:26:59 +0900 Subject: [PATCH 6/7] Utility method reworked, etc. --- nova/auth/authutils.py | 48 +++++++++++++++++++++++++++++++++++++++++ nova/auth/manager.py | 4 +++- nova/tests/test_auth.py | 24 +++++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 nova/auth/authutils.py diff --git a/nova/auth/authutils.py b/nova/auth/authutils.py new file mode 100644 index 00000000..429e86ef --- /dev/null +++ b/nova/auth/authutils.py @@ -0,0 +1,48 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 NTT DATA CORPORATION. +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +Auth module specific utilities and helper functions. +""" + +import netaddr +import string + + +def get_host_only_server_string(server_str): + """ + Returns host part only of the given server_string if it's a combination + of host part and port. Otherwise, return null string. + """ + + # First of all, exclude pure IPv6 address (w/o port). + if netaddr.valid_ipv6(server_str): + return '' + + # Next, check if this is IPv6 address with port number combination. + if server_str.find("]:") != -1: + [address, sep, port] = server_str.replace('[', '', 1).partition(']:') + return address + + # Third, check if this is a combination of general address and port + if server_str.find(':') == -1: + return '' + + # This must be a combination of host part and port + (address, port) = server_str.split(':') + return address diff --git a/nova/auth/manager.py b/nova/auth/manager.py index 06def220..775b38af 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -35,6 +35,7 @@ from nova import flags from nova import log as logging from nova import utils from nova.auth import signer +from nova.auth import authutils FLAGS = flags.FLAGS @@ -315,7 +316,8 @@ class AuthManager(object): LOG.debug(_('expected_signature: %s'), expected_signature) LOG.debug(_('signature: %s'), signature) if signature != expected_signature: - host_only = utils.get_host_only_server_string(server_string) + host_only = authutils.get_host_only_server_string( + server_string) # If the given server_string contains port num, try without it. if host_only != '': host_only_signature = signer.Signer( diff --git a/nova/tests/test_auth.py b/nova/tests/test_auth.py index f8a1b156..3886e9e6 100644 --- a/nova/tests/test_auth.py +++ b/nova/tests/test_auth.py @@ -25,6 +25,7 @@ from nova import log as logging from nova import test from nova.auth import manager from nova.api.ec2 import cloud +from nova.auth import authutils FLAGS = flags.FLAGS LOG = logging.getLogger('nova.tests.auth_unittest') @@ -339,6 +340,29 @@ class AuthManagerDbTestCase(_AuthManagerBaseTestCase): auth_driver = 'nova.auth.dbdriver.DbDriver' +class AuthManagerUtilTestCase(test.TestCase): + def test_get_host_only_server_string(self): + result = authutils.get_host_only_server_string('::1') + self.assertEqual('', result) + result = authutils.get_host_only_server_string('[::1]:8773') + self.assertEqual('::1', result) + result = authutils.get_host_only_server_string('2001:db8::192.168.1.1') + self.assertEqual('', result) + result = authutils.get_host_only_server_string( + '[2001:db8::192.168.1.1]:8773') + self.assertEqual('2001:db8::192.168.1.1', result) + result = authutils.get_host_only_server_string('192.168.1.1') + self.assertEqual('', result) + result = authutils.get_host_only_server_string('192.168.1.2:8773') + self.assertEqual('192.168.1.2', result) + result = authutils.get_host_only_server_string('192.168.1.3') + self.assertEqual('', result) + result = authutils.get_host_only_server_string('www.example.com:8443') + self.assertEqual('www.example.com', result) + result = authutils.get_host_only_server_string('www.example.com') + self.assertEqual('', result) + + if __name__ == "__main__": # TODO: Implement use_fake as an option unittest.main() From 4683480df0a22e5ddb351dfd6a51df0e93395051 Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Fri, 22 Apr 2011 21:35:54 +0900 Subject: [PATCH 7/7] Rework completed. Added test cases, changed helper method name, etc. --- nova/auth/authutils.py | 48 ------------------------------- nova/auth/manager.py | 8 ++---- nova/tests/test_auth.py | 64 ++++++++++++++++++++++++----------------- 3 files changed, 40 insertions(+), 80 deletions(-) delete mode 100644 nova/auth/authutils.py diff --git a/nova/auth/authutils.py b/nova/auth/authutils.py deleted file mode 100644 index 429e86ef..00000000 --- a/nova/auth/authutils.py +++ /dev/null @@ -1,48 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 NTT DATA CORPORATION. -# Copyright 2011 OpenStack LLC. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Auth module specific utilities and helper functions. -""" - -import netaddr -import string - - -def get_host_only_server_string(server_str): - """ - Returns host part only of the given server_string if it's a combination - of host part and port. Otherwise, return null string. - """ - - # First of all, exclude pure IPv6 address (w/o port). - if netaddr.valid_ipv6(server_str): - return '' - - # Next, check if this is IPv6 address with port number combination. - if server_str.find("]:") != -1: - [address, sep, port] = server_str.replace('[', '', 1).partition(']:') - return address - - # Third, check if this is a combination of general address and port - if server_str.find(':') == -1: - return '' - - # This must be a combination of host part and port - (address, port) = server_str.split(':') - return address diff --git a/nova/auth/manager.py b/nova/auth/manager.py index 775b38af..d42594c8 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -35,7 +35,6 @@ from nova import flags from nova import log as logging from nova import utils from nova.auth import signer -from nova.auth import authutils FLAGS = flags.FLAGS @@ -316,13 +315,12 @@ class AuthManager(object): LOG.debug(_('expected_signature: %s'), expected_signature) LOG.debug(_('signature: %s'), signature) if signature != expected_signature: - host_only = authutils.get_host_only_server_string( - server_string) + (addr_str, port_str) = utils.parse_server_string(server_string) # If the given server_string contains port num, try without it. - if host_only != '': + if port_str != '': host_only_signature = signer.Signer( user.secret.encode()).generate(params, verb, - host_only, path) + addr_str, path) LOG.debug(_('host_only_signature: %s'), host_only_signature) if signature == host_only_signature: diff --git a/nova/tests/test_auth.py b/nova/tests/test_auth.py index 3886e9e6..f02dd94b 100644 --- a/nova/tests/test_auth.py +++ b/nova/tests/test_auth.py @@ -25,7 +25,6 @@ from nova import log as logging from nova import test from nova.auth import manager from nova.api.ec2 import cloud -from nova.auth import authutils FLAGS = flags.FLAGS LOG = logging.getLogger('nova.tests.auth_unittest') @@ -102,9 +101,43 @@ class _AuthManagerBaseTestCase(test.TestCase): self.assertEqual('private-party', u.access) def test_004_signature_is_valid(self): - #self.assertTrue(self.manager.authenticate(**boto.generate_url ...? )) - pass - #raise NotImplementedError + with user_generator(self.manager, name='admin', secret='admin', + access='admin'): + with project_generator(self.manager, name="admin", + manager_user='admin'): + accesskey = 'admin:admin' + expected_result = (self.manager.get_user('admin'), + self.manager.get_project('admin')) + # captured sig and query string using boto 1.9b/euca2ools 1.2 + sig = 'd67Wzd9Bwz8xid9QU+lzWXcF2Y3tRicYABPJgrqfrwM=' + auth_params = {'AWSAccessKeyId': 'admin:admin', + 'Action': 'DescribeAvailabilityZones', + 'SignatureMethod': 'HmacSHA256', + 'SignatureVersion': '2', + 'Timestamp': '2011-04-22T11:29:29', + 'Version': '2009-11-30'} + self.assertTrue(expected_result, self.manager.authenticate( + accesskey, + sig, + auth_params, + 'GET', + '127.0.0.1:8773', + '/services/Cloud/')) + # captured sig and query string using RightAWS 1.10.0 + sig = 'ECYLU6xdFG0ZqRVhQybPJQNJ5W4B9n8fGs6+/fuGD2c=' + auth_params = {'AWSAccessKeyId': 'admin:admin', + 'Action': 'DescribeAvailabilityZones', + 'SignatureMethod': 'HmacSHA256', + 'SignatureVersion': '2', + 'Timestamp': '2011-04-22T11:29:49.000Z', + 'Version': '2008-12-01'} + self.assertTrue(expected_result, self.manager.authenticate( + accesskey, + sig, + auth_params, + 'GET', + '127.0.0.1', + '/services/Cloud')) def test_005_can_get_credentials(self): return @@ -340,29 +373,6 @@ class AuthManagerDbTestCase(_AuthManagerBaseTestCase): auth_driver = 'nova.auth.dbdriver.DbDriver' -class AuthManagerUtilTestCase(test.TestCase): - def test_get_host_only_server_string(self): - result = authutils.get_host_only_server_string('::1') - self.assertEqual('', result) - result = authutils.get_host_only_server_string('[::1]:8773') - self.assertEqual('::1', result) - result = authutils.get_host_only_server_string('2001:db8::192.168.1.1') - self.assertEqual('', result) - result = authutils.get_host_only_server_string( - '[2001:db8::192.168.1.1]:8773') - self.assertEqual('2001:db8::192.168.1.1', result) - result = authutils.get_host_only_server_string('192.168.1.1') - self.assertEqual('', result) - result = authutils.get_host_only_server_string('192.168.1.2:8773') - self.assertEqual('192.168.1.2', result) - result = authutils.get_host_only_server_string('192.168.1.3') - self.assertEqual('', result) - result = authutils.get_host_only_server_string('www.example.com:8443') - self.assertEqual('www.example.com', result) - result = authutils.get_host_only_server_string('www.example.com') - self.assertEqual('', result) - - if __name__ == "__main__": # TODO: Implement use_fake as an option unittest.main()