DevAuth support for reseller admins and an initial super admin. DevAuth server no longer needs the account ring or direct account server access. Proxy server supports account PUTs.

This commit is contained in:
gholt
2010-09-10 13:40:43 -07:00
parent 118ffba216
commit b56bf3a0f3
11 changed files with 284 additions and 168 deletions

View File

@@ -33,6 +33,16 @@ if __name__ == '__main__':
default=False, help='Give the user administrator access; otherwise ' default=False, help='Give the user administrator access; otherwise '
'the user will only have access to containers specifically allowed ' 'the user will only have access to containers specifically allowed '
'with ACLs.') 'with ACLs.')
parser.add_option('-r', '--reseller-admin', dest='reseller_admin',
action='store_true', default=False, help='Give the user full reseller '
'administrator access, giving them full access to all accounts within '
'the reseller, including the ability to create new accounts. Creating '
'a new reseller admin requires super_admin rights.')
parser.add_option('-U', '--admin-user', dest='admin_user',
default='.super_admin', help='The user with admin rights to add users '
'(default: .super_admin).')
parser.add_option('-K', '--admin-key', dest='admin_key',
help='The key for the user with admin rights to add users.')
args = argv[1:] args = argv[1:]
if not args: if not args:
args.append('-h') args.append('-h')
@@ -48,9 +58,13 @@ if __name__ == '__main__':
port = int(conf.get('bind_port', 11000)) port = int(conf.get('bind_port', 11000))
ssl = conf.get('cert_file') is not None ssl = conf.get('cert_file') is not None
path = '/account/%s/%s' % (account, user) path = '/account/%s/%s' % (account, user)
headers = {'X-Auth-User-Key': password} headers = {'X-Auth-Admin-User': options.admin_user,
'X-Auth-Admin-Key': options.admin_key,
'X-Auth-User-Key': password}
if options.admin: if options.admin:
headers['X-Auth-User-Admin'] = 'true' headers['X-Auth-User-Admin'] = 'true'
if options.reseller_admin:
headers['X-Auth-User-Reseller-Admin'] = 'true'
conn = http_connect(host, port, 'PUT', path, headers, ssl=ssl) conn = http_connect(host, port, 'PUT', path, headers, ssl=ssl)
resp = conn.getresponse() resp = conn.getresponse()
if resp.status == 204: if resp.status == 204:

View File

@@ -15,25 +15,37 @@
# limitations under the License. # limitations under the License.
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
from optparse import OptionParser
from sys import argv, exit from sys import argv, exit
from swift.common.bufferedhttp import http_connect_raw as http_connect from swift.common.bufferedhttp import http_connect_raw as http_connect
if __name__ == '__main__': if __name__ == '__main__':
f = '/etc/swift/auth-server.conf' default_conf = '/etc/swift/auth-server.conf'
if len(argv) == 2: parser = OptionParser(usage='Usage: %prog [options]')
f = argv[1] parser.add_option('-c', '--conf', dest='conf', default=default_conf,
elif len(argv) != 1: help='Configuration file to determine how to connect to the local '
exit('Syntax: %s [conf_file]' % argv[0]) 'auth server (default: %s).' % default_conf)
parser.add_option('-U', '--admin-user', dest='admin_user',
default='.super_admin', help='The user with admin rights to recreate '
'accounts (default: .super_admin).')
parser.add_option('-K', '--admin-key', dest='admin_key',
help='The key for the user with admin rights to recreate accounts.')
args = argv[1:]
if not args:
args.append('-h')
(options, args) = parser.parse_args(args)
c = ConfigParser() c = ConfigParser()
if not c.read(f): if not c.read(options.conf):
exit('Unable to read conf file: %s' % f) exit('Unable to read conf file: %s' % options.conf)
conf = dict(c.items('app:auth-server')) conf = dict(c.items('app:auth-server'))
host = conf.get('bind_ip', '127.0.0.1') host = conf.get('bind_ip', '127.0.0.1')
port = int(conf.get('bind_port', 11000)) port = int(conf.get('bind_port', 11000))
ssl = conf.get('cert_file') is not None ssl = conf.get('cert_file') is not None
path = '/recreate_accounts' path = '/recreate_accounts'
conn = http_connect(host, port, 'POST', path, ssl=ssl) conn = http_connect(host, port, 'POST', path, ssl=ssl,
headers={'X-Auth-Admin-User': options.admin_user,
'X-Auth-Admin-Key': options.admin_key})
resp = conn.getresponse() resp = conn.getresponse()
if resp.status == 200: if resp.status == 200:
print resp.read() print resp.read()

View File

@@ -177,6 +177,8 @@ good idea what to do on other environments.
[app:auth-server] [app:auth-server]
use = egg:swift#auth use = egg:swift#auth
default_cluster_url = http://127.0.0.1:8080/v1 default_cluster_url = http://127.0.0.1:8080/v1
# Highly recommended to change this.
super_admin_key = devauth
#. Create `/etc/swift/proxy-server.conf`:: #. Create `/etc/swift/proxy-server.conf`::
@@ -511,7 +513,9 @@ good idea what to do on other environments.
#!/bin/bash #!/bin/bash
swift-auth-recreate-accounts # Replace devauth with whatever your super_admin key is (recorded in
# /etc/swift/auth-server.conf).
swift-auth-recreate-accounts -K devauth
swift-init object-updater start swift-init object-updater start
swift-init container-updater start swift-init container-updater start
swift-init object-replicator start swift-init object-replicator start
@@ -526,12 +530,12 @@ good idea what to do on other environments.
#. `remakerings` #. `remakerings`
#. `cd ~/swift/trunk; ./.unittests` #. `cd ~/swift/trunk; ./.unittests`
#. `startmain` (The ``Unable to increase file descriptor limit. Running as non-root?`` warnings are expected and ok.) #. `startmain` (The ``Unable to increase file descriptor limit. Running as non-root?`` warnings are expected and ok.)
#. `swift-auth-add-user --admin test tester testing` #. `swift-auth-add-user -K devauth -a test tester testing` # Replace ``devauth`` with whatever your super_admin key is (recorded in /etc/swift/auth-server.conf).
#. 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`` #. 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 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` #. Check that `st` works: `st -A http://127.0.0.1:11000/v1.0 -U test:tester -K testing stat`
#. `swift-auth-add-user --admin test2 tester2 testing2` #. `swift-auth-add-user -K devauth -a test2 tester2 testing2` # Replace ``devauth`` with whatever your super_admin key is (recorded in /etc/swift/auth-server.conf).
#. `swift-auth-add-user test tester3 testing3` #. `swift-auth-add-user -K devauth test tester3 testing3` # Replace ``devauth`` with whatever your super_admin key is (recorded in /etc/swift/auth-server.conf).
#. `cp ~/swift/trunk/test/functional/sample.conf /etc/swift/func_test.conf` #. `cp ~/swift/trunk/test/functional/sample.conf /etc/swift/func_test.conf`
#. `cd ~/swift/trunk; ./.functests` (Note: functional tests will first delete #. `cd ~/swift/trunk; ./.functests` (Note: functional tests will first delete
everything in the configured accounts.) everything in the configured accounts.)

