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
# it secure but unavailable for key-signing.
# 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
# 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,

View File

@ -89,10 +89,13 @@ class Sha1(object):
"""Encodes a user key into a particular format. The result of this method
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
: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)
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
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
: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)
def match(self, key, creds):

View File

@ -165,6 +165,9 @@ class Swauth(object):
if self.auth_encoder is None:
raise ValueError('Invalid auth_type in config file: %s'
% 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 = \
conf.get('allow_overrides', 't').lower() in TRUE_VALUES
self.agent = '%(orig)s Swauth'

View File

@ -119,6 +119,39 @@ class TestAuth(unittest.TestCase):
'token_life': str(DEFAULT_TOKEN_LIFE),
'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):
app = FakeApp()