Per Chuck's suggestion, changed noaccess to admin access, where admin access is not the default. Also, changed swift-auth-create-account to swift-auth-add-user with changes to use optparse
This commit is contained in:
parent
65eb19f103
commit
0066ed02d7
@ -15,6 +15,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
from ConfigParser import ConfigParser
|
||||
from optparse import OptionParser
|
||||
from os.path import basename
|
||||
from sys import argv, exit
|
||||
|
||||
@ -22,45 +23,37 @@ from swift.common.bufferedhttp import http_connect_raw as http_connect
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
f = '/etc/swift/auth-server.conf'
|
||||
good = False
|
||||
noaccess = False
|
||||
if len(argv) == 6 and argv[4] == 'noaccess':
|
||||
good = True
|
||||
noaccess = True
|
||||
f = argv[5]
|
||||
elif len(argv) == 5:
|
||||
good = True
|
||||
if argv[4] == 'noaccess':
|
||||
noaccess = True
|
||||
else:
|
||||
f = argv[4]
|
||||
elif len(argv) == 4:
|
||||
good = True
|
||||
if not good:
|
||||
exit('''
|
||||
Syntax: %s <new_account> <new_user> <new_password> [noaccess] [conf_file]
|
||||
The noaccess keyword will create a user with no access to the account; another
|
||||
user for the account will have to add the user to the ACLs for a container to
|
||||
grant some access.
|
||||
'''.strip() % basename(argv[0]))
|
||||
new_account = argv[1]
|
||||
new_user = argv[2]
|
||||
new_password = argv[3]
|
||||
default_conf = '/etc/swift/auth-server.conf'
|
||||
parser = OptionParser(
|
||||
usage='Usage: %prog [options] <account> <user> <password>')
|
||||
parser.add_option('-c', '--conf', dest='conf', default=default_conf,
|
||||
help='Configuration file to determine how to connect to the local '
|
||||
'auth server (default: %s).' % default_conf)
|
||||
parser.add_option('-a', '--admin', dest='admin', action='store_true',
|
||||
default=False, help='Give the user administrator access; otherwise '
|
||||
'the user will only have access to container specifically allowed '
|
||||
'with ACLs.')
|
||||
args = argv[1:]
|
||||
if not args:
|
||||
args.append('-h')
|
||||
(options, args) = parser.parse_args(args)
|
||||
if len(args) != 3:
|
||||
parser.parse_args(['-h'])
|
||||
account, user, password = args
|
||||
c = ConfigParser()
|
||||
if not c.read(f):
|
||||
exit('Unable to read conf file: %s' % f)
|
||||
if not c.read(options.conf):
|
||||
exit('Unable to read conf file: %s' % options.conf)
|
||||
conf = dict(c.items('app:auth-server'))
|
||||
host = conf.get('bind_ip', '127.0.0.1')
|
||||
port = int(conf.get('bind_port', 11000))
|
||||
ssl = conf.get('cert_file') is not None
|
||||
path = '/account/%s/%s' % (new_account, new_user)
|
||||
headers = {'X-Auth-Key': new_password}
|
||||
if noaccess:
|
||||
headers['X-User-No-Access'] = 'true'
|
||||
path = '/account/%s/%s' % (account, user)
|
||||
headers = {'X-Auth-User-Key': password}
|
||||
if options.admin:
|
||||
headers['X-Auth-User-Admin'] = 'true'
|
||||
conn = http_connect(host, port, 'PUT', path, headers, ssl=ssl)
|
||||
resp = conn.getresponse()
|
||||
if resp.status == 204:
|
||||
print resp.getheader('x-storage-url')
|
||||
else:
|
||||
print 'Account creation failed. (%d)' % resp.status
|
||||
print 'Update failed: %s %s' % (resp.status, resp.reason)
|
@ -526,19 +526,20 @@ good idea what to do on other environments.
|
||||
#. `remakerings`
|
||||
#. `cd ~/swift/trunk; ./.unittests`
|
||||
#. `startmain` (The ``Unable to increase file descriptor limit. Running as non-root?`` warnings are expected and ok.)
|
||||
#. `swift-auth-create-account test tester testing`
|
||||
#. `swift-auth-add-user --admin test tester testing`
|
||||
#. Get an `X-Storage-Url` and `X-Auth-Token`: ``curl -v -H 'X-Storage-User: test:tester' -H 'X-Storage-Pass: testing' http://127.0.0.1:11000/v1.0``
|
||||
#. Check that you can GET account: ``curl -v -H 'X-Auth-Token: <token-from-x-auth-token-above>' <url-from-x-storage-url-above>``
|
||||
#. Check that `st` works: `st -A http://127.0.0.1:11000/v1.0 -U test:tester -K testing stat`
|
||||
#. `swift-auth-create-account test2 tester2 testing2`
|
||||
#. `swift-auth-create-account test tester3 testing3 noaccess`
|
||||
#. `swift-auth-add-user --admin test2 tester2 testing2`
|
||||
#. `swift-auth-add-user test tester3 testing3`
|
||||
#. Create `/etc/swift/func_test.conf`::
|
||||
|
||||
cp ~/swift/trunk/test/functional/sample.conf /etc/swift/func_test.conf
|
||||
|
||||
#. `cd ~/swift/trunk; ./.functests`
|
||||
#. `cd ~/swift/trunk; ./.probetests` (Note for future reference: probe tests
|
||||
will reset your environment)
|
||||
#. `cd ~/swift/trunk; ./.functests` (Note: functional tests will first delete
|
||||
everything in the configured account.)
|
||||
#. `cd ~/swift/trunk; ./.probetests` (Note: probe tests will reset your
|
||||
environment as they call `resetswift` for each test.)
|
||||
|
||||
If you plan to work on documentation (and who doesn't?!):
|
||||
|
||||
|
@ -107,9 +107,9 @@ Installing Swift For Use With Cyberduck
|
||||
cert_file = /etc/swift/cert.crt
|
||||
key_file = /etc/swift/cert.key
|
||||
|
||||
#. Use swift-auth-create-account to create a new account::
|
||||
#. Use swift-auth-add-user to create a new account and admin user::
|
||||
|
||||
ubuntu@domU-12-31-39-03-CD-06:/home/swift/swift/bin$ swift-auth-create-account a3 b3 c3
|
||||
ubuntu@domU-12-31-39-03-CD-06:/home/swift/swift/bin$ swift-auth-add-user --admin a3 b3 c3
|
||||
https://ec2-184-72-156-130.compute-1.amazonaws.com:8080/v1/06228ccf-6d0a-4395-889e-e971e8de8781
|
||||
|
||||
.. note::
|
||||
|
2
setup.py
2
setup.py
@ -61,7 +61,7 @@ setup(
|
||||
'bin/st', 'bin/swift-account-auditor',
|
||||
'bin/swift-account-audit', 'bin/swift-account-reaper',
|
||||
'bin/swift-account-replicator', 'bin/swift-account-server',
|
||||
'bin/swift-auth-create-account',
|
||||
'bin/swift-auth-add-user',
|
||||
'bin/swift-auth-recreate-accounts', 'bin/swift-auth-server',
|
||||
'bin/swift-container-auditor',
|
||||
'bin/swift-container-replicator',
|
||||
|
@ -105,14 +105,14 @@ class AuthController(object):
|
||||
self.db_file = os.path.join(self.swift_dir, 'auth.db')
|
||||
self.conn = get_db_connection(self.db_file, okay_to_create=True)
|
||||
try:
|
||||
self.conn.execute('SELECT noaccess FROM account LIMIT 1')
|
||||
self.conn.execute('SELECT admin FROM account LIMIT 1')
|
||||
except sqlite3.OperationalError, err:
|
||||
if str(err) == 'no such column: noaccess':
|
||||
if str(err) == 'no such column: admin':
|
||||
self.conn.execute(
|
||||
'ALTER TABLE account ADD COLUMN noaccess TEXT')
|
||||
"ALTER TABLE account ADD COLUMN admin TEXT DEFAULT 't'")
|
||||
self.conn.execute('''CREATE TABLE IF NOT EXISTS account (
|
||||
account TEXT, url TEXT, cfaccount TEXT,
|
||||
user TEXT, password TEXT, noaccess TEXT)''')
|
||||
user TEXT, password TEXT, admin TEXT)''')
|
||||
self.conn.execute('''CREATE INDEX IF NOT EXISTS ix_account_account
|
||||
ON account (account)''')
|
||||
try:
|
||||
@ -224,7 +224,8 @@ class AuthController(object):
|
||||
Tests if the given token is a valid token
|
||||
|
||||
:param token: The token to validate
|
||||
:returns: (TTL, account, user, cfaccount) if valid, False otherwise
|
||||
:returns: (TTL, account, user, cfaccount) if valid, False otherwise.
|
||||
cfaccount will be None for users without admin access.
|
||||
"""
|
||||
begin = time()
|
||||
self.purge_old_tokens()
|
||||
@ -248,7 +249,7 @@ class AuthController(object):
|
||||
return rv
|
||||
|
||||
def create_account(self, new_account, new_user, new_password,
|
||||
noaccess=False):
|
||||
admin=False):
|
||||
"""
|
||||
Handles the create_account call for developers, used to request
|
||||
an account be created both on a Swift cluster and in the auth server
|
||||
@ -266,9 +267,9 @@ class AuthController(object):
|
||||
:param new_account: The name for the new account
|
||||
:param new_user: The name for the new user
|
||||
:param new_password: The password for the new account
|
||||
:param noaccess: If true, the user will be granted no access to the
|
||||
account by default; another user will have to add the
|
||||
user to the ACLs for containers to grant access.
|
||||
:param admin: If true, the user will be granted full access to the
|
||||
account; otherwise, another user will have to add the
|
||||
user to the ACLs for containers to grant access.
|
||||
|
||||
:returns: False if the create fails, 'already exists' if the user
|
||||
already exists, or storage url if successful
|
||||
@ -283,7 +284,7 @@ class AuthController(object):
|
||||
if row:
|
||||
self.logger.info(
|
||||
'ALREADY EXISTS create_account(%s, %s, _, %s) [%.02f]' %
|
||||
(repr(new_account), repr(new_user), repr(noaccess),
|
||||
(repr(new_account), repr(new_user), repr(admin),
|
||||
time() - begin))
|
||||
return 'already exists'
|
||||
row = conn.execute(
|
||||
@ -297,19 +298,19 @@ class AuthController(object):
|
||||
if not account_hash:
|
||||
self.logger.info(
|
||||
'FAILED create_account(%s, %s, _, %s) [%.02f]' %
|
||||
(repr(new_account), repr(new_user), repr(noaccess),
|
||||
(repr(new_account), repr(new_user), repr(admin),
|
||||
time() - begin))
|
||||
return False
|
||||
url = self.default_cluster_url.rstrip('/') + '/' + account_hash
|
||||
conn.execute('''INSERT INTO account
|
||||
(account, url, cfaccount, user, password, noaccess)
|
||||
(account, url, cfaccount, user, password, admin)
|
||||
VALUES (?, ?, ?, ?, ?, ?)''',
|
||||
(new_account, url, account_hash, new_user, new_password,
|
||||
noaccess and 't' or ''))
|
||||
admin and 't' or ''))
|
||||
conn.commit()
|
||||
self.logger.info(
|
||||
'SUCCESS create_account(%s, %s, _, %s) = %s [%.02f]' %
|
||||
(repr(new_account), repr(new_user), repr(noaccess), repr(url),
|
||||
(repr(new_account), repr(new_user), repr(admin), repr(url),
|
||||
time() - begin))
|
||||
return url
|
||||
|
||||
@ -350,25 +351,31 @@ class AuthController(object):
|
||||
_, token = split_path(request.path, minsegs=2)
|
||||
except ValueError:
|
||||
return HTTPBadRequest()
|
||||
# Retrieves (TTL, account, user, cfaccount) if valid, False otherwise
|
||||
validation = self.validate_token(token)
|
||||
if not validation:
|
||||
return HTTPNotFound()
|
||||
# X-Auth-User: account:user,account,cfaccount
|
||||
groups = ['%s:%s' % (validation[1], validation[2]), validation[1]]
|
||||
if validation[3]: # admin access to a cfaccount
|
||||
groups.append(validation[3])
|
||||
return HTTPNoContent(headers={'X-Auth-TTL': validation[0],
|
||||
'X-Auth-User': '%s:%s,%s,%s' %
|
||||
(validation[1], validation[2], validation[1], validation[3])})
|
||||
'X-Auth-User': ','.join(groups)})
|
||||
|
||||
def handle_account_create(self, request):
|
||||
def handle_add_user(self, request):
|
||||
"""
|
||||
Handles Rest requests from developers to have an account created.
|
||||
Handles Rest requests from developers to have a user added. If the
|
||||
account specified doesn't exist, it will also be added. Currently,
|
||||
updating a user's information (password, admin access) must be done by
|
||||
directly updating the sqlite database.
|
||||
|
||||
Valid URL paths:
|
||||
* PUT /account/<account-name>/<user-name> - create the account
|
||||
|
||||
Valid headers:
|
||||
* X-Auth-Key: <password> (Only required when creating an account)
|
||||
* X-Auth-User-Key: <password>
|
||||
* X-Auth-User-Admin: <true|false>
|
||||
|
||||
If the HTTP request returns with a 204, then the account was created,
|
||||
If the HTTP request returns with a 204, then the user was added,
|
||||
and the storage url will be available in the X-Storage-Url header.
|
||||
|
||||
:param request: webob.Request object
|
||||
@ -377,11 +384,11 @@ class AuthController(object):
|
||||
_, account_name, user_name = split_path(request.path, minsegs=3)
|
||||
except ValueError:
|
||||
return HTTPBadRequest()
|
||||
if 'X-Auth-Key' not in request.headers:
|
||||
return HTTPBadRequest('X-Auth-Key is required')
|
||||
password = request.headers['x-auth-key']
|
||||
if 'X-Auth-User-Key' not in request.headers:
|
||||
return HTTPBadRequest('X-Auth-User-Key is required')
|
||||
password = request.headers['x-auth-user-key']
|
||||
storage_url = self.create_account(account_name, user_name, password,
|
||||
request.headers.get('x-user-no-access'))
|
||||
request.headers.get('x-auth-user-admin') == 'true')
|
||||
if storage_url == 'already exists':
|
||||
return HTTPBadRequest(storage_url)
|
||||
if not storage_url:
|
||||
@ -458,13 +465,14 @@ class AuthController(object):
|
||||
self.purge_old_tokens()
|
||||
with self.get_conn() as conn:
|
||||
row = conn.execute('''
|
||||
SELECT cfaccount, url, noaccess FROM account
|
||||
SELECT cfaccount, url, admin FROM account
|
||||
WHERE account = ? AND user = ? AND password = ?''',
|
||||
(account, user, password)).fetchone()
|
||||
if row is None:
|
||||
return HTTPUnauthorized()
|
||||
cfaccount = row[2] and '.none' or row[0]
|
||||
cfaccount = row[0]
|
||||
url = row[1]
|
||||
admin = row[2] == 't'
|
||||
row = conn.execute('''
|
||||
SELECT token FROM token WHERE account = ? AND user = ?''',
|
||||
(account, user)).fetchone()
|
||||
@ -476,7 +484,7 @@ class AuthController(object):
|
||||
INSERT INTO token
|
||||
(token, created, account, user, cfaccount)
|
||||
VALUES (?, ?, ?, ?, ?)''',
|
||||
(token, time(), account, user, cfaccount))
|
||||
(token, time(), account, user, admin and cfaccount or ''))
|
||||
conn.commit()
|
||||
return HTTPNoContent(headers={'x-auth-token': token,
|
||||
'x-storage-token': token,
|
||||
@ -503,7 +511,7 @@ class AuthController(object):
|
||||
elif req.method == 'GET' and req.path.startswith('/token/'):
|
||||
handler = self.handle_token
|
||||
elif req.method == 'PUT' and req.path.startswith('/account/'):
|
||||
handler = self.handle_account_create
|
||||
handler = self.handle_add_user
|
||||
elif req.method == 'POST' and \
|
||||
req.path == '/recreate_accounts':
|
||||
handler = self.handle_account_recreate
|
||||
|
@ -3,17 +3,17 @@ auth_host = 127.0.0.1
|
||||
auth_port = 11000
|
||||
auth_ssl = no
|
||||
|
||||
# Primary functional test account
|
||||
# Primary functional test account (needs admin access to the account)
|
||||
account = test
|
||||
username = tester
|
||||
password = testing
|
||||
|
||||
# User on a second account
|
||||
# User on a second account (needs admin access to the account)
|
||||
account2 = test2
|
||||
username2 = tester2
|
||||
password2 = testing2
|
||||
|
||||
# User on same account as first, but with noaccess
|
||||
# User on same account as first, but without admin access
|
||||
username3 = tester3
|
||||
password3 = testing3
|
||||
|
||||
|
@ -462,7 +462,7 @@ class TestContainer(unittest.TestCase):
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 201)
|
||||
|
||||
def test_noaccess_user(self):
|
||||
def test_nonadmin_user(self):
|
||||
if skip or skip3:
|
||||
raise SkipTest
|
||||
# Obtain the first account's string
|
||||
|
Loading…
x
Reference in New Issue
Block a user