View File

@@ -12,6 +12,8 @@ pipeline = auth-server
[app:auth-server] [app:auth-server]
use = egg:swift#auth use = egg:swift#auth
# Highly recommended to change this.
super_admin_key = devauth
# log_name = auth-server # log_name = auth-server
# log_facility = LOG_LOCAL0 # log_facility = LOG_LOCAL0
# log_level = INFO # log_level = INFO

View File

@@ -14,23 +14,21 @@
# limitations under the License. # limitations under the License.
from __future__ import with_statement from __future__ import with_statement
import errno
import os import os
import socket
from contextlib import contextmanager from contextlib import contextmanager
from time import gmtime, strftime, time from time import gmtime, strftime, time
from urllib import unquote, quote from urllib import unquote, quote
from uuid import uuid4 from uuid import uuid4
from urlparse import urlparse
import sqlite3 import sqlite3
from webob import Request, Response from webob import Request, Response
from webob.exc import HTTPBadRequest, HTTPNoContent, HTTPUnauthorized, \ from webob.exc import HTTPBadRequest, HTTPForbidden, HTTPNoContent, \
HTTPServiceUnavailable, HTTPNotFound HTTPUnauthorized, HTTPServiceUnavailable, HTTPNotFound
from swift.common.bufferedhttp import http_connect from swift.common.bufferedhttp import http_connect_raw as http_connect
from swift.common.db import get_db_connection from swift.common.db import get_db_connection
from swift.common.ring import Ring from swift.common.utils import get_logger, split_path
from swift.common.utils import get_logger, normalize_timestamp, split_path
class AuthController(object): class AuthController(object):
@@ -69,8 +67,7 @@ class AuthController(object):
* The developer makes a ReST call to create a new user. * The developer makes a ReST call to create a new user.
* If the account for the user does not yet exist, the auth server makes * If the account for the user does not yet exist, the auth server makes
ReST calls to the Swift cluster's account servers to create a new account a ReST call to the Swift cluster to create a new account on its end.
on its end.
* The auth server records the information in its database. * The auth server records the information in its database.
A last use case is recreating existing accounts; this is really only useful A last use case is recreating existing accounts; this is really only useful
@@ -78,34 +75,34 @@ class AuthController(object):
the auth server's database is retained: the auth server's database is retained:
* A developer makes an ReST call to have the existing accounts recreated. * A developer makes an ReST call to have the existing accounts recreated.
* For each account in its database, the auth server makes ReST calls to * For each account in its database, the auth server makes a ReST call to
the Swift cluster's account servers to create a specific account on its the Swift cluster to create the specific account on its end.
end.
:param conf: The [auth-server] dictionary of the auth server configuration :param conf: The [auth-server] dictionary of the auth server configuration
file file
:param ring: Overrides loading the account ring from a file; useful for
testing.
See the etc/auth-server.conf-sample for information on the possible See the etc/auth-server.conf-sample for information on the possible
configuration parameters. configuration parameters.
""" """
def __init__(self, conf, ring=None): def __init__(self, conf):
self.logger = get_logger(conf) self.logger = get_logger(conf)
self.super_admin_key = conf.get('super_admin_key')
if not self.super_admin_key:
msg = 'No super_admin_key set in conf file! Exiting.'
try:
self.logger.critical(msg)
except:
pass
raise ValueError(msg)
self.swift_dir = conf.get('swift_dir', '/etc/swift') self.swift_dir = conf.get('swift_dir', '/etc/swift')
self.reseller_prefix = conf.get('reseller_prefix', 'AUTH').strip() self.reseller_prefix = conf.get('reseller_prefix', 'AUTH').strip()
if self.reseller_prefix and self.reseller_prefix[-1] != '_': if self.reseller_prefix and self.reseller_prefix[-1] != '_':
self.reseller_prefix += '_' self.reseller_prefix += '_'
self.default_cluster_url = \ self.default_cluster_url = conf.get('default_cluster_url',
conf.get('default_cluster_url', 'http://127.0.0.1:8080/v1') 'http://127.0.0.1:8080/v1').rstrip('/')
self.token_life = int(conf.get('token_life', 86400)) self.token_life = int(conf.get('token_life', 86400))
self.log_headers = conf.get('log_headers') == 'True' self.log_headers = conf.get('log_headers') == 'True'
if ring:
self.account_ring = ring
else:
self.account_ring = \
Ring(os.path.join(self.swift_dir, 'account.ring.gz'))
self.db_file = os.path.join(self.swift_dir, 'auth.db') self.db_file = os.path.join(self.swift_dir, 'auth.db')
self.conn = get_db_connection(self.db_file, okay_to_create=True) self.conn = get_db_connection(self.db_file, okay_to_create=True)
try: try:
@@ -114,9 +111,16 @@ class AuthController(object):
if str(err) == 'no such column: admin': if str(err) == 'no such column: admin':
self.conn.execute("ALTER TABLE account ADD COLUMN admin TEXT") self.conn.execute("ALTER TABLE account ADD COLUMN admin TEXT")
self.conn.execute("UPDATE account SET admin = 't'") self.conn.execute("UPDATE account SET admin = 't'")
try:
self.conn.execute('SELECT reseller_admin FROM account LIMIT 1')
except sqlite3.OperationalError, err:
if str(err) == 'no such column: reseller_admin':
self.conn.execute(
"ALTER TABLE account ADD COLUMN reseller_admin TEXT")
self.conn.execute('''CREATE TABLE IF NOT EXISTS account ( self.conn.execute('''CREATE TABLE IF NOT EXISTS account (
account TEXT, url TEXT, cfaccount TEXT, account TEXT, url TEXT, cfaccount TEXT,
user TEXT, password TEXT, admin TEXT)''') user TEXT, password TEXT, admin TEXT,
reseller_admin TEXT)''')
self.conn.execute('''CREATE INDEX IF NOT EXISTS ix_account_account self.conn.execute('''CREATE INDEX IF NOT EXISTS ix_account_account
ON account (account)''') ON account (account)''')
try: try:
@@ -139,51 +143,36 @@ class AuthController(object):
def add_storage_account(self, account_name=''): def add_storage_account(self, account_name=''):
""" """
Creates an account within the Swift cluster by making a ReST call to Creates an account within the Swift cluster by making a ReST call.
each of the responsible account servers.
:param account_name: The desired name for the account; if omitted a :param account_name: The desired name for the account; if omitted a
UUID4 will be used. UUID4 will be used.
:returns: False upon failure, otherwise the name of the account :returns: False upon failure, otherwise the name of the account
within the Swift cluster. within the Swift cluster.
""" """
begin = time()
orig_account_name = account_name orig_account_name = account_name
if not account_name: if not account_name:
account_name = '%s%s' % (self.reseller_prefix, uuid4().hex) account_name = '%s%s' % (self.reseller_prefix, uuid4().hex)
partition, nodes = self.account_ring.get_nodes(account_name) url = '%s/%s' % (self.default_cluster_url, account_name)
headers = {'X-Timestamp': normalize_timestamp(time()), parsed = urlparse(url)
'x-cf-trans-id': 'tx' + str(uuid4())} # Create a single use token.
statuses = [] token = '%stk%s' % (self.reseller_prefix, uuid4().hex)
for node in nodes: with self.get_conn() as conn:
try: conn.execute('''
conn = None INSERT INTO token
conn = http_connect(node['ip'], node['port'], node['device'], (token, created, account, user, cfaccount) VALUES
partition, 'PUT', '/' + account_name, headers) (?, ?, '.super_admin', '.single_use', '.reseller_admin')''',
source = conn.getresponse() (token, time()))
statuses.append(source.status) conn.commit()
if source.status >= 500: conn = http_connect(parsed.hostname, parsed.port, 'PUT', parsed.path,
self.logger.error('ERROR With account server %s:%s/%s: ' {'X-Auth-Token': token}, ssl=(parsed.scheme == 'https'))
'Response %s %s: %s' % resp = conn.getresponse()
(node['ip'], node['port'], node['device'], resp.read()
source.status, source.reason, source.read(1024))) if resp.status // 100 != 2:
conn = None self.logger.error('ERROR attempting to create account %s: %s %s' %
except BaseException, err: (url, resp.status, resp.reason))
log_call = self.logger.exception return False
msg = 'ERROR With account server ' \ return account_name
'%(ip)s:%(port)s/%(device)s (will retry later): ' % node
if isinstance(err, socket.error):
if err[0] == errno.ECONNREFUSED:
log_call = self.logger.error
msg += 'Connection refused'
elif err[0] == errno.EHOSTUNREACH:
log_call = self.logger.error
msg += 'Host unreachable'
log_call(msg)
rv = False
if len([s for s in statuses if (200 <= s < 300)]) > len(nodes) / 2:
rv = account_name
return rv
@contextmanager @contextmanager
def get_conn(self): def get_conn(self):
@@ -229,7 +218,9 @@ class AuthController(object):
:param token: The token to validate :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. cfaccount will be None for users without admin access for the
account. cfaccount will be .reseller_admin for users with
full reseller admin rights.
""" """
begin = time() begin = time()
self.purge_old_tokens() self.purge_old_tokens()
@@ -241,18 +232,20 @@ class AuthController(object):
(token,)).fetchone() (token,)).fetchone()
if row is not None: if row is not None:
created = row[0] created = row[0]
if time() - created >= self.token_life: if time() - created < self.token_life:
rv = (self.token_life - (time() - created), row[1], row[2],
row[3])
# Remove the token if it was expired or single use.
if not rv or rv[2] == '.single_use':
conn.execute(''' conn.execute('''
DELETE FROM token WHERE token = ?''', (token,)) DELETE FROM token WHERE token = ?''', (token,))
conn.commit() conn.commit()
else:
rv = (self.token_life - (time() - created), row[1], row[2],
row[3])
self.logger.info('validate_token(%s, _, _) = %s [%.02f]' % self.logger.info('validate_token(%s, _, _) = %s [%.02f]' %
(repr(token), repr(rv), time() - begin)) (repr(token), repr(rv), time() - begin))
return rv return rv
def create_user(self, account, user, password, admin=False): def create_user(self, account, user, password, admin=False,
reseller_admin=False):
""" """
Handles the create_user call for developers, used to request a user be Handles the create_user call for developers, used to request a user be
added in the auth server database. If the account does not yet exist, added in the auth server database. If the account does not yet exist,
@@ -274,6 +267,9 @@ class AuthController(object):
:param admin: If true, the user will be granted full access to the :param admin: If true, the user will be granted full access to the
account; otherwise, another user will have to add the account; otherwise, another user will have to add the
user to the ACLs for containers to grant access. user to the ACLs for containers to grant access.
:param reseller_admin: If true, the user will be granted full access to
all accounts within this reseller, including the
ability to create additional accounts.
:returns: False if the create fails, 'already exists' if the user :returns: False if the create fails, 'already exists' if the user
already exists, or storage url if successful already exists, or storage url if successful
@@ -287,9 +283,9 @@ class AuthController(object):
(account, user)).fetchone() (account, user)).fetchone()
if row: if row:
self.logger.info( self.logger.info(
'ALREADY EXISTS create_user(%s, %s, _, %s) [%.02f]' % 'ALREADY EXISTS create_user(%s, %s, _, %s, %s) [%.02f]' %
(repr(account), repr(user), repr(admin), (repr(account), repr(user), repr(admin),
time() - begin)) repr(reseller_admin), time() - begin))
return 'already exists' return 'already exists'
row = conn.execute( row = conn.execute(
'SELECT url, cfaccount FROM account WHERE account = ?', 'SELECT url, cfaccount FROM account WHERE account = ?',
@@ -301,21 +297,22 @@ class AuthController(object):
account_hash = self.add_storage_account() account_hash = self.add_storage_account()
if not account_hash: if not account_hash:
self.logger.info( self.logger.info(
'FAILED create_user(%s, %s, _, %s) [%.02f]' % 'FAILED create_user(%s, %s, _, %s, %s) [%.02f]' %
(repr(account), repr(user), repr(admin), (repr(account), repr(user), repr(admin),
time() - begin)) repr(reseller_admin), time() - begin))
return False return False
url = self.default_cluster_url.rstrip('/') + '/' + account_hash url = self.default_cluster_url.rstrip('/') + '/' + account_hash
conn.execute('''INSERT INTO account conn.execute('''INSERT INTO account
(account, url, cfaccount, user, password, admin) (account, url, cfaccount, user, password, admin,
VALUES (?, ?, ?, ?, ?, ?)''', reseller_admin)
VALUES (?, ?, ?, ?, ?, ?, ?)''',
(account, url, account_hash, user, password, (account, url, account_hash, user, password,
admin and 't' or '')) admin and 't' or '', reseller_admin and 't' or ''))
conn.commit() conn.commit()
self.logger.info( self.logger.info(
'SUCCESS create_user(%s, %s, _, %s) = %s [%.02f]' % 'SUCCESS create_user(%s, %s, _, %s, %s) = %s [%.02f]' %
(repr(account), repr(user), repr(admin), repr(url), (repr(account), repr(user), repr(admin), repr(reseller_admin),
time() - begin)) repr(url), time() - begin))
return url return url
def recreate_accounts(self): def recreate_accounts(self):
@@ -339,6 +336,26 @@ class AuthController(object):
(rv, time() - begin)) (rv, time() - begin))
return rv return rv
def authorize_reseller_admin(self, request):
if request.headers.get('X-Auth-Admin-User') == '.super_admin' and \
request.headers.get('X-Auth-Admin-Key') == self.super_admin_key:
return None
try:
account, user = \
request.headers.get('X-Auth-Admin-User').split(':', 1)
except ValueError:
return HTTPForbidden(request=request)
with self.get_conn() as conn:
row = conn.execute('''
SELECT user FROM account
WHERE account = ? AND user = ? AND password = ? AND
reseller_admin = 't' ''',
(account, user,
request.headers.get('X-Auth-Admin-Key'))).fetchone()
if row:
return None
return HTTPForbidden(request=request)
def handle_token(self, request): def handle_token(self, request):
""" """
Handles ReST requests from Swift to validate tokens Handles ReST requests from Swift to validate tokens
@@ -362,7 +379,9 @@ class AuthController(object):
if not validation: if not validation:
return HTTPNotFound() return HTTPNotFound()
groups = ['%s:%s' % (validation[1], validation[2]), validation[1]] groups = ['%s:%s' % (validation[1], validation[2]), validation[1]]
if validation[3]: # admin access to a cfaccount if validation[3]:
# admin access to a cfaccount or ".reseller_admin" to access to all
# accounts, including creating new ones.
groups.append(validation[3]) groups.append(validation[3])
return HTTPNoContent(headers={'X-Auth-TTL': validation[0], return HTTPNoContent(headers={'X-Auth-TTL': validation[0],
'X-Auth-Groups': ','.join(groups)}) 'X-Auth-Groups': ','.join(groups)})
@@ -380,6 +399,7 @@ class AuthController(object):
Valid headers: Valid headers:
* X-Auth-User-Key: <password> * X-Auth-User-Key: <password>
* X-Auth-User-Admin: <true|false> * X-Auth-User-Admin: <true|false>
* X-Auth-User-Reseller-Admin: <true|false>
If the HTTP request returns with a 204, then the user was added, 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. and the storage url will be available in the X-Storage-Url header.
@@ -390,11 +410,21 @@ class AuthController(object):
_, account_name, user_name = split_path(request.path, minsegs=3) _, account_name, user_name = split_path(request.path, minsegs=3)
except ValueError: except ValueError:
return HTTPBadRequest() return HTTPBadRequest()
create_reseller_admin = \
request.headers.get('x-auth-user-reseller-admin') == 'true'
if create_reseller_admin and (
request.headers.get('X-Auth-Admin-User') != '.super_admin' or
request.headers.get('X-Auth-Admin-Key') != self.super_admin_key):
return HTTPForbidden(request=request)
resp = self.authorize_reseller_admin(request)
if resp:
return resp
if 'X-Auth-User-Key' not in request.headers: if 'X-Auth-User-Key' not in request.headers:
return HTTPBadRequest('X-Auth-User-Key is required') return HTTPBadRequest('X-Auth-User-Key is required')
password = request.headers['x-auth-user-key'] password = request.headers['x-auth-user-key']
storage_url = self.create_user(account_name, user_name, password, storage_url = self.create_user(account_name, user_name, password,
request.headers.get('x-auth-user-admin') == 'true') request.headers.get('x-auth-user-admin') == 'true',
create_reseller_admin)
if storage_url == 'already exists': if storage_url == 'already exists':
return HTTPBadRequest(storage_url) return HTTPBadRequest(storage_url)
if not storage_url: if not storage_url:
@@ -412,6 +442,9 @@ class AuthController(object):
:param request: webob.Request object :param request: webob.Request object
""" """
if request.headers.get('X-Auth-Admin-User') != '.super_admin' or \
request.headers.get('X-Auth-Admin-Key') != self.super_admin_key:
return HTTPForbidden(request=request)
result = self.recreate_accounts() result = self.recreate_accounts()
return Response(result, 200, request=request) return Response(result, 200, request=request)
@@ -471,7 +504,7 @@ class AuthController(object):
self.purge_old_tokens() self.purge_old_tokens()
with self.get_conn() as conn: with self.get_conn() as conn:
row = conn.execute(''' row = conn.execute('''
SELECT cfaccount, url, admin FROM account SELECT cfaccount, url, admin, reseller_admin FROM account
WHERE account = ? AND user = ? AND password = ?''', WHERE account = ? AND user = ? AND password = ?''',
(account, user, password)).fetchone() (account, user, password)).fetchone()
if row is None: if row is None:
@@ -479,6 +512,7 @@ class AuthController(object):
cfaccount = row[0] cfaccount = row[0]
url = row[1] url = row[1]
admin = row[2] == 't' admin = row[2] == 't'
reseller_admin = row[3] == 't'
row = conn.execute(''' row = conn.execute('''
SELECT token FROM token WHERE account = ? AND user = ?''', SELECT token FROM token WHERE account = ? AND user = ?''',
(account, user)).fetchone() (account, user)).fetchone()
@@ -486,11 +520,16 @@ class AuthController(object):
token = row[0] token = row[0]
else: else:
token = '%stk%s' % (self.reseller_prefix, uuid4().hex) token = '%stk%s' % (self.reseller_prefix, uuid4().hex)
token_cfaccount = ''
if admin:
token_cfaccount = cfaccount
if reseller_admin:
token_cfaccount = '.reseller_admin'
conn.execute(''' conn.execute('''
INSERT INTO token INSERT INTO token
(token, created, account, user, cfaccount) (token, created, account, user, cfaccount)
VALUES (?, ?, ?, ?, ?)''', VALUES (?, ?, ?, ?, ?)''',
(token, time(), account, user, admin and cfaccount or '')) (token, time(), account, user, token_cfaccount))
conn.commit() conn.commit()
return HTTPNoContent(headers={'x-auth-token': token, return HTTPNoContent(headers={'x-auth-token': token,
'x-storage-token': token, 'x-storage-token': token,

View File

@@ -36,6 +36,8 @@ MAX_OBJECT_NAME_LENGTH = 1024
CONTAINER_LISTING_LIMIT = 10000 CONTAINER_LISTING_LIMIT = 10000
#: Max container list length of a get request for an account #: Max container list length of a get request for an account
ACCOUNT_LISTING_LIMIT = 10000 ACCOUNT_LISTING_LIMIT = 10000
MAX_ACCOUNT_NAME_LENGTH = 256
MAX_CONTAINER_NAME_LENGTH = 256
def check_metadata(req, target_type): def check_metadata(req, target_type):

View File

@@ -49,7 +49,7 @@ class DevAuth(object):
token = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN')) token = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN'))
if token and token.startswith(self.reseller_prefix): if token and token.startswith(self.reseller_prefix):
memcache_client = cache_from_env(env) memcache_client = cache_from_env(env)
key = 'devauth/%s' % token key = '%s/token/%s' % (self.reseller_prefix, token)
cached_auth_data = memcache_client.get(key) cached_auth_data = memcache_client.get(key)
if cached_auth_data: if cached_auth_data:
start, expiration, groups = cached_auth_data start, expiration, groups = cached_auth_data
@@ -85,14 +85,19 @@ class DevAuth(object):
version, account, container, obj = split_path(req.path, 1, 4, True) version, account, container, obj = split_path(req.path, 1, 4, True)
if not account or not account.startswith(self.reseller_prefix): if not account or not account.startswith(self.reseller_prefix):
return self.denied_response(req) return self.denied_response(req)
if req.remote_user and account in req.remote_user.split(','): user_groups = (req.remote_user or '').split(',')
if '.reseller_admin' in user_groups:
return None
if account in user_groups and (req.method != 'PUT' or container):
# If the user is admin for the account and is not trying to do an
# account PUT...
return None return None
referrers, groups = parse_acl(getattr(req, 'acl', None)) referrers, groups = parse_acl(getattr(req, 'acl', None))
if referrer_allowed(req.referer, referrers): if referrer_allowed(req.referer, referrers):
return None return None
if not req.remote_user: if not req.remote_user:
return self.denied_response(req) return self.denied_response(req)
for user_group in req.remote_user.split(','): for user_group in user_groups:
if user_group in groups: if user_group in groups:
return None return None
return self.denied_response(req) return self.denied_response(req)

View File

@@ -35,13 +35,12 @@ from swift.common.ring import Ring
from swift.common.utils import get_logger, normalize_timestamp, split_path, \ from swift.common.utils import get_logger, normalize_timestamp, split_path, \
cache_from_env cache_from_env
from swift.common.bufferedhttp import http_connect from swift.common.bufferedhttp import http_connect
from swift.common.constraints import check_object_creation, check_metadata, \ from swift.common.constraints import check_metadata, check_object_creation, \
MAX_FILE_SIZE, check_xml_encodable check_xml_encodable, MAX_ACCOUNT_NAME_LENGTH, MAX_CONTAINER_NAME_LENGTH, \
MAX_FILE_SIZE
from swift.common.exceptions import ChunkReadTimeout, \ from swift.common.exceptions import ChunkReadTimeout, \
ChunkWriteTimeout, ConnectionTimeout ChunkWriteTimeout, ConnectionTimeout
MAX_CONTAINER_NAME_LENGTH = 256
def update_headers(response, headers): def update_headers(response, headers):
""" """
@@ -1079,6 +1078,59 @@ class AccountController(Controller):
return self.GETorHEAD_base(req, 'Account', partition, nodes, return self.GETorHEAD_base(req, 'Account', partition, nodes,
req.path_info.rstrip('/'), self.app.account_ring.replica_count) req.path_info.rstrip('/'), self.app.account_ring.replica_count)
@public
def PUT(self, req):
"""HTTP PUT request handler."""
error_response = check_metadata(req, 'account')
if error_response:
return error_response
if len(self.account_name) > MAX_ACCOUNT_NAME_LENGTH:
resp = HTTPBadRequest(request=req)
resp.body = 'Account name length of %d longer than %d' % \
(len(self.account_name), MAX_ACCOUNT_NAME_LENGTH)
return resp
account_partition, accounts = \
self.app.account_ring.get_nodes(self.account_name)
headers = {'X-Timestamp': normalize_timestamp(time.time()),
'x-cf-trans-id': self.trans_id}
headers.update(value for value in req.headers.iteritems()
if value[0].lower().startswith('x-account-meta-'))
statuses = []
reasons = []
bodies = []
for node in self.iter_nodes(account_partition, accounts,
self.app.account_ring):
if self.error_limited(node):
continue
try:
with ConnectionTimeout(self.app.conn_timeout):
conn = http_connect(node['ip'], node['port'],
node['device'], account_partition, 'PUT',
req.path_info, headers)
with Timeout(self.app.node_timeout):
source = conn.getresponse()
body = source.read()
if 200 <= source.status < 300 \
or 400 <= source.status < 500:
statuses.append(source.status)
reasons.append(source.reason)
bodies.append(body)
else:
if source.status == 507:
self.error_limit(node)
except:
self.exception_occurred(node, 'Account',
'Trying to PUT to %s' % req.path)
if len(statuses) >= len(accounts):
break
while len(statuses) < len(accounts):
statuses.append(503)
reasons.append('')
bodies.append('')
self.app.memcache.delete('account%s' % req.path_info.rstrip('/'))
return self.best_response(req, statuses, reasons, bodies,
'Account PUT')
@public @public
def POST(self, req): def POST(self, req):
"""HTTP POST request handler.""" """HTTP POST request handler."""

View File

@@ -124,7 +124,7 @@ class Connection(object):
if response.status == 401: if response.status == 401:
raise AuthenticationFailed() raise AuthenticationFailed()
if response.status != 204: if response.status not in (200, 204):
raise ResponseError(response) raise ResponseError(response)
for hdr in response.getheaders(): for hdr in response.getheaders():

View File

@@ -172,7 +172,7 @@ class TestAccount(Base):
def testPUT(self): def testPUT(self):
self.env.account.conn.make_request('PUT') self.env.account.conn.make_request('PUT')
self.assert_status(405) self.assert_status([403, 405])
def testAccountHead(self): def testAccountHead(self):
try_count = 0 try_count = 0

View File

@@ -63,12 +63,6 @@ def fake_http_connect(*code_iter, **kwargs):
return connect return connect
class FakeRing(object):
def get_nodes(self, path):
return 1, [{'ip': '10.0.0.%s' % x, 'port': 1000+x, 'device': 'sda'}
for x in xrange(3)]
class TestAuthServer(unittest.TestCase): class TestAuthServer(unittest.TestCase):
def setUp(self): def setUp(self):
@@ -76,8 +70,9 @@ class TestAuthServer(unittest.TestCase):
'auth_server') 'auth_server')
rmtree(self.testdir, ignore_errors=1) rmtree(self.testdir, ignore_errors=1)
os.mkdir(self.testdir) os.mkdir(self.testdir)
self.conf = {'swift_dir': self.testdir, 'log_name': 'auth'} self.conf = {'swift_dir': self.testdir, 'log_name': 'auth',
self.controller = auth_server.AuthController(self.conf, FakeRing()) 'super_admin_key': 'testkey'}
self.controller = auth_server.AuthController(self.conf)
def tearDown(self): def tearDown(self):
rmtree(self.testdir, ignore_errors=1) rmtree(self.testdir, ignore_errors=1)
@@ -106,7 +101,7 @@ class TestAuthServer(unittest.TestCase):
self.assert_(conn is not None) self.assert_(conn is not None)
def test_validate_token_non_existant_token(self): def test_validate_token_non_existant_token(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing',).split('/')[-1] 'test', 'tester', 'testing',).split('/')[-1]
res = self.controller.handle_auth(Request.blank('/v1/test/auth', res = self.controller.handle_auth(Request.blank('/v1/test/auth',
@@ -117,7 +112,7 @@ class TestAuthServer(unittest.TestCase):
self.assertEquals(self.controller.validate_token(token + 'bad'), False) self.assertEquals(self.controller.validate_token(token + 'bad'), False)
def test_validate_token_good(self): def test_validate_token_good(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing',).split('/')[-1] 'test', 'tester', 'testing',).split('/')[-1]
res = self.controller.handle_auth(Request.blank('/v1/test/auth', res = self.controller.handle_auth(Request.blank('/v1/test/auth',
@@ -132,7 +127,7 @@ class TestAuthServer(unittest.TestCase):
orig_time = auth_server.time orig_time = auth_server.time
try: try:
auth_server.time = lambda: 1 auth_server.time = lambda: 1
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user('test', 'tester', cfaccount = self.controller.create_user('test', 'tester',
'testing').split('/')[-1] 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/v1/test/auth', res = self.controller.handle_auth(Request.blank('/v1/test/auth',
@@ -148,107 +143,98 @@ class TestAuthServer(unittest.TestCase):
auth_server.time = orig_time auth_server.time = orig_time
def test_create_user_no_new_account(self): def test_create_user_no_new_account(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
result = self.controller.create_user('', 'tester', 'testing') result = self.controller.create_user('', 'tester', 'testing')
self.assertFalse(result) self.assertFalse(result)
def test_create_user_no_new_user(self): def test_create_user_no_new_user(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
result = self.controller.create_user('test', '', 'testing') result = self.controller.create_user('test', '', 'testing')
self.assertFalse(result) self.assertFalse(result)
def test_create_user_no_new_password(self): def test_create_user_no_new_password(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
result = self.controller.create_user('test', 'tester', '') result = self.controller.create_user('test', 'tester', '')
self.assertFalse(result) self.assertFalse(result)
def test_create_user_good(self): def test_create_user_good(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
url = self.controller.create_user('test', 'tester', 'testing') url = self.controller.create_user('test', 'tester', 'testing')
self.assert_(url) self.assert_(url)
self.assertEquals('/'.join(url.split('/')[:-1]), self.assertEquals('/'.join(url.split('/')[:-1]),
self.controller.default_cluster_url.rstrip('/'), repr(url)) self.controller.default_cluster_url.rstrip('/'), repr(url))
def test_recreate_accounts_none(self): def test_recreate_accounts_none(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
rv = self.controller.recreate_accounts() rv = self.controller.recreate_accounts()
self.assertEquals(rv.split()[0], '0', repr(rv)) self.assertEquals(rv.split()[0], '0', repr(rv))
self.assertEquals(rv.split()[-1], '[]', repr(rv)) self.assertEquals(rv.split()[-1], '[]', repr(rv))
def test_recreate_accounts_one(self): def test_recreate_accounts_one(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
self.controller.create_user('test', 'tester', 'testing') self.controller.create_user('test', 'tester', 'testing')
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
rv = self.controller.recreate_accounts() rv = self.controller.recreate_accounts()
self.assertEquals(rv.split()[0], '1', repr(rv)) self.assertEquals(rv.split()[0], '1', repr(rv))
self.assertEquals(rv.split()[-1], '[]', repr(rv)) self.assertEquals(rv.split()[-1], '[]', repr(rv))
def test_recreate_accounts_several(self): def test_recreate_accounts_several(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
self.controller.create_user('test1', 'tester', 'testing') self.controller.create_user('test1', 'tester', 'testing')
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
self.controller.create_user('test2', 'tester', 'testing') self.controller.create_user('test2', 'tester', 'testing')
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
self.controller.create_user('test3', 'tester', 'testing') self.controller.create_user('test3', 'tester', 'testing')
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
self.controller.create_user('test4', 'tester', 'testing') self.controller.create_user('test4', 'tester', 'testing')
auth_server.http_connect = fake_http_connect(201, 201, 201, auth_server.http_connect = fake_http_connect(201, 201, 201, 201)
201, 201, 201,
201, 201, 201,
201, 201, 201)
rv = self.controller.recreate_accounts() rv = self.controller.recreate_accounts()
self.assertEquals(rv.split()[0], '4', repr(rv)) self.assertEquals(rv.split()[0], '4', repr(rv))
self.assertEquals(rv.split()[-1], '[]', repr(rv)) self.assertEquals(rv.split()[-1], '[]', repr(rv))
def test_recreate_accounts_one_fail(self): def test_recreate_accounts_one_fail(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
url = self.controller.create_user('test', 'tester', 'testing') url = self.controller.create_user('test', 'tester', 'testing')
cfaccount = url.split('/')[-1] cfaccount = url.split('/')[-1]
auth_server.http_connect = fake_http_connect(500, 500, 500) auth_server.http_connect = fake_http_connect(500)
rv = self.controller.recreate_accounts() rv = self.controller.recreate_accounts()
self.assertEquals(rv.split()[0], '1', repr(rv)) self.assertEquals(rv.split()[0], '1', repr(rv))
self.assertEquals(rv.split()[-1], '[%s]' % repr(cfaccount), self.assertEquals(rv.split()[-1], '[%s]' % repr(cfaccount),
repr(rv)) repr(rv))
def test_recreate_accounts_several_fail(self): def test_recreate_accounts_several_fail(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
url = self.controller.create_user('test1', 'tester', 'testing') url = self.controller.create_user('test1', 'tester', 'testing')
cfaccounts = [url.split('/')[-1]] cfaccounts = [url.split('/')[-1]]
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
url = self.controller.create_user('test2', 'tester', 'testing') url = self.controller.create_user('test2', 'tester', 'testing')
cfaccounts.append(url.split('/')[-1]) cfaccounts.append(url.split('/')[-1])
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
url = self.controller.create_user('test3', 'tester', 'testing') url = self.controller.create_user('test3', 'tester', 'testing')
cfaccounts.append(url.split('/')[-1]) cfaccounts.append(url.split('/')[-1])
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
url = self.controller.create_user('test4', 'tester', 'testing') url = self.controller.create_user('test4', 'tester', 'testing')
cfaccounts.append(url.split('/')[-1]) cfaccounts.append(url.split('/')[-1])
auth_server.http_connect = fake_http_connect(500, 500, 500, auth_server.http_connect = fake_http_connect(500, 500, 500, 500)
500, 500, 500,
500, 500, 500,
500, 500, 500)
rv = self.controller.recreate_accounts() rv = self.controller.recreate_accounts()
self.assertEquals(rv.split()[0], '4', repr(rv)) self.assertEquals(rv.split()[0], '4', repr(rv))
failed = rv.split('[', 1)[-1][:-1].split(', ') failed = rv.split('[', 1)[-1][:-1].split(', ')
self.assertEquals(set(failed), set(repr(a) for a in cfaccounts)) self.assertEquals(set(failed), set(repr(a) for a in cfaccounts))
def test_recreate_accounts_several_fail_some(self): def test_recreate_accounts_several_fail_some(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
url = self.controller.create_user('test1', 'tester', 'testing') url = self.controller.create_user('test1', 'tester', 'testing')
cfaccounts = [url.split('/')[-1]] cfaccounts = [url.split('/')[-1]]
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
url = self.controller.create_user('test2', 'tester', 'testing') url = self.controller.create_user('test2', 'tester', 'testing')
cfaccounts.append(url.split('/')[-1]) cfaccounts.append(url.split('/')[-1])
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
url = self.controller.create_user('test3', 'tester', 'testing') url = self.controller.create_user('test3', 'tester', 'testing')
cfaccounts.append(url.split('/')[-1]) cfaccounts.append(url.split('/')[-1])
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
url = self.controller.create_user('test4', 'tester', 'testing') url = self.controller.create_user('test4', 'tester', 'testing')
cfaccounts.append(url.split('/')[-1]) cfaccounts.append(url.split('/')[-1])
auth_server.http_connect = fake_http_connect(500, 500, 500, auth_server.http_connect = fake_http_connect(500, 201, 500, 201)
201, 201, 201,
500, 500, 500,
201, 201, 201)
rv = self.controller.recreate_accounts() rv = self.controller.recreate_accounts()
self.assertEquals(rv.split()[0], '4', repr(rv)) self.assertEquals(rv.split()[0], '4', repr(rv))
failed = rv.split('[', 1)[-1][:-1].split(', ') failed = rv.split('[', 1)[-1][:-1].split(', ')
@@ -263,7 +249,7 @@ class TestAuthServer(unittest.TestCase):
self.assertEquals(res.status_int, 400) self.assertEquals(res.status_int, 400)
def test_auth_SOSO_missing_headers(self): def test_auth_SOSO_missing_headers(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing').split('/')[-1] 'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/v1/test/auth', res = self.controller.handle_auth(Request.blank('/v1/test/auth',
@@ -279,7 +265,7 @@ class TestAuthServer(unittest.TestCase):
self.assertEquals(res.status_int, 401) self.assertEquals(res.status_int, 401)
def test_auth_SOSO_bad_account(self): def test_auth_SOSO_bad_account(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing').split('/')[-1] 'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/v1/testbad/auth', res = self.controller.handle_auth(Request.blank('/v1/testbad/auth',
@@ -294,7 +280,7 @@ class TestAuthServer(unittest.TestCase):
self.assertEquals(res.status_int, 401) self.assertEquals(res.status_int, 401)
def test_auth_SOSO_bad_user(self): def test_auth_SOSO_bad_user(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing').split('/')[-1] 'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/v1/test/auth', res = self.controller.handle_auth(Request.blank('/v1/test/auth',
@@ -309,7 +295,7 @@ class TestAuthServer(unittest.TestCase):
self.assertEquals(res.status_int, 401) self.assertEquals(res.status_int, 401)
def test_auth_SOSO_bad_password(self): def test_auth_SOSO_bad_password(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing').split('/')[-1] 'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/v1/test/auth', res = self.controller.handle_auth(Request.blank('/v1/test/auth',
@@ -324,7 +310,7 @@ class TestAuthServer(unittest.TestCase):
self.assertEquals(res.status_int, 401) self.assertEquals(res.status_int, 401)
def test_auth_SOSO_good(self): def test_auth_SOSO_good(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing').split('/')[-1] 'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/v1/test/auth', res = self.controller.handle_auth(Request.blank('/v1/test/auth',
@@ -336,7 +322,7 @@ class TestAuthServer(unittest.TestCase):
self.assert_(ttl > 0, repr(ttl)) self.assert_(ttl > 0, repr(ttl))
def test_auth_SOSO_good_Mosso_headers(self): def test_auth_SOSO_good_Mosso_headers(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing').split('/')[-1] 'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/v1/test/auth', res = self.controller.handle_auth(Request.blank('/v1/test/auth',
@@ -348,7 +334,7 @@ class TestAuthServer(unittest.TestCase):
self.assert_(ttl > 0, repr(ttl)) self.assert_(ttl > 0, repr(ttl))
def test_auth_SOSO_bad_Mosso_headers(self): def test_auth_SOSO_bad_Mosso_headers(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing',).split('/')[-1] 'test', 'tester', 'testing',).split('/')[-1]
res = self.controller.handle_auth(Request.blank('/v1/test/auth', res = self.controller.handle_auth(Request.blank('/v1/test/auth',
@@ -368,7 +354,7 @@ class TestAuthServer(unittest.TestCase):
self.assertEquals(res.status_int, 401) self.assertEquals(res.status_int, 401)
def test_auth_Mosso_missing_headers(self): def test_auth_Mosso_missing_headers(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing').split('/')[-1] 'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/auth', res = self.controller.handle_auth(Request.blank('/auth',
@@ -384,7 +370,7 @@ class TestAuthServer(unittest.TestCase):
self.assertEquals(res.status_int, 401) self.assertEquals(res.status_int, 401)
def test_auth_Mosso_bad_header_format(self): def test_auth_Mosso_bad_header_format(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing').split('/')[-1] 'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/auth', res = self.controller.handle_auth(Request.blank('/auth',
@@ -399,7 +385,7 @@ class TestAuthServer(unittest.TestCase):
self.assertEquals(res.status_int, 401) self.assertEquals(res.status_int, 401)
def test_auth_Mosso_bad_account(self): def test_auth_Mosso_bad_account(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing').split('/')[-1] 'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/auth', res = self.controller.handle_auth(Request.blank('/auth',
@@ -414,7 +400,7 @@ class TestAuthServer(unittest.TestCase):
self.assertEquals(res.status_int, 401) self.assertEquals(res.status_int, 401)
def test_auth_Mosso_bad_user(self): def test_auth_Mosso_bad_user(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing').split('/')[-1] 'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/auth', res = self.controller.handle_auth(Request.blank('/auth',
@@ -429,7 +415,7 @@ class TestAuthServer(unittest.TestCase):
self.assertEquals(res.status_int, 401) self.assertEquals(res.status_int, 401)
def test_auth_Mosso_bad_password(self): def test_auth_Mosso_bad_password(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing').split('/')[-1] 'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/auth', res = self.controller.handle_auth(Request.blank('/auth',
@@ -444,7 +430,7 @@ class TestAuthServer(unittest.TestCase):
self.assertEquals(res.status_int, 401) self.assertEquals(res.status_int, 401)
def test_auth_Mosso_good(self): def test_auth_Mosso_good(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing').split('/')[-1] 'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/auth', res = self.controller.handle_auth(Request.blank('/auth',
@@ -456,7 +442,7 @@ class TestAuthServer(unittest.TestCase):
self.assert_(ttl > 0, repr(ttl)) self.assert_(ttl > 0, repr(ttl))
def test_auth_Mosso_good_SOSO_header_names(self): def test_auth_Mosso_good_SOSO_header_names(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
cfaccount = self.controller.create_user( cfaccount = self.controller.create_user(
'test', 'tester', 'testing').split('/')[-1] 'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/auth', res = self.controller.handle_auth(Request.blank('/auth',
@@ -473,11 +459,11 @@ class TestAuthServer(unittest.TestCase):
logger = get_logger(self.conf, 'auth') logger = get_logger(self.conf, 'auth')
logger.logger.addHandler(log_handler) logger.logger.addHandler(log_handler)
try: try:
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
url = self.controller.create_user('test', 'tester', 'testing') url = self.controller.create_user('test', 'tester', 'testing')
self.assertEquals(log.getvalue().rsplit(' ', 1)[0], self.assertEquals(log.getvalue().rsplit(' ', 1)[0],
"auth SUCCESS create_user('test', 'tester', _, False) = %s" "auth SUCCESS create_user('test', 'tester', _, False, False) "
% repr(url)) "= %s" % repr(url))
log.truncate(0) log.truncate(0)
def start_response(*args): def start_response(*args):
pass pass
@@ -603,8 +589,8 @@ class TestAuthServer(unittest.TestCase):
conn.commit() conn.commit()
conn.close() conn.close()
# Upgrade to current db # Upgrade to current db
conf = {'swift_dir': swift_dir} conf = {'swift_dir': swift_dir, 'super_admin_key': 'testkey'}
controller = auth_server.AuthController(conf, FakeRing()) controller = auth_server.AuthController(conf)
# Check new items exist and are correct # Check new items exist and are correct
conn = get_db_connection(db_file) conn = get_db_connection(db_file)
row = conn.execute('SELECT admin FROM account').fetchone() row = conn.execute('SELECT admin FROM account').fetchone()
@@ -615,17 +601,17 @@ class TestAuthServer(unittest.TestCase):
rmtree(swift_dir) rmtree(swift_dir)
def test_create_user_twice(self): def test_create_user_twice(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
self.controller.create_user('test', 'tester', 'testing') self.controller.create_user('test', 'tester', 'testing')
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
self.assertEquals( self.assertEquals(
self.controller.create_user('test', 'tester', 'testing'), self.controller.create_user('test', 'tester', 'testing'),
'already exists') 'already exists')
def test_create_2users_1account(self): def test_create_2users_1account(self):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
url = self.controller.create_user('test', 'tester', 'testing') url = self.controller.create_user('test', 'tester', 'testing')
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201)
url2 = self.controller.create_user('test', 'tester2', 'testing2') url2 = self.controller.create_user('test', 'tester2', 'testing2')
self.assertEquals(url, url2) self.assertEquals(url, url2)