Add support for setting already hashed password

You can use this for restoring dumped users list from swauth-list
command.
Change-Id: Ia77d7a0b91b2f79999286858e383477a80d7db15
This commit is contained in:
Ondřej Nový 2016-05-23 17:47:07 +02:00
parent 9b27778987
commit b548d3dcf7
4 changed files with 77 additions and 4 deletions

View File

@ -43,6 +43,9 @@ if __name__ == '__main__':
'the account already exists, this will have no effect on existing '
'service URLs. Those will need to be updated with '
'swauth-set-account-service')
parser.add_option('-e', '--hashed', dest='password_hashed',
action='store_true', default=False, help='Supplied password is '
'already hashed and in format <auth_type>:<hashed_password>')
parser.add_option('-A', '--admin-url', dest='admin_url',
default='http://127.0.0.1:8080/auth/', help='The URL to the auth '
'subsystem (default: http://127.0.0.1:8080/auth/')
@ -91,12 +94,15 @@ if __name__ == '__main__':
path = '%sv2/%s/%s' % (parsed_path, account, user)
headers = {'X-Auth-Admin-User': options.admin_user,
'X-Auth-Admin-Key': options.admin_key,
'X-Auth-User-Key': password,
'Content-Length': '0'}
if options.admin:
headers['X-Auth-User-Admin'] = 'true'
if options.reseller_admin:
headers['X-Auth-User-Reseller-Admin'] = 'true'
if options.password_hashed:
headers['X-Auth-User-Key-Hash'] = password
else:
headers['X-Auth-User-Key'] = password
conn = http_connect(parsed.hostname, parsed.port, 'PUT', path, headers,
ssl=(parsed.scheme == 'https'))
resp = conn.getresponse()

View File

@ -287,7 +287,9 @@ A user can be created with a PUT request against a non-existent
user URI. The new user's password must be set using the
``X-Auth-User-Key`` header. The user name MUST NOT start with a
period ('.'). This requirement is enforced by the API, and will
result in a 400 error.
result in a 400 error. Alternatively you can use
``X-Auth-User-Key-Hash`` header for providing already hashed
password in format ``<auth_type>:<hashed_password>``.
Optional Headers:

View File

@ -1038,6 +1038,8 @@ class Swauth(object):
account.
X-Auth-User-Key represents the user's key (url encoded),
- OR -
X-Auth-User-Key-Hash represents the user's hashed key (url encoded),
X-Auth-User-Admin may be set to `true` to create an account .admin, and
X-Auth-User-Reseller-Admin may be set to `true` to create a
.reseller_admin.
@ -1062,14 +1064,22 @@ class Swauth(object):
account = req.path_info_pop()
user = req.path_info_pop()
key = unquote(req.headers.get('x-auth-user-key', ''))
key_hash = unquote(req.headers.get('x-auth-user-key-hash', ''))
admin = req.headers.get('x-auth-user-admin') == 'true'
reseller_admin = \
req.headers.get('x-auth-user-reseller-admin') == 'true'
if reseller_admin:
admin = True
if req.path_info or not account or account[0] == '.' or not user or \
user[0] == '.' or not key:
user[0] == '.' or (not key and not key_hash):
return HTTPBadRequest(request=req)
if key_hash:
if ':' not in key_hash:
return HTTPBadRequest(request=req)
auth_type, hash = key_hash.split(':')
if getattr(swauth.authtypes, auth_type.title(), None) is None:
return HTTPBadRequest(request=req)
user_arg = account + ':' + user
if reseller_admin:
if not self.is_super_admin(req) and\
@ -1095,7 +1105,7 @@ class Swauth(object):
groups.append('.admin')
if reseller_admin:
groups.append('.reseller_admin')
auth_value = self.auth_encoder().encode(key)
auth_value = key_hash or self.auth_encoder().encode(key)
resp = self.make_pre_authed_request(
req.environ, 'PUT', path,
json.dumps({'auth': auth_value,

View File

@ -18,6 +18,7 @@ import json
import mock
from time import time
import unittest
from urllib import quote
from swift.common.swob import Request
from swift.common.swob import Response
@ -3025,6 +3026,60 @@ class TestAuth(unittest.TestCase):
self.assertEqual(resp.status_int, 500)
self.assertEqual(self.test_auth.app.calls, 1)
def test_put_user_key_hash(self):
key_hash = ("sha512:aSm0jEeqIp46T5YLZy1r8+cXs/Xzs1S4VUwVauhBs44=$ef"
"7332ec1288bf69c75682eb8d459d5a84baa7e43f45949c242a9af9"
"7130ef16ac361fe1aa33a789e218122b83c54ef1923fc015080741"
"ca21f6187329f6cb7a")
self.test_auth.app = FakeApp(iter([
('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
# PUT of user object
('201 Created', {}, '')]))
resp = Request.blank('/auth/v2/act/usr',
environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Auth-Admin-User': '.super_admin',
'X-Auth-Admin-Key': 'supertest',
'X-Auth-User-Key-Hash': quote(key_hash)}
).get_response(self.test_auth)
self.assertEqual(resp.status_int, 201)
self.assertEqual(self.test_auth.app.calls, 2)
self.assertEqual(json.loads(self.test_auth.app.request.body),
{"groups": [{"name": "act:usr"}, {"name": "act"}],
"auth": key_hash})
def test_put_user_key_hash_wrong_type(self):
key_hash = "wrong_auth_type:1234"
self.test_auth.app = FakeApp(iter([
('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
# PUT of user object
('201 Created', {}, '')]))
resp = Request.blank('/auth/v2/act/usr',
environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Auth-Admin-User': '.super_admin',
'X-Auth-Admin-Key': 'supertest',
'X-Auth-User-Key-Hash': quote(key_hash)}
).get_response(self.test_auth)
self.assertEqual(resp.status_int, 400)
self.assertEqual(self.test_auth.app.calls, 0)
def test_put_user_key_hash_wrong_format(self):
key_hash = "1234"
self.test_auth.app = FakeApp(iter([
('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
# PUT of user object
('201 Created', {}, '')]))
resp = Request.blank('/auth/v2/act/usr',
environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Auth-Admin-User': '.super_admin',
'X-Auth-Admin-Key': 'supertest',
'X-Auth-User-Key-Hash': quote(key_hash)}
).get_response(self.test_auth)
self.assertEqual(resp.status_int, 400)
self.assertEqual(self.test_auth.app.calls, 0)
def test_delete_user_bad_creds(self):
self.test_auth.app = FakeApp(iter([
('200 Ok', {}, json.dumps({"groups": [{"name": "act2:adm"},