Allow configuring salt manually

Older versions of swauth supported manually setting up a salt string in
conf file. This change re-introduces it and makes it a tunable option.

The current behavior of randomly generating salt for every password is
NOT affected with this change.

Change-Id: Ifdf6f806b954e4d41c083eeffa981cd7d0dd50b9
Signed-off-by: Prashanth Pai <ppai@redhat.com>
This commit is contained in:
Prashanth Pai 2016-02-26 15:38:27 +05:30
parent ac9698ae4d
commit e0b0292a27
4 changed files with 48 additions and 2 deletions

View File

@ -51,6 +51,10 @@ use = egg:swauth#swauth
# An alternative is 'sha512' which stores only a one-way hash of the key leaving # An alternative is 'sha512' which stores only a one-way hash of the key leaving
# it secure but unavailable for key-signing. # it secure but unavailable for key-signing.
# auth_type = plaintext # auth_type = plaintext
# Used if the auth_type is sha1 or sha512. Salt is data(text) that is used as
# an additional input to the one-way encoding function. If not set, a random
# salt will be generated for each password.
# auth_type_salt =
# This allows middleware higher in the WSGI pipeline to override auth # This allows middleware higher in the WSGI pipeline to override auth
# processing, useful for middleware such as tempurl and formpost. If you know # processing, useful for middleware such as tempurl and formpost. If you know
# you're not going to use such middleware and you want a bit of extra security, # you're not going to use such middleware and you want a bit of extra security,

View File

@ -89,10 +89,13 @@ class Sha1(object):
"""Encodes a user key into a particular format. The result of this method """Encodes a user key into a particular format. The result of this method
will be used by swauth for storing user credentials. will be used by swauth for storing user credentials.
If salt is not manually set in conf file, a random salt will be
generated and used.
:param key: User's secret key :param key: User's secret key
:returns: A string representing user credentials :returns: A string representing user credentials
""" """
salt = os.urandom(32).encode('base64').rstrip() salt = self.salt or os.urandom(32).encode('base64').rstrip()
return self.encode_w_salt(salt, key) return self.encode_w_salt(salt, key)
def match(self, key, creds): def match(self, key, creds):
@ -134,10 +137,13 @@ class Sha512(object):
"""Encodes a user key into a particular format. The result of this method """Encodes a user key into a particular format. The result of this method
will be used by swauth for storing user credentials. will be used by swauth for storing user credentials.
If salt is not manually set in conf file, a random salt will be
generated and used.
:param key: User's secret key :param key: User's secret key
:returns: A string representing user credentials :returns: A string representing user credentials
""" """
salt = os.urandom(32).encode('base64').rstrip() salt = self.salt or os.urandom(32).encode('base64').rstrip()
return self.encode_w_salt(salt, key) return self.encode_w_salt(salt, key)
def match(self, key, creds): def match(self, key, creds):

View File

@ -165,6 +165,9 @@ class Swauth(object):
if self.auth_encoder is None: if self.auth_encoder is None:
raise ValueError('Invalid auth_type in config file: %s' raise ValueError('Invalid auth_type in config file: %s'
% self.auth_type) % self.auth_type)
# If auth_type_salt is not set in conf file, a random salt will be
# generated for each new password to be encoded.
self.auth_encoder.salt = conf.get('auth_type_salt', None)
self.allow_overrides = \ self.allow_overrides = \
conf.get('allow_overrides', 't').lower() in TRUE_VALUES conf.get('allow_overrides', 't').lower() in TRUE_VALUES
self.agent = '%(orig)s Swauth' self.agent = '%(orig)s Swauth'

View File

@ -119,6 +119,39 @@ class TestAuth(unittest.TestCase):
'token_life': str(DEFAULT_TOKEN_LIFE), 'token_life': str(DEFAULT_TOKEN_LIFE),
'max_token_life': str(MAX_TOKEN_LIFE)})(FakeApp()) 'max_token_life': str(MAX_TOKEN_LIFE)})(FakeApp())
def test_salt(self):
for auth_type in ('sha1', 'sha512'):
# Salt not manually set
test_auth = \
auth.filter_factory({
'super_admin_key': 'supertest',
'token_life': str(DEFAULT_TOKEN_LIFE),
'max_token_life': str(MAX_TOKEN_LIFE),
'auth_type': auth_type})(FakeApp())
self.assertEqual(test_auth.auth_encoder.salt, None)
mock_urandom = mock.Mock(return_value="abc")
with mock.patch("os.urandom", mock_urandom):
h_key = test_auth.auth_encoder().encode("key")
self.assertTrue(mock_urandom.called)
prefix = auth_type + ":" + "abc".encode('base64').rstrip() + '$'
self.assertTrue(h_key.startswith(prefix))
# Salt manually set
test_auth = \
auth.filter_factory({
'super_admin_key': 'supertest',
'token_life': str(DEFAULT_TOKEN_LIFE),
'max_token_life': str(MAX_TOKEN_LIFE),
'auth_type': auth_type,
'auth_type_salt': "mysalt"})(FakeApp())
self.assertEqual(test_auth.auth_encoder.salt, "mysalt")
mock_urandom = mock.Mock()
with mock.patch("os.urandom", mock_urandom):
h_key = test_auth.auth_encoder().encode("key")
self.assertFalse(mock_urandom.called)
prefix = auth_type + ":" + "mysalt" + '$'
self.assertTrue(h_key.startswith(prefix))
def test_swift_version(self): def test_swift_version(self):
app = FakeApp() app = FakeApp()