Pulled changes from lp:~gholt/swift/repozewhat

This commit is contained in:
gholt 2010-09-03 17:42:52 -07:00
commit b5ae6a2924
18 changed files with 1135 additions and 415 deletions

View File

@ -15,6 +15,7 @@
# limitations under the License. # limitations under the License.
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
from os.path import basename
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
@ -22,11 +23,27 @@ from swift.common.bufferedhttp import http_connect_raw as http_connect
if __name__ == '__main__': if __name__ == '__main__':
f = '/etc/swift/auth-server.conf' f = '/etc/swift/auth-server.conf'
if len(argv) == 5: 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] f = argv[4]
elif len(argv) != 4: elif len(argv) == 4:
exit('Syntax: %s <new_account> <new_user> <new_password> [conf_file]' % good = True
argv[0]) 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_account = argv[1]
new_user = argv[2] new_user = argv[2]
new_password = argv[3] new_password = argv[3]
@ -38,8 +55,10 @@ 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' % (new_account, new_user) path = '/account/%s/%s' % (new_account, new_user)
conn = http_connect(host, port, 'PUT', path, {'x-auth-key':new_password}, headers = {'X-Auth-Key': new_password}
ssl=ssl) if noaccess:
headers['X-User-No-Access'] = 'true'
conn = http_connect(host, port, 'PUT', path, headers, ssl=ssl)
resp = conn.getresponse() resp = conn.getresponse()
if resp.status == 204: if resp.status == 204:
print resp.getheader('x-storage-url') print resp.getheader('x-storage-url')

View File

@ -530,17 +530,11 @@ good idea what to do on other environments.
#. 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-create-account test2 tester2 testing2`
#. `swift-auth-create-account test tester3 testing3 noaccess`
#. Create `/etc/swift/func_test.conf`:: #. Create `/etc/swift/func_test.conf`::
auth_host = 127.0.0.1 cp ~/swift/trunk/test/functional/sample.conf /etc/swift/func_test.conf
auth_port = 11000
auth_ssl = no
account = test
username = tester
password = testing
collate = C
#. `cd ~/swift/trunk; ./.functests` #. `cd ~/swift/trunk; ./.functests`
#. `cd ~/swift/trunk; ./.probetests` (Note for future reference: probe tests #. `cd ~/swift/trunk; ./.probetests` (Note for future reference: probe tests

View File

@ -7,3 +7,8 @@ source-dir = doc/source
tag_build = tag_build =
tag_date = 0 tag_date = 0
tag_svn_revision = 0 tag_svn_revision = 0
[nosetests]
with-coverage=1
cover-package=swift
verbosity=2

View File

@ -22,6 +22,7 @@ from time import gmtime, strftime, time
from urllib import unquote, quote from urllib import unquote, quote
from uuid import uuid4 from uuid import uuid4
import sqlite3
from webob import Request, Response from webob import Request, Response
from webob.exc import HTTPBadRequest, HTTPNoContent, HTTPUnauthorized, \ from webob.exc import HTTPBadRequest, HTTPNoContent, HTTPUnauthorized, \
HTTPServiceUnavailable, HTTPNotFound HTTPServiceUnavailable, HTTPNotFound
@ -58,10 +59,10 @@ class AuthController(object):
* The user makes a ReST call to the Swift cluster using the url given with * The user makes a ReST call to the Swift cluster using the url given with
the token as the X-Auth-Token header. the token as the X-Auth-Token header.
* The Swift cluster makes an ReST call to the auth server to validate the * The Swift cluster makes an ReST call to the auth server to validate the
token for the given account hash, caching the result for future requests token, caching the result for future requests up to the expiration the
up to the expiration the auth server returns. auth server returns.
* The auth server validates the token / account hash given and returns the * The auth server validates the token given and returns the expiration for
expiration for the token. the token.
* The Swift cluster completes the user's request. * The Swift cluster completes the user's request.
Another use case is creating a new account: Another use case is creating a new account:
@ -103,17 +104,33 @@ class AuthController(object):
Ring(os.path.join(self.swift_dir, 'account.ring.gz')) 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:
self.conn.execute('SELECT noaccess FROM account LIMIT 1')
except sqlite3.OperationalError, err:
if str(err) == 'no such column: noaccess':
self.conn.execute(
'ALTER TABLE account ADD COLUMN noaccess 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)''') user TEXT, password TEXT, noaccess 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:
self.conn.execute('SELECT user FROM token LIMIT 1')
except sqlite3.OperationalError, err:
if str(err) == 'no such column: user':
self.conn.execute('DROP INDEX IF EXISTS ix_token_created')
self.conn.execute('DROP INDEX IF EXISTS ix_token_cfaccount')
self.conn.execute('DROP TABLE IF EXISTS token')
self.conn.execute('''CREATE TABLE IF NOT EXISTS token ( self.conn.execute('''CREATE TABLE IF NOT EXISTS token (
cfaccount TEXT, token TEXT, created FLOAT)''') token TEXT, created FLOAT,
self.conn.execute('''CREATE INDEX IF NOT EXISTS ix_token_cfaccount account TEXT, user TEXT, cfaccount TEXT)''')
ON token (cfaccount)''') self.conn.execute('''CREATE INDEX IF NOT EXISTS ix_token_token
ON token (token)''')
self.conn.execute('''CREATE INDEX IF NOT EXISTS ix_token_created self.conn.execute('''CREATE INDEX IF NOT EXISTS ix_token_created
ON token (created)''') ON token (created)''')
self.conn.execute('''CREATE INDEX IF NOT EXISTS ix_token_account
ON token (account)''')
self.conn.commit() self.conn.commit()
def add_storage_account(self, account_name=''): def add_storage_account(self, account_name=''):
@ -202,38 +219,36 @@ class AuthController(object):
(time() - self.token_life,)) (time() - self.token_life,))
conn.commit() conn.commit()
def validate_token(self, token, account_hash): def validate_token(self, token):
""" """
Tests if the given token is a valid token Tests if the given token is a valid token
:param token: The token to validate :param token: The token to validate
:param account_hash: The account hash the token is being used with :returns: (TTL, account, user, cfaccount) if valid, False otherwise
:returns: TTL if valid, False otherwise
""" """
begin = time() begin = time()
self.purge_old_tokens() self.purge_old_tokens()
rv = False rv = False
with self.get_conn() as conn: with self.get_conn() as conn:
row = conn.execute(''' row = conn.execute('''
SELECT created FROM token SELECT created, account, user, cfaccount FROM token
WHERE cfaccount = ? AND token = ?''', WHERE token = ?''',
(account_hash, 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:
conn.execute(''' conn.execute('''
DELETE FROM token DELETE FROM token WHERE token = ?''', (token,))
WHERE cfaccount = ? AND token = ?''',
(account_hash, token))
conn.commit() conn.commit()
else: else:
rv = self.token_life - (time() - created) rv = (self.token_life - (time() - created), row[1], row[2],
self.logger.info('validate_token(%s, %s, _, _) = %s [%.02f]' % row[3])
(repr(token), repr(account_hash), repr(rv), self.logger.info('validate_token(%s, _, _) = %s [%.02f]' %
time() - begin)) (repr(token), repr(rv), time() - begin))
return rv return rv
def create_account(self, new_account, new_user, new_password): def create_account(self, new_account, new_user, new_password,
noaccess=False):
""" """
Handles the create_account call for developers, used to request Handles the create_account call for developers, used to request
an account be created both on a Swift cluster and in the auth server an account be created both on a Swift cluster and in the auth server
@ -251,28 +266,51 @@ class AuthController(object):
:param new_account: The name for the new account :param new_account: The name for the new account
:param new_user: The name for the new user :param new_user: The name for the new user
:param new_password: The password for the new account :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.
:returns: False if the create fails, storage url if successful :returns: False if the create fails, 'already exists' if the user
already exists, or storage url if successful
""" """
begin = time() begin = time()
if not all((new_account, new_user, new_password)): if not all((new_account, new_user, new_password)):
return False return False
with self.get_conn() as conn:
row = conn.execute(
'SELECT url FROM account WHERE account = ? AND user = ?',
(new_account, new_user)).fetchone()
if row:
self.logger.info(
'ALREADY EXISTS create_account(%s, %s, _, %s) [%.02f]' %
(repr(new_account), repr(new_user), repr(noaccess),
time() - begin))
return 'already exists'
row = conn.execute(
'SELECT url, cfaccount FROM account WHERE account = ?',
(new_account,)).fetchone()
if row:
url = row[0]
account_hash = row[1]
else:
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_account(%s, %s, _,) [%.02f]' % 'FAILED create_account(%s, %s, _, %s) [%.02f]' %
(repr(new_account), repr(new_user), time() - begin)) (repr(new_account), repr(new_user), repr(noaccess),
time() - begin))
return False return False
url = self.default_cluster_url.rstrip('/') + '/' + account_hash url = self.default_cluster_url.rstrip('/') + '/' + account_hash
with self.get_conn() as conn:
conn.execute('''INSERT INTO account conn.execute('''INSERT INTO account
(account, url, cfaccount, user, password) (account, url, cfaccount, user, password, noaccess)
VALUES (?, ?, ?, ?, ?)''', VALUES (?, ?, ?, ?, ?, ?)''',
(new_account, url, account_hash, new_user, new_password)) (new_account, url, account_hash, new_user, new_password,
noaccess and 't' or ''))
conn.commit() conn.commit()
self.logger.info( self.logger.info(
'SUCCESS create_account(%s, %s, _) = %s [%.02f]' % 'SUCCESS create_account(%s, %s, _, %s) = %s [%.02f]' %
(repr(new_account), repr(new_user), repr(url), time() - begin)) (repr(new_account), repr(new_user), repr(noaccess), repr(url),
time() - begin))
return url return url
def recreate_accounts(self): def recreate_accounts(self):
@ -285,8 +323,8 @@ class AuthController(object):
""" """
begin = time() begin = time()
with self.get_conn() as conn: with self.get_conn() as conn:
account_hashes = [r[0] for r in account_hashes = [r[0] for r in conn.execute(
conn.execute('SELECT cfaccount FROM account').fetchall()] 'SELECT distinct(cfaccount) FROM account').fetchall()]
failures = [] failures = []
for i, account_hash in enumerate(account_hashes): for i, account_hash in enumerate(account_hashes):
if not self.add_storage_account(account_hash): if not self.add_storage_account(account_hash):
@ -301,7 +339,7 @@ class AuthController(object):
Hanles ReST request from Swift to validate tokens Hanles ReST request from Swift to validate tokens
Valid URL paths: Valid URL paths:
* GET /token/<account-hash>/<token> * GET /token/<token>
If the HTTP equest returns with a 204, then the token is valid, If the HTTP equest returns with a 204, then the token is valid,
and the TTL of the token will be available in the X-Auth-Ttl header. and the TTL of the token will be available in the X-Auth-Ttl header.
@ -309,13 +347,14 @@ class AuthController(object):
:param request: webob.Request object :param request: webob.Request object
""" """
try: try:
_, account_hash, token = split_path(request.path, minsegs=3) _, token = split_path(request.path, minsegs=2)
except ValueError: except ValueError:
return HTTPBadRequest() return HTTPBadRequest()
ttl = self.validate_token(token, account_hash) validation = self.validate_token(token)
if not ttl: if not validation:
return HTTPNotFound() return HTTPNotFound()
return HTTPNoContent(headers={'x-auth-ttl': ttl}) return HTTPNoContent(headers={'X-Auth-TTL': validation[0],
'X-Auth-User': ':'.join(validation[1:])})
def handle_account_create(self, request): def handle_account_create(self, request):
""" """
@ -339,7 +378,10 @@ class AuthController(object):
if 'X-Auth-Key' not in request.headers: if 'X-Auth-Key' not in request.headers:
return HTTPBadRequest('X-Auth-Key is required') return HTTPBadRequest('X-Auth-Key is required')
password = request.headers['x-auth-key'] password = request.headers['x-auth-key']
storage_url = self.create_account(account_name, user_name, password) storage_url = self.create_account(account_name, user_name, password,
request.headers.get('x-user-no-access'))
if storage_url == 'already exists':
return HTTPBadRequest(storage_url)
if not storage_url: if not storage_url:
return HTTPServiceUnavailable() return HTTPServiceUnavailable()
return HTTPNoContent(headers={'x-storage-url': storage_url}) return HTTPNoContent(headers={'x-storage-url': storage_url})
@ -414,23 +456,25 @@ 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 FROM account SELECT cfaccount, url, noaccess 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:
return HTTPUnauthorized() return HTTPUnauthorized()
cfaccount = row[0] cfaccount = row[2] and '.none' or row[0]
url = row[1] url = row[1]
row = conn.execute('SELECT token FROM token WHERE cfaccount = ?', row = conn.execute('''
(cfaccount,)).fetchone() SELECT token FROM token WHERE account = ? AND user = ?''',
(account, user)).fetchone()
if row: if row:
token = row[0] token = row[0]
else: else:
token = 'tk' + str(uuid4()) token = 'tk' + str(uuid4())
conn.execute(''' conn.execute('''
INSERT INTO token (cfaccount, token, created) INSERT INTO token
VALUES (?, ?, ?)''', (token, created, account, user, cfaccount)
(cfaccount, token, time())) VALUES (?, ?, ?, ?, ?)''',
(token, time(), account, user, 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

@ -13,30 +13,135 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import time from time import time
from webob.request import Request
from webob.exc import HTTPUnauthorized, HTTPPreconditionFailed
from eventlet.timeout import Timeout from eventlet.timeout import Timeout
from repoze.what.adapters import BaseSourceAdapter
from repoze.what.middleware import setup_auth
from repoze.what.predicates import in_any_group, NotAuthorizedError
from webob.exc import HTTPForbidden, HTTPUnauthorized
from swift.common.utils import split_path
from swift.common.bufferedhttp import http_connect_raw as http_connect from swift.common.bufferedhttp import http_connect_raw as http_connect
from swift.common.utils import get_logger, cache_from_env from swift.common.utils import cache_from_env, split_path
from swift.common.memcached import MemcacheRing
class DevAuthMiddleware(object): class DevAuthorization(object):
"""
Auth Middleware that uses the dev auth server
"""
def __init__(self, app, conf, memcache_client=None, logger=None): def __init__(self, app, conf):
self.app = app self.app = app
self.memcache_client = memcache_client self.conf = conf
if logger is None:
self.logger = get_logger(conf) def __call__(self, environ, start_response):
environ['swift.authorize'] = self.authorize
environ['swift.clean_acl'] = self.clean_acl
return self.app(environ, start_response)
def authorize(self, req):
version, account, container, obj = split_path(req.path, 1, 4, True)
if not account:
return self.denied_response(req)
groups = [account]
acl = self.parse_acl(getattr(req, 'acl', None))
if acl:
referrers, accounts, users = acl
if referrers:
parts = req.referer.split('//', 1)
allow = False
if len(parts) == 2:
rhost = parts[1].split('/', 1)[0].split(':', 1)[0].lower()
else: else:
self.logger = logger rhost = 'unknown'
for mhost in referrers:
if mhost[0] == '-':
mhost = mhost[1:]
if mhost == rhost or \
(mhost[0] == '.' and rhost.endswith(mhost)):
allow = False
elif mhost == 'any' or mhost == rhost or \
(mhost[0] == '.' and rhost.endswith(mhost)):
allow = True
if allow:
return None
groups.extend(accounts)
groups.extend(users)
try:
in_any_group(*groups).check_authorization(req.environ)
except NotAuthorizedError:
return self.denied_response(req)
return None
def denied_response(self, req):
if req.remote_user:
return HTTPForbidden(request=req)
else:
return HTTPUnauthorized(request=req)
def clean_acl(self, header_name, value):
values = []
for raw_value in value.lower().split(','):
raw_value = raw_value.strip()
if raw_value:
if ':' in raw_value:
first, second = \
(v.strip() for v in raw_value.split(':', 1))
if not first:
raise ValueError('No value before colon in %s' %
repr(raw_value))
if first == '.ref' and 'write' in header_name:
raise ValueError('Referrers not allowed in write '
'ACLs: %s' % repr(raw_value))
if second:
if first == '.ref' and second[0] == '-':
second = second[1:].strip()
if not second:
raise ValueError('No value after referrer '
'deny designation in %s' % repr(raw_value))
second = '-' + second
values.append('%s:%s' % (first, second))
elif first == '.ref':
raise ValueError('No value after referrer designation '
'in %s' % repr(raw_value))
else:
values.append(first)
else:
values.append(raw_value)
return ','.join(values)
def parse_acl(self, acl_string):
if not acl_string:
return None
referrers = []
accounts = []
users = []
for value in acl_string.split(','):
if value.startswith('.ref:'):
referrers.append(value[len('.ref:'):])
elif ':' in value:
users.append(value)
else:
accounts.append(value)
return (referrers, accounts, users)
class DevIdentifier(object):
def __init__(self, conf):
self.conf = conf
def identify(self, env):
return {'token':
env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN'))}
def remember(self, env, identity):
return []
def forget(self, env, identity):
return []
class DevAuthenticator(object):
def __init__(self, conf):
self.conf = conf self.conf = conf
self.auth_host = conf.get('ip', '127.0.0.1') self.auth_host = conf.get('ip', '127.0.0.1')
self.auth_port = int(conf.get('port', 11000)) self.auth_port = int(conf.get('port', 11000))
@ -44,69 +149,135 @@ class DevAuthMiddleware(object):
conf.get('ssl', 'false').lower() in ('true', 'on', '1', 'yes') conf.get('ssl', 'false').lower() in ('true', 'on', '1', 'yes')
self.timeout = int(conf.get('node_timeout', 10)) self.timeout = int(conf.get('node_timeout', 10))
def __call__(self, env, start_response): def authenticate(self, env, identity):
if self.memcache_client is None: token = identity.get('token')
self.memcache_client = cache_from_env(env) if not token:
req = Request(env) return None
if 'x-storage-token' in req.headers and \ memcache_client = cache_from_env(env)
'x-auth-token' not in req.headers: key = 'devauth/%s' % token
req.headers['x-auth-token'] = req.headers['x-storage-token'] cached_auth_data = memcache_client.get(key)
try:
version, account, container, obj = split_path(req.path, 1, 4, True)
except ValueError, e:
version = account = container = obj = None
if account is None:
return HTTPPreconditionFailed(request=req, body='Bad URL')(
env, start_response)
if not req.headers.get('x-auth-token'):
return HTTPPreconditionFailed(request=req,
body='Missing Auth Token')(env, start_response)
if not self.auth(account, req.headers['x-auth-token']):
return HTTPUnauthorized(request=req)(env, start_response)
# If we get here, then things should be good.
return self.app(env, start_response)
def auth(self, account, token):
"""
Dev authorization implmentation
:param account: account name
:param token: auth token
:returns: True if authorization is successful, False otherwise
"""
key = 'auth/%s/%s' % (account, token)
now = time.time()
cached_auth_data = self.memcache_client.get(key)
if cached_auth_data: if cached_auth_data:
start, expiration = cached_auth_data start, expiration, user = cached_auth_data
if now - start <= expiration: if time() - start <= expiration:
return True return user
try:
with Timeout(self.timeout): with Timeout(self.timeout):
conn = http_connect(self.auth_host, self.auth_port, 'GET', conn = http_connect(self.auth_host, self.auth_port, 'GET',
'/token/%s/%s' % (account, token), ssl=self.ssl) '/token/%s' % token, ssl=self.ssl)
resp = conn.getresponse() resp = conn.getresponse()
resp.read() resp.read()
conn.close() conn.close()
if resp.status == 204: if resp.status == 204:
validated = float(resp.getheader('x-auth-ttl')) expiration = float(resp.getheader('x-auth-ttl'))
else: user = resp.getheader('x-auth-user')
validated = False memcache_client.set(key, (time(), expiration, user),
except: timeout=expiration)
self.logger.exception('ERROR with auth') return user
return False return None
if not validated:
return False
else: class DevChallenger(object):
val = (now, validated)
self.memcache_client.set(key, val, timeout=validated) def __init__(self, conf):
return True self.conf = conf
def challenge(self, env, status, app_headers, forget_headers):
def no_challenge(env, start_response):
start_response(str(status), [])
return []
return no_challenge
class DevGroupSourceAdapter(BaseSourceAdapter):
def __init__(self, *args, **kwargs):
super(DevGroupSourceAdapter, self).__init__(*args, **kwargs)
self.sections = {}
def _get_all_sections(self):
return self.sections
def _get_section_items(self, section):
return self.sections[section]
def _find_sections(self, credentials):
creds = credentials['repoze.what.userid'].split(':')
if len(creds) != 3:
return set()
rv = set([creds[0], ':'.join(creds[:2]), creds[2]])
return rv
def _include_items(self, section, items):
self.sections[section] |= items
def _exclude_items(self, section, items):
for item in items:
self.sections[section].remove(item)
def _item_is_included(self, section, item):
return item in self.sections[section]
def _create_section(self, section):
self.sections[section] = set()
def _edit_section(self, section, new_section):
self.sections[new_section] = self.sections[section]
del self.sections[section]
def _delete_section(self, section):
del self.sections[section]
def _section_exists(self, section):
return self.sections.has_key(section)
class DevPermissionSourceAdapter(BaseSourceAdapter):
def __init__(self, *args, **kwargs):
super(DevPermissionSourceAdapter, self).__init__(*args, **kwargs)
self.sections = {}
def _get_all_sections(self):
return self.sections
def _get_section_items(self, section):
return self.sections[section]
def _find_sections(self, group_name):
return set([n for (n, p) in self.sections.items()
if group_name in p])
def _include_items(self, section, items):
self.sections[section] |= items
def _exclude_items(self, section, items):
for item in items:
self.sections[section].remove(item)
def _item_is_included(self, section, item):
return item in self.sections[section]
def _create_section(self, section):
self.sections[section] = set()
def _edit_section(self, section, new_section):
self.sections[new_section] = self.sections[section]
del self.sections[section]
def _delete_section(self, section):
del self.sections[section]
def _section_exists(self, section):
return self.sections.has_key(section)
def filter_factory(global_conf, **local_conf): def filter_factory(global_conf, **local_conf):
conf = global_conf.copy() conf = global_conf.copy()
conf.update(local_conf) conf.update(local_conf)
def auth_filter(app): def auth_filter(app):
return DevAuthMiddleware(app, conf) return setup_auth(DevAuthorization(app, conf),
group_adapters={'all_groups': DevGroupSourceAdapter()},
permission_adapters={'all_perms': DevPermissionSourceAdapter()},
identifiers=[('devauth', DevIdentifier(conf))],
authenticators=[('devauth', DevAuthenticator(conf))],
challengers=[('devauth', DevChallenger(conf))])
return auth_filter return auth_filter

View File

@ -44,6 +44,9 @@ DATADIR = 'containers'
class ContainerController(object): class ContainerController(object):
"""WSGI Controller for the container server.""" """WSGI Controller for the container server."""
# Ensure these are all lowercase
save_headers = ['x-container-read', 'x-container-write']
def __init__(self, conf): def __init__(self, conf):
self.logger = get_logger(conf) self.logger = get_logger(conf)
self.root = conf.get('devices', '/srv/node/') self.root = conf.get('devices', '/srv/node/')
@ -192,7 +195,8 @@ class ContainerController(object):
metadata = {} metadata = {}
metadata.update((key, (value, timestamp)) metadata.update((key, (value, timestamp))
for key, value in req.headers.iteritems() for key, value in req.headers.iteritems()
if key.lower().startswith('x-container-meta-')) if key.lower() in self.save_headers or
key.lower().startswith('x-container-meta-'))
if metadata: if metadata:
broker.update_metadata(metadata) broker.update_metadata(metadata)
resp = self.account_update(req, account, container, broker) resp = self.account_update(req, account, container, broker)
@ -373,7 +377,8 @@ class ContainerController(object):
metadata = {} metadata = {}
metadata.update((key, (value, timestamp)) metadata.update((key, (value, timestamp))
for key, value in req.headers.iteritems() for key, value in req.headers.iteritems()
if key.lower().startswith('x-container-meta-')) if key.lower() in self.save_headers or
key.lower().startswith('x-container-meta-'))
if metadata: if metadata:
broker.update_metadata(metadata) broker.update_metadata(metadata)
return HTTPNoContent(request=req) return HTTPNoContent(request=req)

View File

@ -17,6 +17,7 @@ from __future__ import with_statement
import mimetypes import mimetypes
import os import os
import time import time
import traceback
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
from urllib import unquote, quote from urllib import unquote, quote
import uuid import uuid
@ -73,6 +74,22 @@ def public(func):
return wrapped return wrapped
def delay_denial(func):
"""
Decorator to declare which methods should have any swift.authorize call
delayed. This is so the method can load the Request object up with
additional information that may be needed by the authorization system.
:param func: function to delay authorization on
"""
func.delay_denial = True
@functools.wraps(func)
def wrapped(*a, **kw):
return func(*a, **kw)
return wrapped
class Controller(object): class Controller(object):
"""Base WSGI controller class for the proxy""" """Base WSGI controller class for the proxy"""
@ -206,19 +223,28 @@ class Controller(object):
:param account: account name for the container :param account: account name for the container
:param container: container name to look up :param container: container name to look up
:returns: tuple of (container partition, container nodes) or :returns: tuple of (container partition, container nodes, container
(None, None) if the container does not exist read acl, container write acl) or (None, None, None, None) if
the container does not exist
""" """
partition, nodes = self.app.container_ring.get_nodes( partition, nodes = self.app.container_ring.get_nodes(
account, container) account, container)
path = '/%s/%s' % (account, container) path = '/%s/%s' % (account, container)
cache_key = 'container%s' % path cache_key = 'container%s' % path
# Older memcache values (should be treated as if they aren't there):
# 0 = no responses, 200 = found, 404 = not found, -1 = mixed responses # 0 = no responses, 200 = found, 404 = not found, -1 = mixed responses
if self.app.memcache.get(cache_key) == 200: # Newer memcache values:
return partition, nodes # [older status value from above, read acl, write acl]
cache_value = self.app.memcache.get(cache_key)
if hasattr(cache_value, '__iter__'):
status, read_acl, write_acl = cache_value
if status == 200:
return partition, nodes, read_acl, write_acl
if not self.account_info(account)[1]: if not self.account_info(account)[1]:
return (None, None) return (None, None, None, None)
result_code = 0 result_code = 0
read_acl = None
write_acl = None
attempts_left = self.app.container_ring.replica_count attempts_left = self.app.container_ring.replica_count
headers = {'x-cf-trans-id': self.trans_id} headers = {'x-cf-trans-id': self.trans_id}
for node in self.iter_nodes(partition, nodes, self.app.container_ring): for node in self.iter_nodes(partition, nodes, self.app.container_ring):
@ -233,6 +259,8 @@ class Controller(object):
body = resp.read() body = resp.read()
if 200 <= resp.status <= 299: if 200 <= resp.status <= 299:
result_code = 200 result_code = 200
read_acl = resp.getheader('x-container-read')
write_acl = resp.getheader('x-container-write')
break break
elif resp.status == 404: elif resp.status == 404:
result_code = 404 if not result_code else -1 result_code = 404 if not result_code else -1
@ -251,10 +279,11 @@ class Controller(object):
cache_timeout = self.app.recheck_container_existence cache_timeout = self.app.recheck_container_existence
else: else:
cache_timeout = self.app.recheck_container_existence * 0.1 cache_timeout = self.app.recheck_container_existence * 0.1
self.app.memcache.set(cache_key, result_code, timeout=cache_timeout) self.app.memcache.set(cache_key, (result_code, read_acl, write_acl),
timeout=cache_timeout)
if result_code == 200: if result_code == 200:
return partition, nodes return partition, nodes, read_acl, write_acl
return (None, None) return (None, None, None, None)
def iter_nodes(self, partition, nodes, ring): def iter_nodes(self, partition, nodes, ring):
""" """
@ -474,6 +503,12 @@ class ObjectController(Controller):
def GETorHEAD(self, req): def GETorHEAD(self, req):
"""Handle HTTP GET or HEAD requests.""" """Handle HTTP GET or HEAD requests."""
if 'swift.authorize' in req.environ:
req.acl = \
self.container_info(self.account_name, self.container_name)[2]
aresp = req.environ['swift.authorize'](req)
if aresp:
return aresp
partition, nodes = self.app.object_ring.get_nodes( partition, nodes = self.app.object_ring.get_nodes(
self.account_name, self.container_name, self.object_name) self.account_name, self.container_name, self.object_name)
return self.GETorHEAD_base(req, 'Object', partition, return self.GETorHEAD_base(req, 'Object', partition,
@ -481,13 +516,30 @@ class ObjectController(Controller):
req.path_info, self.app.object_ring.replica_count) req.path_info, self.app.object_ring.replica_count)
@public @public
@delay_denial
def GET(self, req):
"""Handler for HTTP GET requests."""
return self.GETorHEAD(req)
@public
@delay_denial
def HEAD(self, req):
"""Handler for HTTP HEAD requests."""
return self.GETorHEAD(req)
@public
@delay_denial
def POST(self, req): def POST(self, req):
"""HTTP POST request handler.""" """HTTP POST request handler."""
error_response = check_metadata(req, 'object') error_response = check_metadata(req, 'object')
if error_response: if error_response:
return error_response return error_response
container_partition, containers = \ container_partition, containers, _, req.acl = \
self.container_info(self.account_name, self.container_name) self.container_info(self.account_name, self.container_name)
if 'swift.authorize' in req.environ:
aresp = req.environ['swift.authorize'](req)
if aresp:
return aresp
if not containers: if not containers:
return HTTPNotFound(request=req) return HTTPNotFound(request=req)
containers = self.get_update_nodes(container_partition, containers, containers = self.get_update_nodes(container_partition, containers,
@ -521,10 +573,15 @@ class ObjectController(Controller):
bodies, 'Object POST') bodies, 'Object POST')
@public @public
@delay_denial
def PUT(self, req): def PUT(self, req):
"""HTTP PUT request handler.""" """HTTP PUT request handler."""
container_partition, containers = \ container_partition, containers, _, req.acl = \
self.container_info(self.account_name, self.container_name) self.container_info(self.account_name, self.container_name)
if 'swift.authorize' in req.environ:
aresp = req.environ['swift.authorize'](req)
if aresp:
return aresp
if not containers: if not containers:
return HTTPNotFound(request=req) return HTTPNotFound(request=req)
containers = self.get_update_nodes(container_partition, containers, containers = self.get_update_nodes(container_partition, containers,
@ -701,10 +758,15 @@ class ObjectController(Controller):
return resp return resp
@public @public
@delay_denial
def DELETE(self, req): def DELETE(self, req):
"""HTTP DELETE request handler.""" """HTTP DELETE request handler."""
container_partition, containers = \ container_partition, containers, _, req.acl = \
self.container_info(self.account_name, self.container_name) self.container_info(self.account_name, self.container_name)
if 'swift.authorize' in req.environ:
aresp = req.environ['swift.authorize'](req)
if aresp:
return aresp
if not containers: if not containers:
return HTTPNotFound(request=req) return HTTPNotFound(request=req)
containers = self.get_update_nodes(container_partition, containers, containers = self.get_update_nodes(container_partition, containers,
@ -771,11 +833,25 @@ class ObjectController(Controller):
class ContainerController(Controller): class ContainerController(Controller):
"""WSGI controller for container requests""" """WSGI controller for container requests"""
# Ensure these are all lowercase
pass_through_headers = ['x-container-read', 'x-container-write']
def __init__(self, app, account_name, container_name, **kwargs): def __init__(self, app, account_name, container_name, **kwargs):
Controller.__init__(self, app) Controller.__init__(self, app)
self.account_name = unquote(account_name) self.account_name = unquote(account_name)
self.container_name = unquote(container_name) self.container_name = unquote(container_name)
def clean_acls(self, req):
if 'swift.clean_acl' in req.environ:
for header in ('x-container-read', 'x-container-write'):
if header in req.headers:
try:
req.headers[header] = \
req.environ['swift.clean_acl'](header,
req.headers[header])
except ValueError, err:
return HTTPBadRequest(request=req, body=str(err))
def GETorHEAD(self, req): def GETorHEAD(self, req):
"""Handler for HTTP GET/HEAD requests.""" """Handler for HTTP GET/HEAD requests."""
if not self.account_info(self.account_name)[1]: if not self.account_info(self.account_name)[1]:
@ -784,8 +860,25 @@ class ContainerController(Controller):
self.account_name, self.container_name) self.account_name, self.container_name)
resp = self.GETorHEAD_base(req, 'Container', part, nodes, resp = self.GETorHEAD_base(req, 'Container', part, nodes,
req.path_info, self.app.container_ring.replica_count) req.path_info, self.app.container_ring.replica_count)
if 'swift.authorize' in req.environ:
req.acl = resp.headers.get('x-container-read')
aresp = req.environ['swift.authorize'](req)
if aresp:
return aresp
return resp return resp
@public
@delay_denial
def GET(self, req):
"""Handler for HTTP GET requests."""
return self.GETorHEAD(req)
@public
@delay_denial
def HEAD(self, req):
"""Handler for HTTP HEAD requests."""
return self.GETorHEAD(req)
@public @public
def PUT(self, req): def PUT(self, req):
"""HTTP PUT request handler.""" """HTTP PUT request handler."""
@ -806,8 +899,10 @@ class ContainerController(Controller):
self.account_name, self.container_name) self.account_name, self.container_name)
headers = {'X-Timestamp': normalize_timestamp(time.time()), headers = {'X-Timestamp': normalize_timestamp(time.time()),
'x-cf-trans-id': self.trans_id} 'x-cf-trans-id': self.trans_id}
self.clean_acls(req)
headers.update(value for value in req.headers.iteritems() headers.update(value for value in req.headers.iteritems()
if value[0].lower().startswith('x-container-meta-')) if value[0].lower() in self.pass_through_headers or
value[0].lower().startswith('x-container-meta-'))
statuses = [] statuses = []
reasons = [] reasons = []
bodies = [] bodies = []
@ -863,8 +958,10 @@ class ContainerController(Controller):
self.account_name, self.container_name) self.account_name, self.container_name)
headers = {'X-Timestamp': normalize_timestamp(time.time()), headers = {'X-Timestamp': normalize_timestamp(time.time()),
'x-cf-trans-id': self.trans_id} 'x-cf-trans-id': self.trans_id}
self.clean_acls(req)
headers.update(value for value in req.headers.iteritems() headers.update(value for value in req.headers.iteritems()
if value[0].lower().startswith('x-container-meta-')) if value[0].lower() in self.pass_through_headers or
value[0].lower().startswith('x-container-meta-'))
statuses = [] statuses = []
reasons = [] reasons = []
bodies = [] bodies = []
@ -1118,7 +1215,8 @@ class BaseApplication(object):
self.posthooklogger(env, req) self.posthooklogger(env, req)
return response return response
except: except:
print "EXCEPTION IN __call__: %s" % env print "EXCEPTION IN __call__: %s: %s" % \
(traceback.format_exc(), env)
start_response('500 Server Error', start_response('500 Server Error',
[('Content-Type', 'text/plain')]) [('Content-Type', 'text/plain')])
return ['Internal server error.\n'] return ['Internal server error.\n']
@ -1160,12 +1258,28 @@ class BaseApplication(object):
controller.trans_id = req.headers.get('x-cf-trans-id', '-') controller.trans_id = req.headers.get('x-cf-trans-id', '-')
try: try:
handler = getattr(controller, req.method) handler = getattr(controller, req.method)
if getattr(handler, 'publicly_accessible'): if not getattr(handler, 'publicly_accessible'):
handler = None
except AttributeError:
handler = None
if not handler:
return HTTPMethodNotAllowed(request=req)
if path_parts['version']: if path_parts['version']:
req.path_info_pop() req.path_info_pop()
if 'swift.authorize' in req.environ:
# We call authorize before the handler, always. If authorized,
# we remove the swift.authorize hook so isn't ever called
# again. If not authorized, we return the denial unless the
# controller's method indicates it'd like to gather more
# information and try again later.
resp = req.environ['swift.authorize'](req)
if resp:
if not getattr(handler, 'delay_denial', None) and \
'swift.authorize' in req.environ:
return resp
else:
del req.environ['swift.authorize']
return handler(req) return handler(req)
except AttributeError:
return HTTPMethodNotAllowed(request=req)
except Exception: except Exception:
self.logger.exception('ERROR Unhandled exception in request') self.logger.exception('ERROR Unhandled exception in request')
return HTTPServerError(request=req) return HTTPServerError(request=req)
@ -1187,7 +1301,9 @@ class Application(BaseApplication):
return req.response return req.response
def posthooklogger(self, env, req): def posthooklogger(self, env, req):
response = req.response response = getattr(req, 'response', None)
if not response:
return
trans_time = '%.4f' % (time.time() - req.start_time) trans_time = '%.4f' % (time.time() - req.start_time)
the_request = quote(unquote(req.path)) the_request = quote(unquote(req.path))
if req.query_string: if req.query_string:
@ -1215,7 +1331,8 @@ class Application(BaseApplication):
status_int, status_int,
req.referer or '-', req.referer or '-',
req.user_agent or '-', req.user_agent or '-',
req.headers.get('x-auth-token', '-'), '%s:%s' % (req.remote_user or '',
req.headers.get('x-auth-token', '-')),
getattr(req, 'bytes_transferred', 0) or '-', getattr(req, 'bytes_transferred', 0) or '-',
getattr(response, 'bytes_transferred', 0) or '-', getattr(response, 'bytes_transferred', 0) or '-',
req.headers.get('etag', '-'), req.headers.get('etag', '-'),

View File

@ -1,10 +1,20 @@
# Sample functional test configuration file # sample config
auth_host = 127.0.0.1 auth_host = 127.0.0.1
auth_port = 80 auth_port = 11000
auth_ssl = no auth_ssl = no
account = test_account # Primary functional test account
username = test_user account = test
password = test_password username = tester
password = testing
# User on a second account
account2 = test2
username2 = tester2
password2 = testing2
# User on same account as first, but with noaccess
username3 = tester3
password3 = testing3
collate = C collate = C

View File

@ -106,9 +106,12 @@ class Base(unittest.TestCase):
self.assert_(response_body == body, self.assert_(response_body == body,
'Body returned: %s' % (response_body)) 'Body returned: %s' % (response_body))
def assert_status(self, status): def assert_status(self, status_or_statuses):
self.assert_(self.env.conn.response.status == status, self.assert_(self.env.conn.response.status == status_or_statuses or
'Status returned: %d' % (self.env.conn.response.status)) (hasattr(status_or_statuses, '__iter__') and
self.env.conn.response.status in status_or_statuses),
'Status returned: %d Expected: %s' %
(self.env.conn.response.status, status_or_statuses))
class Base2(object): class Base2(object):
def setUp(self): def setUp(self):
@ -148,11 +151,11 @@ class TestAccount(Base):
def testNoAuthToken(self): def testNoAuthToken(self):
self.assertRaises(ResponseError, self.env.account.info, self.assertRaises(ResponseError, self.env.account.info,
cfg={'no_auth_token':True}) cfg={'no_auth_token':True})
self.assert_status(412) self.assert_status([401, 412])
self.assertRaises(ResponseError, self.env.account.containers, self.assertRaises(ResponseError, self.env.account.containers,
cfg={'no_auth_token':True}) cfg={'no_auth_token':True})
self.assert_status(412) self.assert_status([401, 412])
def testInvalidUTF8Path(self): def testInvalidUTF8Path(self):
invalid_utf8 = Utils.create_utf8_name()[::-1] invalid_utf8 = Utils.create_utf8_name()[::-1]
@ -1123,7 +1126,8 @@ class TestFile(Base):
self.assert_status(400) self.assert_status(400)
# bad request types # bad request types
for req in ('LICK', 'GETorHEAD_base', 'container_info', 'best_response'): #for req in ('LICK', 'GETorHEAD_base', 'container_info', 'best_response'):
for req in ('LICK', 'GETorHEAD_base'):
self.env.account.conn.make_request(req) self.env.account.conn.make_request(req)
self.assert_status(405) self.assert_status(405)

View File

@ -10,11 +10,11 @@ from swift.common.client import get_auth, http_connection
swift_test_auth = os.environ.get('SWIFT_TEST_AUTH') swift_test_auth = os.environ.get('SWIFT_TEST_AUTH')
swift_test_user = os.environ.get('SWIFT_TEST_USER') swift_test_user = [os.environ.get('SWIFT_TEST_USER'), None, None]
swift_test_key = os.environ.get('SWIFT_TEST_KEY') swift_test_key = [os.environ.get('SWIFT_TEST_KEY'), None, None]
# If no environment set, fall back to old school conf file # If no environment set, fall back to old school conf file
if not all([swift_test_auth, swift_test_user, swift_test_key]): if not all([swift_test_auth, swift_test_user[0], swift_test_key[0]]):
conf = ConfigParser() conf = ConfigParser()
class Sectionizer(object): class Sectionizer(object):
def __init__(self, fp): def __init__(self, fp):
@ -32,16 +32,36 @@ if not all([swift_test_auth, swift_test_user, swift_test_key]):
if conf.get('auth_ssl', 'no').lower() in ('yes', 'true', 'on', '1'): if conf.get('auth_ssl', 'no').lower() in ('yes', 'true', 'on', '1'):
swift_test_auth = 'https' swift_test_auth = 'https'
swift_test_auth += '://%(auth_host)s:%(auth_port)s/v1.0' % conf swift_test_auth += '://%(auth_host)s:%(auth_port)s/v1.0' % conf
swift_test_user = '%(account)s:%(username)s' % conf swift_test_user[0] = '%(account)s:%(username)s' % conf
swift_test_key = conf['password'] swift_test_key[0] = conf['password']
try:
swift_test_user[1] = '%(account2)s:%(username2)s' % conf
swift_test_key[1] = conf['password2']
except KeyError, err:
pass # old conf, no second account tests can be run
try:
swift_test_user[2] = '%(account)s:%(username3)s' % conf
swift_test_key[2] = conf['password3']
except KeyError, err:
pass # old conf, no third account tests can be run
except IOError, err: except IOError, err:
if err.errno != errno.ENOENT: if err.errno != errno.ENOENT:
raise raise
skip = not all([swift_test_auth, swift_test_user, swift_test_key]) skip = not all([swift_test_auth, swift_test_user[0], swift_test_key[0]])
if skip: if skip:
print >>sys.stderr, 'SKIPPING FUNCTIONAL TESTS DUE TO NO CONFIG' print >>sys.stderr, 'SKIPPING FUNCTIONAL TESTS DUE TO NO CONFIG'
skip2 = not all([not skip, swift_test_user[1], swift_test_key[1]])
if not skip and skip2:
print >>sys.stderr, \
'SKIPPING SECOND ACCOUNT FUNCTIONAL TESTS DUE TO NO CONFIG FOR THEM'
skip3 = not all([not skip, swift_test_user[2], swift_test_key[2]])
if not skip and skip3:
print >>sys.stderr, \
'SKIPPING THIRD ACCOUNT FUNCTIONAL TESTS DUE TO NO CONFIG FOR THEM'
class AuthError(Exception): class AuthError(Exception):
pass pass
@ -51,29 +71,44 @@ class InternalServerError(Exception):
pass pass
url = token = parsed = conn = None url = [None, None, None]
token = [None, None, None]
parsed = [None, None, None]
conn = [None, None, None]
def retry(func, *args, **kwargs): def retry(func, *args, **kwargs):
"""
You can use the kwargs to override the 'retries' (default: 5) and
'use_account' (default: 1).
"""
global url, token, parsed, conn global url, token, parsed, conn
retries = kwargs.get('retries', 5) retries = kwargs.get('retries', 5)
use_account = 1
if 'use_account' in kwargs:
use_account = kwargs['use_account']
del kwargs['use_account']
use_account -= 1
attempts = 0 attempts = 0
backoff = 1 backoff = 1
while attempts <= retries: while attempts <= retries:
attempts += 1 attempts += 1
try: try:
if not url or not token: if not url[use_account] or not token[use_account]:
url, token = \ url[use_account], token[use_account] = \
get_auth(swift_test_auth, swift_test_user, swift_test_key) get_auth(swift_test_auth, swift_test_user[use_account],
parsed = conn = None swift_test_key[use_account])
if not parsed or not conn: parsed[use_account] = conn[use_account] = None
parsed, conn = http_connection(url) if not parsed[use_account] or not conn[use_account]:
return func(url, token, parsed, conn, *args, **kwargs) parsed[use_account], conn[use_account] = \
http_connection(url[use_account])
return func(url[use_account], token[use_account],
parsed[use_account], conn[use_account], *args, **kwargs)
except (socket.error, HTTPException): except (socket.error, HTTPException):
if attempts > retries: if attempts > retries:
raise raise
parsed = conn = None parsed[use_account] = conn[use_account] = None
except AuthError, err: except AuthError, err:
url = token = None url[use_account] = token[use_account] = None
continue continue
except InternalServerError, err: except InternalServerError, err:
pass pass

View File

@ -1,6 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
import unittest import unittest
from nose import SkipTest
from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \ from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \
MAX_META_OVERALL_SIZE, MAX_META_VALUE_LENGTH MAX_META_OVERALL_SIZE, MAX_META_VALUE_LENGTH
@ -12,7 +13,7 @@ class TestAccount(unittest.TestCase):
def test_metadata(self): def test_metadata(self):
if skip: if skip:
return raise SkipTest
def post(url, token, parsed, conn, value): def post(url, token, parsed, conn, value):
conn.request('POST', parsed.path, '', conn.request('POST', parsed.path, '',
{'X-Auth-Token': token, 'X-Account-Meta-Test': value}) {'X-Auth-Token': token, 'X-Account-Meta-Test': value})
@ -48,7 +49,7 @@ class TestAccount(unittest.TestCase):
def test_multi_metadata(self): def test_multi_metadata(self):
if skip: if skip:
return raise SkipTest
def post(url, token, parsed, conn, name, value): def post(url, token, parsed, conn, name, value):
conn.request('POST', parsed.path, '', conn.request('POST', parsed.path, '',
{'X-Auth-Token': token, name: value}) {'X-Auth-Token': token, name: value})
@ -74,7 +75,7 @@ class TestAccount(unittest.TestCase):
def test_bad_metadata(self): def test_bad_metadata(self):
if skip: if skip:
return raise SkipTest
def post(url, token, parsed, conn, extra_headers): def post(url, token, parsed, conn, extra_headers):
headers = {'X-Auth-Token': token} headers = {'X-Auth-Token': token}
headers.update(extra_headers) headers.update(extra_headers)

View File

@ -1,19 +1,22 @@
#!/usr/bin/python #!/usr/bin/python
import json
import unittest import unittest
from nose import SkipTest
from uuid import uuid4 from uuid import uuid4
from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \ from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \
MAX_META_OVERALL_SIZE, MAX_META_VALUE_LENGTH MAX_META_OVERALL_SIZE, MAX_META_VALUE_LENGTH
from swift_testing import check_response, retry, skip from swift_testing import check_response, retry, skip, skip2, skip3, \
swift_test_user
class TestContainer(unittest.TestCase): class TestContainer(unittest.TestCase):
def setUp(self): def setUp(self):
if skip: if skip:
return raise SkipTest
self.name = uuid4().hex self.name = uuid4().hex
def put(url, token, parsed, conn): def put(url, token, parsed, conn):
conn.request('PUT', parsed.path + '/' + self.name, '', conn.request('PUT', parsed.path + '/' + self.name, '',
@ -25,7 +28,27 @@ class TestContainer(unittest.TestCase):
def tearDown(self): def tearDown(self):
if skip: if skip:
return raise SkipTest
def get(url, token, parsed, conn):
conn.request('GET', parsed.path + '/' + self.name + '?format=json',
'', {'X-Auth-Token': token})
return check_response(conn)
def delete(url, token, parsed, conn, obj):
conn.request('DELETE',
'/'.join([parsed.path, self.name, obj['name']]), '',
{'X-Auth-Token': token})
return check_response(conn)
while True:
resp = retry(get)
body = resp.read()
self.assert_(resp.status // 100 == 2, resp.status)
objs = json.loads(body)
if not objs:
break
for obj in objs:
resp = retry(delete, obj)
resp.read()
self.assertEquals(resp.status, 204)
def delete(url, token, parsed, conn): def delete(url, token, parsed, conn):
conn.request('DELETE', parsed.path + '/' + self.name, '', conn.request('DELETE', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token}) {'X-Auth-Token': token})
@ -36,7 +59,7 @@ class TestContainer(unittest.TestCase):
def test_multi_metadata(self): def test_multi_metadata(self):
if skip: if skip:
return raise SkipTest
def post(url, token, parsed, conn, name, value): def post(url, token, parsed, conn, name, value):
conn.request('POST', parsed.path + '/' + self.name, '', conn.request('POST', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token, name: value}) {'X-Auth-Token': token, name: value})
@ -63,7 +86,7 @@ class TestContainer(unittest.TestCase):
def test_PUT_metadata(self): def test_PUT_metadata(self):
if skip: if skip:
return raise SkipTest
def put(url, token, parsed, conn, name, value): def put(url, token, parsed, conn, name, value):
conn.request('PUT', parsed.path + '/' + name, '', conn.request('PUT', parsed.path + '/' + name, '',
{'X-Auth-Token': token, 'X-Container-Meta-Test': value}) {'X-Auth-Token': token, 'X-Container-Meta-Test': value})
@ -110,7 +133,7 @@ class TestContainer(unittest.TestCase):
def test_POST_metadata(self): def test_POST_metadata(self):
if skip: if skip:
return raise SkipTest
def post(url, token, parsed, conn, value): def post(url, token, parsed, conn, value):
conn.request('POST', parsed.path + '/' + self.name, '', conn.request('POST', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token, 'X-Container-Meta-Test': value}) {'X-Auth-Token': token, 'X-Container-Meta-Test': value})
@ -145,7 +168,7 @@ class TestContainer(unittest.TestCase):
def test_PUT_bad_metadata(self): def test_PUT_bad_metadata(self):
if skip: if skip:
return raise SkipTest
def put(url, token, parsed, conn, name, extra_headers): def put(url, token, parsed, conn, name, extra_headers):
headers = {'X-Auth-Token': token} headers = {'X-Auth-Token': token}
headers.update(extra_headers) headers.update(extra_headers)
@ -240,7 +263,7 @@ class TestContainer(unittest.TestCase):
def test_POST_bad_metadata(self): def test_POST_bad_metadata(self):
if skip: if skip:
return raise SkipTest
def post(url, token, parsed, conn, extra_headers): def post(url, token, parsed, conn, extra_headers):
headers = {'X-Auth-Token': token} headers = {'X-Auth-Token': token}
headers.update(extra_headers) headers.update(extra_headers)
@ -297,6 +320,206 @@ class TestContainer(unittest.TestCase):
resp.read() resp.read()
self.assertEquals(resp.status, 400) self.assertEquals(resp.status, 400)
def test_public_container(self):
if skip:
raise SkipTest
def get(url, token, parsed, conn):
conn.request('GET', parsed.path + '/' + self.name)
return check_response(conn)
try:
resp = retry(get)
raise Exception('Should not have been able to GET')
except Exception, err:
self.assert_(str(err).startswith('No result after '), err)
def post(url, token, parsed, conn):
conn.request('POST', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token,
'X-Container-Read': '.ref:any'})
return check_response(conn)
resp = retry(post)
resp.read()
self.assertEquals(resp.status, 204)
resp = retry(get)
resp.read()
self.assertEquals(resp.status, 204)
def post(url, token, parsed, conn):
conn.request('POST', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token, 'X-Container-Read': ''})
return check_response(conn)
resp = retry(post)
resp.read()
self.assertEquals(resp.status, 204)
try:
resp = retry(get)
raise Exception('Should not have been able to GET')
except Exception, err:
self.assert_(str(err).startswith('No result after '), err)
def test_cross_account_container(self):
if skip or skip2:
raise SkipTest
# Obtain the first account's string
first_account = ['unknown']
def get1(url, token, parsed, conn):
first_account[0] = parsed.path
conn.request('HEAD', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token})
return check_response(conn)
resp = retry(get1)
resp.read()
# Ensure we can't access the container with the second account
def get2(url, token, parsed, conn):
conn.request('GET', first_account[0] + '/' + self.name, '',
{'X-Auth-Token': token})
return check_response(conn)
resp = retry(get2, use_account=2)
resp.read()
self.assertEquals(resp.status, 403)
# Make the container accessible by the second account
def post(url, token, parsed, conn):
conn.request('POST', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token,
'X-Container-Read': 'test2',
'X-Container-Write': 'test2'})
return check_response(conn)
resp = retry(post)
resp.read()
self.assertEquals(resp.status, 204)
# Ensure we can now use the container with the second account
resp = retry(get2, use_account=2)
resp.read()
self.assertEquals(resp.status, 204)
# Make the container private again
def post(url, token, parsed, conn):
conn.request('POST', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token, 'X-Container-Read': '',
'X-Container-Write': ''})
return check_response(conn)
resp = retry(post)
resp.read()
self.assertEquals(resp.status, 204)
# Ensure we can't access the container with the second account again
resp = retry(get2, use_account=2)
resp.read()
self.assertEquals(resp.status, 403)
def test_cross_account_public_container(self):
if skip or skip2:
raise SkipTest
# Obtain the first account's string
first_account = ['unknown']
def get1(url, token, parsed, conn):
first_account[0] = parsed.path
conn.request('HEAD', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token})
return check_response(conn)
resp = retry(get1)
resp.read()
# Ensure we can't access the container with the second account
def get2(url, token, parsed, conn):
conn.request('GET', first_account[0] + '/' + self.name, '',
{'X-Auth-Token': token})
return check_response(conn)
resp = retry(get2, use_account=2)
resp.read()
self.assertEquals(resp.status, 403)
# Make the container completely public
def post(url, token, parsed, conn):
conn.request('POST', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token,
'X-Container-Read': '.ref:any'})
return check_response(conn)
resp = retry(post)
resp.read()
self.assertEquals(resp.status, 204)
# Ensure we can now read the container with the second account
resp = retry(get2, use_account=2)
resp.read()
self.assertEquals(resp.status, 204)
# But we shouldn't be able to write with the second account
def put2(url, token, parsed, conn):
conn.request('PUT', first_account[0] + '/' + self.name + '/object',
'test object', {'X-Auth-Token': token})
return check_response(conn)
resp = retry(put2, use_account=2)
resp.read()
self.assertEquals(resp.status, 403)
# Now make the container also writeable by the second account
def post(url, token, parsed, conn):
conn.request('POST', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token,
'X-Container-Write': 'test2'})
return check_response(conn)
resp = retry(post)
resp.read()
self.assertEquals(resp.status, 204)
# Ensure we can still read the container with the second account
resp = retry(get2, use_account=2)
resp.read()
self.assertEquals(resp.status, 204)
# And that we can now write with the second account
resp = retry(put2, use_account=2)
resp.read()
self.assertEquals(resp.status, 201)
def test_noaccess_user(self):
if skip or skip3:
raise SkipTest
# Obtain the first account's string
first_account = ['unknown']
def get1(url, token, parsed, conn):
first_account[0] = parsed.path
conn.request('HEAD', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token})
return check_response(conn)
resp = retry(get1)
resp.read()
# Ensure we can't access the container with the third account
def get3(url, token, parsed, conn):
conn.request('GET', first_account[0] + '/' + self.name, '',
{'X-Auth-Token': token})
return check_response(conn)
resp = retry(get3, use_account=3)
resp.read()
self.assertEquals(resp.status, 403)
# Make the container accessible by the third account
def post(url, token, parsed, conn):
conn.request('POST', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token, 'X-Container-Read': swift_test_user[2]})
return check_response(conn)
resp = retry(post)
resp.read()
self.assertEquals(resp.status, 204)
# Ensure we can now read the container with the third account
resp = retry(get3, use_account=3)
resp.read()
self.assertEquals(resp.status, 204)
# But we shouldn't be able to write with the third account
def put3(url, token, parsed, conn):
conn.request('PUT', first_account[0] + '/' + self.name + '/object',
'test object', {'X-Auth-Token': token})
return check_response(conn)
resp = retry(put3, use_account=3)
resp.read()
self.assertEquals(resp.status, 403)
# Now make the container also writeable by the third account
def post(url, token, parsed, conn):
conn.request('POST', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token,
'X-Container-Write': swift_test_user[2]})
return check_response(conn)
resp = retry(post)
resp.read()
self.assertEquals(resp.status, 204)
# Ensure we can still read the container with the third account
resp = retry(get3, use_account=3)
resp.read()
self.assertEquals(resp.status, 204)
# And that we can now write with the third account
resp = retry(put3, use_account=3)
resp.read()
self.assertEquals(resp.status, 201)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -0,0 +1,91 @@
#!/usr/bin/python
import unittest
from nose import SkipTest
from uuid import uuid4
from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \
MAX_META_OVERALL_SIZE, MAX_META_VALUE_LENGTH
from swift_testing import check_response, retry, skip
class TestObject(unittest.TestCase):
def setUp(self):
if skip:
raise SkipTest
self.container = uuid4().hex
def put(url, token, parsed, conn):
conn.request('PUT', parsed.path + '/' + self.container, '',
{'X-Auth-Token': token})
return check_response(conn)
resp = retry(put)
resp.read()
self.assertEquals(resp.status, 201)
self.obj = uuid4().hex
def put(url, token, parsed, conn):
conn.request('PUT', '%s/%s/%s' % (parsed.path, self.container,
self.obj), 'test', {'X-Auth-Token': token})
return check_response(conn)
resp = retry(put)
resp.read()
self.assertEquals(resp.status, 201)
def tearDown(self):
if skip:
raise SkipTest
def delete(url, token, parsed, conn):
conn.request('DELETE', '%s/%s/%s' % (parsed.path, self.container,
self.obj), '', {'X-Auth-Token': token})
return check_response(conn)
resp = retry(delete)
resp.read()
self.assertEquals(resp.status, 204)
def delete(url, token, parsed, conn):
conn.request('DELETE', parsed.path + '/' + self.container, '',
{'X-Auth-Token': token})
return check_response(conn)
resp = retry(delete)
resp.read()
self.assertEquals(resp.status, 204)
def test_public_object(self):
if skip:
raise SkipTest
def get(url, token, parsed, conn):
conn.request('GET',
'%s/%s/%s' % (parsed.path, self.container, self.obj))
return check_response(conn)
try:
resp = retry(get)
raise Exception('Should not have been able to GET')
except Exception, err:
self.assert_(str(err).startswith('No result after '))
def post(url, token, parsed, conn):
conn.request('POST', parsed.path + '/' + self.container, '',
{'X-Auth-Token': token,
'X-Container-Read': '.ref:any'})
return check_response(conn)
resp = retry(post)
resp.read()
self.assertEquals(resp.status, 204)
resp = retry(get)
resp.read()
self.assertEquals(resp.status, 200)
def post(url, token, parsed, conn):
conn.request('POST', parsed.path + '/' + self.container, '',
{'X-Auth-Token': token, 'X-Container-Read': ''})
return check_response(conn)
resp = retry(post)
resp.read()
self.assertEquals(resp.status, 204)
try:
resp = retry(get)
raise Exception('Should not have been able to GET')
except Exception, err:
self.assert_(str(err).startswith('No result after '))
if __name__ == '__main__':
unittest.main()

View File

@ -113,20 +113,7 @@ class TestAuthServer(unittest.TestCase):
headers={'X-Storage-User': 'tester', headers={'X-Storage-User': 'tester',
'X-Storage-Pass': 'testing'})) 'X-Storage-Pass': 'testing'}))
token = res.headers['x-storage-token'] token = res.headers['x-storage-token']
self.assertEquals(self.controller.validate_token(token + 'bad', self.assertEquals(self.controller.validate_token(token + 'bad'), False)
cfaccount), False)
def test_validate_token_non_existant_cfaccount(self):
auth_server.http_connect = fake_http_connect(201, 201, 201)
cfaccount = self.controller.create_account(
'test', 'tester', 'testing').split('/')[-1]
res = self.controller.handle_auth(Request.blank('/v1/test/auth',
environ={'REQUEST_METHOD': 'GET'},
headers={'X-Storage-User': 'tester',
'X-Storage-Pass': 'testing'}))
token = res.headers['x-storage-token']
self.assertEquals(self.controller.validate_token(token,
cfaccount + '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, 201, 201)
@ -137,7 +124,7 @@ class TestAuthServer(unittest.TestCase):
headers={'X-Storage-User': 'tester', headers={'X-Storage-User': 'tester',
'X-Storage-Pass': 'testing'})) 'X-Storage-Pass': 'testing'}))
token = res.headers['x-storage-token'] token = res.headers['x-storage-token']
ttl = self.controller.validate_token(token, cfaccount) ttl = self.controller.validate_token(token)
self.assert_(ttl > 0, repr(ttl)) self.assert_(ttl > 0, repr(ttl))
def test_validate_token_expired(self): def test_validate_token_expired(self):
@ -152,12 +139,10 @@ class TestAuthServer(unittest.TestCase):
headers={'X-Storage-User': 'tester', headers={'X-Storage-User': 'tester',
'X-Storage-Pass': 'testing'})) 'X-Storage-Pass': 'testing'}))
token = res.headers['x-storage-token'] token = res.headers['x-storage-token']
ttl = self.controller.validate_token( ttl = self.controller.validate_token(token)
token, cfaccount)
self.assert_(ttl > 0, repr(ttl)) self.assert_(ttl > 0, repr(ttl))
auth_server.time = lambda: 1 + self.controller.token_life auth_server.time = lambda: 1 + self.controller.token_life
self.assertEquals(self.controller.validate_token( self.assertEquals(self.controller.validate_token(token), False)
token, cfaccount), False)
finally: finally:
auth_server.time = orig_time auth_server.time = orig_time
@ -244,7 +229,7 @@ class TestAuthServer(unittest.TestCase):
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(failed, [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, 201, 201)
@ -266,11 +251,8 @@ class TestAuthServer(unittest.TestCase):
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(', ')
expected = [] self.assertEquals(
for i, value in enumerate(cfaccounts): len(set(repr(a) for a in cfaccounts) - set(failed)), 2)
if not i % 2:
expected.append(repr(value))
self.assertEquals(failed, expected)
def test_auth_bad_path(self): def test_auth_bad_path(self):
self.assertRaises(ValueError, self.controller.handle_auth, self.assertRaises(ValueError, self.controller.handle_auth,
@ -349,7 +331,7 @@ class TestAuthServer(unittest.TestCase):
headers={'X-Storage-User': 'tester', headers={'X-Storage-User': 'tester',
'X-Storage-Pass': 'testing'})) 'X-Storage-Pass': 'testing'}))
token = res.headers['x-storage-token'] token = res.headers['x-storage-token']
ttl = self.controller.validate_token(token, cfaccount) ttl = self.controller.validate_token(token)
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):
@ -361,7 +343,7 @@ class TestAuthServer(unittest.TestCase):
headers={'X-Auth-User': 'test:tester', headers={'X-Auth-User': 'test:tester',
'X-Auth-Key': 'testing'})) 'X-Auth-Key': 'testing'}))
token = res.headers['x-storage-token'] token = res.headers['x-storage-token']
ttl = self.controller.validate_token(token, cfaccount) ttl = self.controller.validate_token(token)
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):
@ -469,7 +451,7 @@ class TestAuthServer(unittest.TestCase):
headers={'X-Auth-User': 'test:tester', headers={'X-Auth-User': 'test:tester',
'X-Auth-Key': 'testing'})) 'X-Auth-Key': 'testing'}))
token = res.headers['x-storage-token'] token = res.headers['x-storage-token']
ttl = self.controller.validate_token(token, cfaccount) ttl = self.controller.validate_token(token)
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):
@ -481,7 +463,7 @@ class TestAuthServer(unittest.TestCase):
headers={'X-Storage-User': 'test:tester', headers={'X-Storage-User': 'test:tester',
'X-Storage-Pass': 'testing'})) 'X-Storage-Pass': 'testing'}))
token = res.headers['x-storage-token'] token = res.headers['x-storage-token']
ttl = self.controller.validate_token(token, cfaccount) ttl = self.controller.validate_token(token)
self.assert_(ttl > 0, repr(ttl)) self.assert_(ttl > 0, repr(ttl))
def test_basic_logging(self): def test_basic_logging(self):
@ -493,8 +475,8 @@ class TestAuthServer(unittest.TestCase):
auth_server.http_connect = fake_http_connect(201, 201, 201) auth_server.http_connect = fake_http_connect(201, 201, 201)
url = self.controller.create_account('test', 'tester', 'testing') url = self.controller.create_account('test', 'tester', 'testing')
self.assertEquals(log.getvalue().rsplit(' ', 1)[0], self.assertEquals(log.getvalue().rsplit(' ', 1)[0],
"auth SUCCESS create_account('test', 'tester', _) = %s" % "auth SUCCESS create_account('test', 'tester', _, False) = %s"
repr(url)) % repr(url))
log.truncate(0) log.truncate(0)
def start_response(*args): def start_response(*args):
pass pass

View File

@ -100,77 +100,58 @@ def start_response(*args):
pass pass
class TestAuth(unittest.TestCase): class TestAuth(unittest.TestCase):
# TODO: With the auth refactor, these tests have to be refactored as well.
# I brought some over from another refactor I've been trying, but these
# also need work.
def setUp(self): def test_clean_acl(self):
self.test_auth = auth.DevAuthMiddleware( devauth = auth.DevAuthorization(None, None)
FakeApp(), {}, FakeMemcache(), Logger()) value = devauth.clean_acl('header', '.ref:any')
self.assertEquals(value, '.ref:any')
value = devauth.clean_acl('header', '.ref:specific.host')
self.assertEquals(value, '.ref:specific.host')
value = devauth.clean_acl('header', '.ref:.ending.with')
self.assertEquals(value, '.ref:.ending.with')
value = devauth.clean_acl('header', '.ref:one,.ref:two')
self.assertEquals(value, '.ref:one,.ref:two')
value = devauth.clean_acl('header', '.ref:any,.ref:-specific.host')
self.assertEquals(value, '.ref:any,.ref:-specific.host')
value = devauth.clean_acl('header', '.ref:any,.ref:-.ending.with')
self.assertEquals(value, '.ref:any,.ref:-.ending.with')
value = devauth.clean_acl('header', '.ref:one,.ref:-two')
self.assertEquals(value, '.ref:one,.ref:-two')
value = devauth.clean_acl('header',
' .ref : one , ,, .ref:two , .ref : - three ')
self.assertEquals(value, '.ref:one,.ref:two,.ref:-three')
self.assertRaises(ValueError, devauth.clean_acl, 'header', '.ref:')
self.assertRaises(ValueError, devauth.clean_acl, 'header', ' .ref : ')
self.assertRaises(ValueError, devauth.clean_acl, 'header',
'user , .ref : ')
self.assertRaises(ValueError, devauth.clean_acl, 'header', '.ref:-')
self.assertRaises(ValueError, devauth.clean_acl, 'header',
' .ref : - ')
self.assertRaises(ValueError, devauth.clean_acl, 'header',
'user , .ref : - ')
def test_auth_fail(self): def test_parse_acl(self):
old_http_connect = auth.http_connect devauth = auth.DevAuthorization(None, None)
try: self.assertEquals(devauth.parse_acl(None), None)
auth.http_connect = mock_http_connect(404) self.assertEquals(devauth.parse_acl(''), None)
self.assertFalse(self.test_auth.auth('a','t')) self.assertEquals(devauth.parse_acl('.ref:ref1'),
finally: (['ref1'], [], []))
auth.http_connect = old_http_connect self.assertEquals(devauth.parse_acl('.ref:-ref1'),
(['-ref1'], [], []))
def test_auth_success(self): self.assertEquals(devauth.parse_acl('account:user'),
old_http_connect = auth.http_connect ([], [], ['account:user']))
try: self.assertEquals(devauth.parse_acl('account'),
auth.http_connect = mock_http_connect(204, {'x-auth-ttl':'1234'}) ([], ['account'], []))
self.assertTrue(self.test_auth.auth('a','t')) self.assertEquals(
finally: devauth.parse_acl('acc1,acc2:usr2,.ref:ref3,.ref:-ref4'),
auth.http_connect = old_http_connect (['ref3', '-ref4'], ['acc1'], ['acc2:usr2']))
self.assertEquals(devauth.parse_acl(
def test_auth_memcache(self): 'acc1,acc2:usr2,.ref:ref3,acc3,acc4:usr4,.ref:ref5,.ref:-ref6'),
old_http_connect = auth.http_connect (['ref3', 'ref5', '-ref6'], ['acc1', 'acc3'],
try: ['acc2:usr2', 'acc4:usr4']))
auth.http_connect = mock_http_connect(204, {'x-auth-ttl':'1234'})
self.assertTrue(self.test_auth.auth('a','t'))
auth.http_connect = mock_http_connect(404)
# Should still be in memcache
self.assertTrue(self.test_auth.auth('a','t'))
finally:
auth.http_connect = old_http_connect
def test_middleware_success(self):
old_http_connect = auth.http_connect
try:
auth.http_connect = mock_http_connect(204, {'x-auth-ttl':'1234'})
req = Request.blank('/v/a/c/o', headers={'x-auth-token':'t'})
resp = self.test_auth(req.environ, start_response)
self.assertEquals(resp, 'OK')
finally:
auth.http_connect = old_http_connect
def test_middleware_no_header(self):
old_http_connect = auth.http_connect
try:
auth.http_connect = mock_http_connect(204, {'x-auth-ttl':'1234'})
req = Request.blank('/v/a/c/o')
resp = self.test_auth(req.environ, start_response)
self.assertEquals(resp, ['Missing Auth Token'])
finally:
auth.http_connect = old_http_connect
def test_middleware_storage_token(self):
old_http_connect = auth.http_connect
try:
auth.http_connect = mock_http_connect(204, {'x-auth-ttl':'1234'})
req = Request.blank('/v/a/c/o', headers={'x-storage-token':'t'})
resp = self.test_auth(req.environ, start_response)
self.assertEquals(resp, 'OK')
finally:
auth.http_connect = old_http_connect
def test_middleware_only_version(self):
old_http_connect = auth.http_connect
try:
auth.http_connect = mock_http_connect(204, {'x-auth-ttl':'1234'})
req = Request.blank('/v', headers={'x-auth-token':'t'})
resp = self.test_auth(req.environ, start_response)
self.assertEquals(resp, ['Bad URL'])
finally:
auth.http_connect = old_http_connect
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -55,6 +55,51 @@ class TestContainerController(unittest.TestCase):
""" Tear down for testing swift.object_server.ObjectController """ """ Tear down for testing swift.object_server.ObjectController """
rmtree(self.testdir, ignore_errors=1) rmtree(self.testdir, ignore_errors=1)
def test_acl_container(self):
# Ensure no acl by default
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': '0'})
self.controller.PUT(req)
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'})
response = self.controller.HEAD(req)
self.assert_(response.status.startswith('204'))
self.assert_('x-container-read' not in response.headers)
self.assert_('x-container-write' not in response.headers)
# Ensure POSTing acls works
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'},
headers={'X-Timestamp': '1', 'X-Container-Read': '.ref:any',
'X-Container-Write': 'account:user'})
self.controller.POST(req)
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'})
response = self.controller.HEAD(req)
self.assert_(response.status.startswith('204'))
self.assertEquals(response.headers.get('x-container-read'),
'.ref:any')
self.assertEquals(response.headers.get('x-container-write'),
'account:user')
# Ensure we can clear acls on POST
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'},
headers={'X-Timestamp': '3', 'X-Container-Read': '',
'X-Container-Write': ''})
self.controller.POST(req)
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'})
response = self.controller.HEAD(req)
self.assert_(response.status.startswith('204'))
self.assert_('x-container-read' not in response.headers)
self.assert_('x-container-write' not in response.headers)
# Ensure PUTing acls works
req = Request.blank('/sda1/p/a/c2', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': '4', 'X-Container-Read': '.ref:any',
'X-Container-Write': 'account:user'})
self.controller.PUT(req)
req = Request.blank('/sda1/p/a/c2', environ={'REQUEST_METHOD': 'HEAD'})
response = self.controller.HEAD(req)
self.assert_(response.status.startswith('204'))
self.assertEquals(response.headers.get('x-container-read'),
'.ref:any')
self.assertEquals(response.headers.get('x-container-write'),
'account:user')
def test_HEAD(self): def test_HEAD(self):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})

View File

@ -19,6 +19,7 @@ import cPickle as pickle
import os import os
import sys import sys
import unittest import unittest
from nose import SkipTest
from shutil import rmtree from shutil import rmtree
from StringIO import StringIO from StringIO import StringIO
from time import gmtime, sleep, strftime, time from time import gmtime, sleep, strftime, time
@ -64,7 +65,7 @@ class TestObjectController(unittest.TestCase):
def test_POST_update_meta(self): def test_POST_update_meta(self):
""" Test swift.object_server.ObjectController.POST """ """ Test swift.object_server.ObjectController.POST """
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
timestamp = normalize_timestamp(time()) timestamp = normalize_timestamp(time())
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': timestamp, headers={'X-Timestamp': timestamp,
@ -92,7 +93,7 @@ class TestObjectController(unittest.TestCase):
def test_POST_not_exist(self): def test_POST_not_exist(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
timestamp = normalize_timestamp(time()) timestamp = normalize_timestamp(time())
req = Request.blank('/sda1/p/a/c/fail', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/sda1/p/a/c/fail', environ={'REQUEST_METHOD': 'POST'},
headers={'X-Timestamp': timestamp, headers={'X-Timestamp': timestamp,
@ -114,7 +115,7 @@ class TestObjectController(unittest.TestCase):
def test_POST_container_connection(self): def test_POST_container_connection(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
def mock_http_connect(response, with_exc=False): def mock_http_connect(response, with_exc=False):
class FakeConn(object): class FakeConn(object):
def __init__(self, status, with_exc): def __init__(self, status, with_exc):
@ -210,7 +211,7 @@ class TestObjectController(unittest.TestCase):
def test_PUT_common(self): def test_PUT_common(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
timestamp = normalize_timestamp(time()) timestamp = normalize_timestamp(time())
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': timestamp, headers={'X-Timestamp': timestamp,
@ -234,7 +235,7 @@ class TestObjectController(unittest.TestCase):
def test_PUT_overwrite(self): def test_PUT_overwrite(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': normalize_timestamp(time()), headers={'X-Timestamp': normalize_timestamp(time()),
'Content-Length': '6', 'Content-Length': '6',
@ -267,7 +268,7 @@ class TestObjectController(unittest.TestCase):
def test_PUT_no_etag(self): def test_PUT_no_etag(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': normalize_timestamp(time()), headers={'X-Timestamp': normalize_timestamp(time()),
'Content-Type': 'text/plain'}) 'Content-Type': 'text/plain'})
@ -286,7 +287,7 @@ class TestObjectController(unittest.TestCase):
def test_PUT_user_metadata(self): def test_PUT_user_metadata(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
timestamp = normalize_timestamp(time()) timestamp = normalize_timestamp(time())
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': timestamp, headers={'X-Timestamp': timestamp,
@ -314,7 +315,7 @@ class TestObjectController(unittest.TestCase):
def test_PUT_container_connection(self): def test_PUT_container_connection(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
def mock_http_connect(response, with_exc=False): def mock_http_connect(response, with_exc=False):
class FakeConn(object): class FakeConn(object):
def __init__(self, status, with_exc): def __init__(self, status, with_exc):
@ -376,7 +377,7 @@ class TestObjectController(unittest.TestCase):
def test_HEAD(self): def test_HEAD(self):
""" Test swift.object_server.ObjectController.HEAD """ """ Test swift.object_server.ObjectController.HEAD """
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
req = Request.blank('/sda1/p/a/c') req = Request.blank('/sda1/p/a/c')
resp = self.object_controller.HEAD(req) resp = self.object_controller.HEAD(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -443,7 +444,7 @@ class TestObjectController(unittest.TestCase):
def test_GET(self): def test_GET(self):
""" Test swift.object_server.ObjectController.GET """ """ Test swift.object_server.ObjectController.GET """
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
req = Request.blank('/sda1/p/a/c') req = Request.blank('/sda1/p/a/c')
resp = self.object_controller.GET(req) resp = self.object_controller.GET(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -532,7 +533,7 @@ class TestObjectController(unittest.TestCase):
def test_GET_if_match(self): def test_GET_if_match(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={ headers={
'X-Timestamp': normalize_timestamp(time()), 'X-Timestamp': normalize_timestamp(time()),
@ -586,7 +587,7 @@ class TestObjectController(unittest.TestCase):
def test_GET_if_none_match(self): def test_GET_if_none_match(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={ headers={
'X-Timestamp': normalize_timestamp(time()), 'X-Timestamp': normalize_timestamp(time()),
@ -637,7 +638,7 @@ class TestObjectController(unittest.TestCase):
def test_GET_if_modified_since(self): def test_GET_if_modified_since(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
timestamp = normalize_timestamp(time()) timestamp = normalize_timestamp(time())
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={ headers={
@ -674,7 +675,7 @@ class TestObjectController(unittest.TestCase):
def test_GET_if_unmodified_since(self): def test_GET_if_unmodified_since(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
timestamp = normalize_timestamp(time()) timestamp = normalize_timestamp(time())
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={ headers={
@ -713,7 +714,7 @@ class TestObjectController(unittest.TestCase):
def test_DELETE(self): def test_DELETE(self):
""" Test swift.object_server.ObjectController.DELETE """ """ Test swift.object_server.ObjectController.DELETE """
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'DELETE'}) req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'DELETE'})
resp = self.object_controller.DELETE(req) resp = self.object_controller.DELETE(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -840,7 +841,7 @@ class TestObjectController(unittest.TestCase):
def test_chunked_put(self): def test_chunked_put(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
listener = listen(('localhost', 0)) listener = listen(('localhost', 0))
port = listener.getsockname()[1] port = listener.getsockname()[1]
killer = spawn(wsgi.server, listener, self.object_controller, killer = spawn(wsgi.server, listener, self.object_controller,
@ -866,7 +867,7 @@ class TestObjectController(unittest.TestCase):
def test_max_object_name_length(self): def test_max_object_name_length(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
timestamp = normalize_timestamp(time()) timestamp = normalize_timestamp(time())
req = Request.blank('/sda1/p/a/c/' + ('1' * 1024), req = Request.blank('/sda1/p/a/c/' + ('1' * 1024),
environ={'REQUEST_METHOD': 'PUT'}, environ={'REQUEST_METHOD': 'PUT'},
@ -887,7 +888,7 @@ class TestObjectController(unittest.TestCase):
def test_disk_file_app_iter_corners(self): def test_disk_file_app_iter_corners(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
df = object_server.DiskFile(self.testdir, 'sda1', '0', 'a', 'c', 'o') df = object_server.DiskFile(self.testdir, 'sda1', '0', 'a', 'c', 'o')
mkdirs(df.datadir) mkdirs(df.datadir)
f = open(os.path.join(df.datadir, f = open(os.path.join(df.datadir,
@ -920,7 +921,7 @@ class TestObjectController(unittest.TestCase):
def test_max_upload_time(self): def test_max_upload_time(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
class SlowBody(): class SlowBody():
def __init__(self): def __init__(self):
self.sent = 0 self.sent = 0
@ -962,7 +963,7 @@ class TestObjectController(unittest.TestCase):
def test_bad_sinces(self): def test_bad_sinces(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': normalize_timestamp(time()), headers={'X-Timestamp': normalize_timestamp(time()),
'Content-Length': '4', 'Content-Type': 'text/plain'}, 'Content-Length': '4', 'Content-Type': 'text/plain'},
@ -988,7 +989,7 @@ class TestObjectController(unittest.TestCase):
def test_content_encoding(self): def test_content_encoding(self):
if not self.path_to_test_xfs: if not self.path_to_test_xfs:
return raise SkipTest
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': normalize_timestamp(time()), headers={'X-Timestamp': normalize_timestamp(time()),
'Content-Length': '4', 'Content-Type': 'text/plain', 'Content-Length': '4', 'Content-Type': 'text/plain',

View File

@ -19,6 +19,7 @@ import logging
import os import os
import sys import sys
import unittest import unittest
from nose import SkipTest
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
from contextlib import contextmanager from contextlib import contextmanager
from cStringIO import StringIO from cStringIO import StringIO
@ -203,7 +204,7 @@ class TestProxyServer(unittest.TestCase):
app = MyApp(None, FakeMemcache(), account_ring=FakeRing(), app = MyApp(None, FakeMemcache(), account_ring=FakeRing(),
container_ring=FakeRing(), object_ring=FakeRing()) container_ring=FakeRing(), object_ring=FakeRing())
req = Request.blank('/account', environ={'REQUEST_METHOD': 'HEAD'}) req = Request.blank('/account', environ={'REQUEST_METHOD': 'HEAD'})
req.account = 'account' app.update_request(req)
resp = app.handle_request(req) resp = app.handle_request(req)
self.assertEquals(resp.status_int, 500) self.assertEquals(resp.status_int, 500)
@ -224,14 +225,14 @@ class TestObjectController(unittest.TestCase):
self.app.memcache.store = {} self.app.memcache.store = {}
req = Request.blank('/a/c/o', headers={'Content-Length': '0', req = Request.blank('/a/c/o', headers={'Content-Length': '0',
'Content-Type': 'text/plain'}) 'Content-Type': 'text/plain'})
req.account = 'a' self.app.update_request(req)
res = method(req) res = method(req)
self.assertEquals(res.status_int, expected) self.assertEquals(res.status_int, expected)
proxy_server.http_connect = fake_http_connect(*statuses, **kwargs) proxy_server.http_connect = fake_http_connect(*statuses, **kwargs)
self.app.memcache.store = {} self.app.memcache.store = {}
req = Request.blank('/a/c/o', headers={'Content-Length': '0', req = Request.blank('/a/c/o', headers={'Content-Length': '0',
'Content-Type': 'text/plain'}) 'Content-Type': 'text/plain'})
req.account = 'a' self.app.update_request(req)
res = method(req) res = method(req)
self.assertEquals(res.status_int, expected) self.assertEquals(res.status_int, expected)
@ -244,7 +245,7 @@ class TestObjectController(unittest.TestCase):
give_content_type=lambda content_type: give_content_type=lambda content_type:
self.assertEquals(content_type, expected.next())) self.assertEquals(content_type, expected.next()))
req = Request.blank('/a/c/%s' % filename, {}) req = Request.blank('/a/c/%s' % filename, {})
req.account = 'a' self.app.update_request(req)
res = controller.PUT(req) res = controller.PUT(req)
test_content_type('test.jpg', test_content_type('test.jpg',
iter(['', '', '', 'image/jpeg', 'image/jpeg', 'image/jpeg'])) iter(['', '', '', 'image/jpeg', 'image/jpeg', 'image/jpeg']))
@ -261,7 +262,7 @@ class TestObjectController(unittest.TestCase):
proxy_server.http_connect = fake_http_connect(*statuses) proxy_server.http_connect = fake_http_connect(*statuses)
req = Request.blank('/a/c/o.jpg', {}) req = Request.blank('/a/c/o.jpg', {})
req.content_length = 0 req.content_length = 0
req.account = 'a' self.app.update_request(req)
self.app.memcache.store = {} self.app.memcache.store = {}
res = controller.PUT(req) res = controller.PUT(req)
expected = str(expected) expected = str(expected)
@ -296,7 +297,7 @@ class TestObjectController(unittest.TestCase):
self.app.memcache.store = {} self.app.memcache.store = {}
req = Request.blank('/a/c/o.jpg', {}) req = Request.blank('/a/c/o.jpg', {})
req.content_length = 0 req.content_length = 0
req.account = 'a' self.app.update_request(req)
res = controller.PUT(req) res = controller.PUT(req)
expected = str(expected) expected = str(expected)
self.assertEquals(res.status[:len(expected)], expected) self.assertEquals(res.status[:len(expected)], expected)
@ -330,7 +331,7 @@ class TestObjectController(unittest.TestCase):
self.app.memcache.store = {} self.app.memcache.store = {}
proxy_server.http_connect = mock_http_connect(*statuses) proxy_server.http_connect = mock_http_connect(*statuses)
req = Request.blank('/a/c/o.jpg', {}) req = Request.blank('/a/c/o.jpg', {})
req.account = 'a' self.app.update_request(req)
req.body_file = StringIO('some data') req.body_file = StringIO('some data')
res = controller.PUT(req) res = controller.PUT(req)
expected = str(expected) expected = str(expected)
@ -347,7 +348,7 @@ class TestObjectController(unittest.TestCase):
req = Request.blank('/a/c/o', {}, headers={ req = Request.blank('/a/c/o', {}, headers={
'Content-Length': str(MAX_FILE_SIZE + 1), 'Content-Length': str(MAX_FILE_SIZE + 1),
'Content-Type': 'foo/bar'}) 'Content-Type': 'foo/bar'})
req.account = 'a' self.app.update_request(req)
res = controller.PUT(req) res = controller.PUT(req)
self.assertEquals(res.status_int, 413) self.assertEquals(res.status_int, 413)
@ -379,7 +380,7 @@ class TestObjectController(unittest.TestCase):
proxy_server.http_connect = mock_http_connect(*statuses) proxy_server.http_connect = mock_http_connect(*statuses)
req = Request.blank('/a/c/o.jpg', {}) req = Request.blank('/a/c/o.jpg', {})
req.content_length = 0 req.content_length = 0
req.account = 'a' self.app.update_request(req)
res = controller.PUT(req) res = controller.PUT(req)
expected = str(expected) expected = str(expected)
self.assertEquals(res.status[:len(str(expected))], self.assertEquals(res.status[:len(str(expected))],
@ -397,7 +398,7 @@ class TestObjectController(unittest.TestCase):
self.app.memcache.store = {} self.app.memcache.store = {}
req = Request.blank('/a/c/o', {}, headers={ req = Request.blank('/a/c/o', {}, headers={
'Content-Type': 'foo/bar'}) 'Content-Type': 'foo/bar'})
req.account = 'a' self.app.update_request(req)
res = controller.POST(req) res = controller.POST(req)
expected = str(expected) expected = str(expected)
self.assertEquals(res.status[:len(expected)], expected) self.assertEquals(res.status[:len(expected)], expected)
@ -417,7 +418,7 @@ class TestObjectController(unittest.TestCase):
proxy_server.http_connect = fake_http_connect(*statuses) proxy_server.http_connect = fake_http_connect(*statuses)
self.app.memcache.store = {} self.app.memcache.store = {}
req = Request.blank('/a/c/o', {}) req = Request.blank('/a/c/o', {})
req.account = 'a' self.app.update_request(req)
res = controller.DELETE(req) res = controller.DELETE(req)
self.assertEquals(res.status[:len(str(expected))], self.assertEquals(res.status[:len(str(expected))],
str(expected)) str(expected))
@ -436,7 +437,7 @@ class TestObjectController(unittest.TestCase):
proxy_server.http_connect = fake_http_connect(*statuses) proxy_server.http_connect = fake_http_connect(*statuses)
self.app.memcache.store = {} self.app.memcache.store = {}
req = Request.blank('/a/c/o', {}) req = Request.blank('/a/c/o', {})
req.account = 'a' self.app.update_request(req)
res = controller.HEAD(req) res = controller.HEAD(req)
self.assertEquals(res.status[:len(str(expected))], self.assertEquals(res.status[:len(str(expected))],
str(expected)) str(expected))
@ -460,14 +461,14 @@ class TestObjectController(unittest.TestCase):
req = Request.blank('/a/c/o', {}, headers={ req = Request.blank('/a/c/o', {}, headers={
'Content-Type': 'foo/bar', 'Content-Type': 'foo/bar',
'X-Object-Meta-Foo': 'x'*256}) 'X-Object-Meta-Foo': 'x'*256})
req.account = 'a' self.app.update_request(req)
res = controller.POST(req) res = controller.POST(req)
self.assertEquals(res.status_int, 202) self.assertEquals(res.status_int, 202)
proxy_server.http_connect = fake_http_connect(202, 202, 202) proxy_server.http_connect = fake_http_connect(202, 202, 202)
req = Request.blank('/a/c/o', {}, headers={ req = Request.blank('/a/c/o', {}, headers={
'Content-Type': 'foo/bar', 'Content-Type': 'foo/bar',
'X-Object-Meta-Foo': 'x'*257}) 'X-Object-Meta-Foo': 'x'*257})
req.account = 'a' self.app.update_request(req)
res = controller.POST(req) res = controller.POST(req)
self.assertEquals(res.status_int, 400) self.assertEquals(res.status_int, 400)
@ -481,14 +482,14 @@ class TestObjectController(unittest.TestCase):
req = Request.blank('/a/c/o', {}, headers={ req = Request.blank('/a/c/o', {}, headers={
'Content-Type': 'foo/bar', 'Content-Type': 'foo/bar',
('X-Object-Meta-'+'x'*128): 'x'}) ('X-Object-Meta-'+'x'*128): 'x'})
req.account = 'a' self.app.update_request(req)
res = controller.POST(req) res = controller.POST(req)
self.assertEquals(res.status_int, 202) self.assertEquals(res.status_int, 202)
proxy_server.http_connect = fake_http_connect(202, 202, 202) proxy_server.http_connect = fake_http_connect(202, 202, 202)
req = Request.blank('/a/c/o', {}, headers={ req = Request.blank('/a/c/o', {}, headers={
'Content-Type': 'foo/bar', 'Content-Type': 'foo/bar',
('X-Object-Meta-'+'x'*129): 'x'}) ('X-Object-Meta-'+'x'*129): 'x'})
req.account = 'a' self.app.update_request(req)
res = controller.POST(req) res = controller.POST(req)
self.assertEquals(res.status_int, 400) self.assertEquals(res.status_int, 400)
@ -500,7 +501,7 @@ class TestObjectController(unittest.TestCase):
headers.update({'Content-Type': 'foo/bar'}) headers.update({'Content-Type': 'foo/bar'})
proxy_server.http_connect = fake_http_connect(202, 202, 202) proxy_server.http_connect = fake_http_connect(202, 202, 202)
req = Request.blank('/a/c/o', {}, headers=headers) req = Request.blank('/a/c/o', {}, headers=headers)
req.account = 'a' self.app.update_request(req)
res = controller.POST(req) res = controller.POST(req)
self.assertEquals(res.status_int, 400) self.assertEquals(res.status_int, 400)
@ -512,7 +513,7 @@ class TestObjectController(unittest.TestCase):
headers.update({'Content-Type': 'foo/bar'}) headers.update({'Content-Type': 'foo/bar'})
proxy_server.http_connect = fake_http_connect(202, 202, 202) proxy_server.http_connect = fake_http_connect(202, 202, 202)
req = Request.blank('/a/c/o', {}, headers=headers) req = Request.blank('/a/c/o', {}, headers=headers)
req.account = 'a' self.app.update_request(req)
res = controller.POST(req) res = controller.POST(req)
self.assertEquals(res.status_int, 400) self.assertEquals(res.status_int, 400)
@ -542,7 +543,7 @@ class TestObjectController(unittest.TestCase):
req = Request.blank('/a/c/o', req = Request.blank('/a/c/o',
environ={'REQUEST_METHOD': 'PUT', 'wsgi.input': SlowBody()}, environ={'REQUEST_METHOD': 'PUT', 'wsgi.input': SlowBody()},
headers={'Content-Length': '4', 'Content-Type': 'text/plain'}) headers={'Content-Length': '4', 'Content-Type': 'text/plain'})
req.account = 'account' self.app.update_request(req)
controller = proxy_server.ObjectController(self.app, 'account', controller = proxy_server.ObjectController(self.app, 'account',
'container', 'object') 'container', 'object')
proxy_server.http_connect = \ proxy_server.http_connect = \
@ -554,7 +555,7 @@ class TestObjectController(unittest.TestCase):
req = Request.blank('/a/c/o', req = Request.blank('/a/c/o',
environ={'REQUEST_METHOD': 'PUT', 'wsgi.input': SlowBody()}, environ={'REQUEST_METHOD': 'PUT', 'wsgi.input': SlowBody()},
headers={'Content-Length': '4', 'Content-Type': 'text/plain'}) headers={'Content-Length': '4', 'Content-Type': 'text/plain'})
req.account = 'account' self.app.update_request(req)
proxy_server.http_connect = \ proxy_server.http_connect = \
fake_http_connect(201, 201, 201) fake_http_connect(201, 201, 201)
# obj obj obj # obj obj obj
@ -583,7 +584,7 @@ class TestObjectController(unittest.TestCase):
req = Request.blank('/a/c/o', req = Request.blank('/a/c/o',
environ={'REQUEST_METHOD': 'PUT', 'wsgi.input': SlowBody()}, environ={'REQUEST_METHOD': 'PUT', 'wsgi.input': SlowBody()},
headers={'Content-Length': '4', 'Content-Type': 'text/plain'}) headers={'Content-Length': '4', 'Content-Type': 'text/plain'})
req.account = 'account' self.app.update_request(req)
controller = proxy_server.ObjectController(self.app, 'account', controller = proxy_server.ObjectController(self.app, 'account',
'container', 'object') 'container', 'object')
proxy_server.http_connect = \ proxy_server.http_connect = \
@ -607,7 +608,7 @@ class TestObjectController(unittest.TestCase):
dev['ip'] = '127.0.0.1' dev['ip'] = '127.0.0.1'
dev['port'] = 1 dev['port'] = 1
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'GET'}) req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'GET'})
req.account = 'account' self.app.update_request(req)
controller = proxy_server.ObjectController(self.app, 'account', controller = proxy_server.ObjectController(self.app, 'account',
'container', 'object') 'container', 'object')
proxy_server.http_connect = \ proxy_server.http_connect = \
@ -649,7 +650,7 @@ class TestObjectController(unittest.TestCase):
environ={'REQUEST_METHOD': 'PUT'}, environ={'REQUEST_METHOD': 'PUT'},
headers={'Content-Length': '4', 'Content-Type': 'text/plain'}, headers={'Content-Length': '4', 'Content-Type': 'text/plain'},
body=' ') body=' ')
req.account = 'account' self.app.update_request(req)
controller = proxy_server.ObjectController(self.app, 'account', controller = proxy_server.ObjectController(self.app, 'account',
'container', 'object') 'container', 'object')
proxy_server.http_connect = \ proxy_server.http_connect = \
@ -663,7 +664,7 @@ class TestObjectController(unittest.TestCase):
environ={'REQUEST_METHOD': 'PUT'}, environ={'REQUEST_METHOD': 'PUT'},
headers={'Content-Length': '4', 'Content-Type': 'text/plain'}, headers={'Content-Length': '4', 'Content-Type': 'text/plain'},
body=' ') body=' ')
req.account = 'account' self.app.update_request(req)
resp = controller.PUT(req) resp = controller.PUT(req)
self.assertEquals(resp.status_int, 503) self.assertEquals(resp.status_int, 503)
@ -708,7 +709,7 @@ class TestObjectController(unittest.TestCase):
def test_proxy_passes_content_type(self): def test_proxy_passes_content_type(self):
with save_globals(): with save_globals():
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'GET'}) req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'GET'})
req.account = 'account' self.app.update_request(req)
controller = proxy_server.ObjectController(self.app, 'account', controller = proxy_server.ObjectController(self.app, 'account',
'container', 'object') 'container', 'object')
proxy_server.http_connect = fake_http_connect(200, 200, 200) proxy_server.http_connect = fake_http_connect(200, 200, 200)
@ -728,7 +729,7 @@ class TestObjectController(unittest.TestCase):
def test_proxy_passes_content_length_on_head(self): def test_proxy_passes_content_length_on_head(self):
with save_globals(): with save_globals():
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'HEAD'}) req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'HEAD'})
req.account = 'account' self.app.update_request(req)
controller = proxy_server.ObjectController(self.app, 'account', controller = proxy_server.ObjectController(self.app, 'account',
'container', 'object') 'container', 'object')
proxy_server.http_connect = fake_http_connect(200, 200, 200) proxy_server.http_connect = fake_http_connect(200, 200, 200)
@ -777,7 +778,7 @@ class TestObjectController(unittest.TestCase):
proxy_server.http_connect = \ proxy_server.http_connect = \
fake_http_connect(200, 200, 200, 200, 200, 200) fake_http_connect(200, 200, 200, 200, 200, 200)
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'DELETE'}) req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'DELETE'})
req.account = 'a' self.app.update_request(req)
resp = getattr(controller, 'DELETE')(req) resp = getattr(controller, 'DELETE')(req)
self.assertEquals(resp.status_int, 200) self.assertEquals(resp.status_int, 200)
@ -853,7 +854,7 @@ class TestObjectController(unittest.TestCase):
proxy_server.http_connect = \ proxy_server.http_connect = \
fake_http_connect(404, 404, 404, 200, 200, 200) fake_http_connect(404, 404, 404, 200, 200, 200)
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}) req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'})
req.account = 'a' self.app.update_request(req)
resp = controller.PUT(req) resp = controller.PUT(req)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
@ -861,7 +862,7 @@ class TestObjectController(unittest.TestCase):
fake_http_connect(404, 404, 404, 200, 200, 200) fake_http_connect(404, 404, 404, 200, 200, 200)
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'POST'},
headers={'Content-Type': 'text/plain'}) headers={'Content-Type': 'text/plain'})
req.account = 'a' self.app.update_request(req)
resp = controller.POST(req) resp = controller.POST(req)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
@ -874,7 +875,7 @@ class TestObjectController(unittest.TestCase):
# acct cont obj obj obj # acct cont obj obj obj
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'Content-Length': '0'}) headers={'Content-Length': '0'})
req.account = 'a' self.app.update_request(req)
resp = controller.PUT(req) resp = controller.PUT(req)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
@ -883,7 +884,7 @@ class TestObjectController(unittest.TestCase):
headers={'Content-Length': '0', headers={'Content-Length': '0',
'X-Object-Meta-' + ('a' * 'X-Object-Meta-' + ('a' *
MAX_META_NAME_LENGTH) : 'v'}) MAX_META_NAME_LENGTH) : 'v'})
req.account = 'a' self.app.update_request(req)
resp = controller.PUT(req) resp = controller.PUT(req)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
proxy_server.http_connect = fake_http_connect(201, 201, 201) proxy_server.http_connect = fake_http_connect(201, 201, 201)
@ -891,7 +892,7 @@ class TestObjectController(unittest.TestCase):
headers={'Content-Length': '0', headers={'Content-Length': '0',
'X-Object-Meta-' + ('a' * 'X-Object-Meta-' + ('a' *
(MAX_META_NAME_LENGTH + 1)) : 'v'}) (MAX_META_NAME_LENGTH + 1)) : 'v'})
req.account = 'a' self.app.update_request(req)
resp = controller.PUT(req) resp = controller.PUT(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -900,7 +901,7 @@ class TestObjectController(unittest.TestCase):
headers={'Content-Length': '0', headers={'Content-Length': '0',
'X-Object-Meta-Too-Long': 'a' * 'X-Object-Meta-Too-Long': 'a' *
MAX_META_VALUE_LENGTH}) MAX_META_VALUE_LENGTH})
req.account = 'a' self.app.update_request(req)
resp = controller.PUT(req) resp = controller.PUT(req)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
proxy_server.http_connect = fake_http_connect(201, 201, 201) proxy_server.http_connect = fake_http_connect(201, 201, 201)
@ -908,7 +909,7 @@ class TestObjectController(unittest.TestCase):
headers={'Content-Length': '0', headers={'Content-Length': '0',
'X-Object-Meta-Too-Long': 'a' * 'X-Object-Meta-Too-Long': 'a' *
(MAX_META_VALUE_LENGTH + 1)}) (MAX_META_VALUE_LENGTH + 1)})
req.account = 'a' self.app.update_request(req)
resp = controller.PUT(req) resp = controller.PUT(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -918,7 +919,7 @@ class TestObjectController(unittest.TestCase):
headers['X-Object-Meta-%d' % x] = 'v' headers['X-Object-Meta-%d' % x] = 'v'
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers=headers) headers=headers)
req.account = 'a' self.app.update_request(req)
resp = controller.PUT(req) resp = controller.PUT(req)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
proxy_server.http_connect = fake_http_connect(201, 201, 201) proxy_server.http_connect = fake_http_connect(201, 201, 201)
@ -927,7 +928,7 @@ class TestObjectController(unittest.TestCase):
headers['X-Object-Meta-%d' % x] = 'v' headers['X-Object-Meta-%d' % x] = 'v'
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers=headers) headers=headers)
req.account = 'a' self.app.update_request(req)
resp = controller.PUT(req) resp = controller.PUT(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -946,7 +947,7 @@ class TestObjectController(unittest.TestCase):
'a' * (MAX_META_OVERALL_SIZE - size - 1) 'a' * (MAX_META_OVERALL_SIZE - size - 1)
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers=headers) headers=headers)
req.account = 'a' self.app.update_request(req)
resp = controller.PUT(req) resp = controller.PUT(req)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
proxy_server.http_connect = fake_http_connect(201, 201, 201) proxy_server.http_connect = fake_http_connect(201, 201, 201)
@ -954,7 +955,7 @@ class TestObjectController(unittest.TestCase):
'a' * (MAX_META_OVERALL_SIZE - size) 'a' * (MAX_META_OVERALL_SIZE - size)
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers=headers) headers=headers)
req.account = 'a' self.app.update_request(req)
resp = controller.PUT(req) resp = controller.PUT(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -964,7 +965,7 @@ class TestObjectController(unittest.TestCase):
'container', 'object') 'container', 'object')
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'Content-Length': '0'}) headers={'Content-Length': '0'})
req.account = 'a' self.app.update_request(req)
proxy_server.http_connect = \ proxy_server.http_connect = \
fake_http_connect(200, 200, 201, 201, 201) fake_http_connect(200, 200, 201, 201, 201)
# acct cont obj obj obj # acct cont obj obj obj
@ -974,7 +975,7 @@ class TestObjectController(unittest.TestCase):
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'Content-Length': '0', headers={'Content-Length': '0',
'X-Copy-From': 'c/o'}) 'X-Copy-From': 'c/o'})
req.account = 'a' self.app.update_request(req)
proxy_server.http_connect = \ proxy_server.http_connect = \
fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201) fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201)
# acct cont acct cont objc obj obj obj # acct cont acct cont objc obj obj obj
@ -986,7 +987,7 @@ class TestObjectController(unittest.TestCase):
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'Content-Length': '0', headers={'Content-Length': '0',
'X-Copy-From': '/c/o'}) 'X-Copy-From': '/c/o'})
req.account = 'a' self.app.update_request(req)
proxy_server.http_connect = \ proxy_server.http_connect = \
fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201) fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201)
# acct cont acct cont objc obj obj obj # acct cont acct cont objc obj obj obj
@ -998,7 +999,7 @@ class TestObjectController(unittest.TestCase):
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'Content-Length': '0', headers={'Content-Length': '0',
'X-Copy-From': '/c/o'}) 'X-Copy-From': '/c/o'})
req.account = 'a' self.app.update_request(req)
proxy_server.http_connect = \ proxy_server.http_connect = \
fake_http_connect(200, 200, 503, 503, 503) fake_http_connect(200, 200, 503, 503, 503)
# acct cont objc objc objc # acct cont objc objc objc
@ -1009,7 +1010,7 @@ class TestObjectController(unittest.TestCase):
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'Content-Length': '0', headers={'Content-Length': '0',
'X-Copy-From': '/c/o'}) 'X-Copy-From': '/c/o'})
req.account = 'a' self.app.update_request(req)
proxy_server.http_connect = \ proxy_server.http_connect = \
fake_http_connect(200, 200, 404, 404, 404) fake_http_connect(200, 200, 404, 404, 404)
# acct cont objc objc objc # acct cont objc objc objc
@ -1020,7 +1021,7 @@ class TestObjectController(unittest.TestCase):
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'Content-Length': '0', headers={'Content-Length': '0',
'X-Copy-From': '/c/o'}) 'X-Copy-From': '/c/o'})
req.account = 'a' self.app.update_request(req)
proxy_server.http_connect = \ proxy_server.http_connect = \
fake_http_connect(200, 200, 404, 404, 200, 201, 201, 201) fake_http_connect(200, 200, 404, 404, 200, 201, 201, 201)
# acct cont objc objc objc obj obj obj # acct cont objc objc objc obj obj obj
@ -1032,7 +1033,7 @@ class TestObjectController(unittest.TestCase):
headers={'Content-Length': '0', headers={'Content-Length': '0',
'X-Copy-From': '/c/o', 'X-Copy-From': '/c/o',
'X-Object-Meta-Ours': 'okay'}) 'X-Object-Meta-Ours': 'okay'})
req.account = 'a' self.app.update_request(req)
proxy_server.http_connect = \ proxy_server.http_connect = \
fake_http_connect(200, 200, 200, 201, 201, 201) fake_http_connect(200, 200, 200, 201, 201, 201)
# acct cont objc obj obj obj # acct cont objc obj obj obj
@ -1052,7 +1053,7 @@ class TestObjectController(unittest.TestCase):
'pointing to a valid directory.\n' \ 'pointing to a valid directory.\n' \
'Please set PATH_TO_TEST_XFS to a directory on an XFS file ' \ 'Please set PATH_TO_TEST_XFS to a directory on an XFS file ' \
'system for testing.' 'system for testing.'
return raise SkipTest
testdir = \ testdir = \
os.path.join(path_to_test_xfs, 'tmp_test_proxy_server_chunked') os.path.join(path_to_test_xfs, 'tmp_test_proxy_server_chunked')
mkdirs(testdir) mkdirs(testdir)
@ -1434,7 +1435,7 @@ class TestObjectController(unittest.TestCase):
'container', 'object') 'container', 'object')
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'Content-Length': '0'}) headers={'Content-Length': '0'})
req.account = 'a' self.app.update_request(req)
proxy_server.http_connect = fake_http_connect(200, 201, 201, 201, proxy_server.http_connect = fake_http_connect(200, 201, 201, 201,
etags=[None, etags=[None,
'68b329da9893e34099c7d8ad5cb9c940', '68b329da9893e34099c7d8ad5cb9c940',
@ -1452,7 +1453,7 @@ class TestObjectController(unittest.TestCase):
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'Content-Length': '10'}, headers={'Content-Length': '10'},
body='1234567890') body='1234567890')
req.account = 'a' self.app.update_request(req)
res = controller.PUT(req) res = controller.PUT(req)
self.assert_(hasattr(req, 'bytes_transferred')) self.assert_(hasattr(req, 'bytes_transferred'))
self.assertEquals(req.bytes_transferred, 10) self.assertEquals(req.bytes_transferred, 10)
@ -1464,7 +1465,7 @@ class TestObjectController(unittest.TestCase):
controller = proxy_server.ObjectController(self.app, 'account', controller = proxy_server.ObjectController(self.app, 'account',
'container', 'object') 'container', 'object')
req = Request.blank('/a/c/o') req = Request.blank('/a/c/o')
req.account = 'a' self.app.update_request(req)
res = controller.GET(req) res = controller.GET(req)
res.body res.body
self.assert_(hasattr(res, 'bytes_transferred')) self.assert_(hasattr(res, 'bytes_transferred'))
@ -1479,7 +1480,7 @@ class TestObjectController(unittest.TestCase):
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'Content-Length': '10'}, headers={'Content-Length': '10'},
body='12345') body='12345')
req.account = 'a' self.app.update_request(req)
res = controller.PUT(req) res = controller.PUT(req)
self.assertEquals(req.bytes_transferred, 5) self.assertEquals(req.bytes_transferred, 5)
self.assert_(hasattr(req, 'client_disconnect')) self.assert_(hasattr(req, 'client_disconnect'))
@ -1492,7 +1493,7 @@ class TestObjectController(unittest.TestCase):
controller = proxy_server.ObjectController(self.app, 'account', controller = proxy_server.ObjectController(self.app, 'account',
'container', 'object') 'container', 'object')
req = Request.blank('/a/c/o') req = Request.blank('/a/c/o')
req.account = 'a' self.app.update_request(req)
orig_object_chunk_size = self.app.object_chunk_size orig_object_chunk_size = self.app.object_chunk_size
try: try:
self.app.object_chunk_size = 5 self.app.object_chunk_size = 5
@ -1528,14 +1529,14 @@ class TestContainerController(unittest.TestCase):
self.app.memcache.store = {} self.app.memcache.store = {}
req = Request.blank('/a/c', headers={'Content-Length': '0', req = Request.blank('/a/c', headers={'Content-Length': '0',
'Content-Type': 'text/plain'}) 'Content-Type': 'text/plain'})
req.account = 'a' self.app.update_request(req)
res = method(req) res = method(req)
self.assertEquals(res.status_int, expected) self.assertEquals(res.status_int, expected)
proxy_server.http_connect = fake_http_connect(*statuses, **kwargs) proxy_server.http_connect = fake_http_connect(*statuses, **kwargs)
self.app.memcache.store = {} self.app.memcache.store = {}
req = Request.blank('/a/c/', headers={'Content-Length': '0', req = Request.blank('/a/c/', headers={'Content-Length': '0',
'Content-Type': 'text/plain'}) 'Content-Type': 'text/plain'})
req.account = 'a' self.app.update_request(req)
res = method(req) res = method(req)
self.assertEquals(res.status_int, expected) self.assertEquals(res.status_int, expected)
@ -1547,7 +1548,7 @@ class TestContainerController(unittest.TestCase):
proxy_server.http_connect = fake_http_connect(*statuses, **kwargs) proxy_server.http_connect = fake_http_connect(*statuses, **kwargs)
self.app.memcache.store = {} self.app.memcache.store = {}
req = Request.blank('/a/c', {}) req = Request.blank('/a/c', {})
req.account = 'a' self.app.update_request(req)
res = controller.HEAD(req) res = controller.HEAD(req)
self.assertEquals(res.status[:len(str(expected))], self.assertEquals(res.status[:len(str(expected))],
str(expected)) str(expected))
@ -1570,7 +1571,7 @@ class TestContainerController(unittest.TestCase):
self.app.memcache.store = {} self.app.memcache.store = {}
req = Request.blank('/a/c', {}) req = Request.blank('/a/c', {})
req.content_length = 0 req.content_length = 0
req.account = 'a' self.app.update_request(req)
res = controller.PUT(req) res = controller.PUT(req)
expected = str(expected) expected = str(expected)
self.assertEquals(res.status[:len(expected)], expected) self.assertEquals(res.status[:len(expected)], expected)
@ -1613,7 +1614,7 @@ class TestContainerController(unittest.TestCase):
fake_http_connect(200, 200, 200, 200) fake_http_connect(200, 200, 200, 200)
self.app.memcache.store = {} self.app.memcache.store = {}
req = Request.blank('/a/c', environ={'REQUEST_METHOD': meth}) req = Request.blank('/a/c', environ={'REQUEST_METHOD': meth})
req.account = 'a' self.app.update_request(req)
resp = getattr(controller, meth)(req) resp = getattr(controller, meth)(req)
self.assertEquals(resp.status_int, 200) self.assertEquals(resp.status_int, 200)
@ -1657,7 +1658,7 @@ class TestContainerController(unittest.TestCase):
self.app.memcache = MockMemcache(allow_lock=True) self.app.memcache = MockMemcache(allow_lock=True)
proxy_server.http_connect = fake_http_connect(200, 200, 200, 201, 201, 201, missing_container=True) proxy_server.http_connect = fake_http_connect(200, 200, 200, 201, 201, 201, missing_container=True)
req = Request.blank('/a/c', environ={'REQUEST_METHOD': 'PUT'}) req = Request.blank('/a/c', environ={'REQUEST_METHOD': 'PUT'})
req.account = 'a' self.app.update_request(req)
res = controller.PUT(req) res = controller.PUT(req)
self.assertEquals(res.status_int, 201) self.assertEquals(res.status_int, 201)
@ -1703,7 +1704,7 @@ class TestContainerController(unittest.TestCase):
controller = proxy_server.ContainerController(self.app, 'account', controller = proxy_server.ContainerController(self.app, 'account',
'container') 'container')
req = Request.blank('/a/c?format=json') req = Request.blank('/a/c?format=json')
req.account = 'a' self.app.update_request(req)
res = controller.GET(req) res = controller.GET(req)
res.body res.body
self.assert_(hasattr(res, 'bytes_transferred')) self.assert_(hasattr(res, 'bytes_transferred'))
@ -1715,7 +1716,7 @@ class TestContainerController(unittest.TestCase):
controller = proxy_server.ContainerController(self.app, 'account', controller = proxy_server.ContainerController(self.app, 'account',
'container') 'container')
req = Request.blank('/a/c?format=json') req = Request.blank('/a/c?format=json')
req.account = 'a' self.app.update_request(req)
orig_object_chunk_size = self.app.object_chunk_size orig_object_chunk_size = self.app.object_chunk_size
try: try:
self.app.object_chunk_size = 1 self.app.object_chunk_size = 1
@ -1760,8 +1761,7 @@ class TestContainerController(unittest.TestCase):
201, give_connect=test_connect) 201, give_connect=test_connect)
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method}, req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
headers={test_header: test_value}) headers={test_header: test_value})
req.account = 'a' self.app.update_request(req)
req.container = 'c'
res = getattr(controller, method)(req) res = getattr(controller, method)(req)
self.assertEquals(test_errors, []) self.assertEquals(test_errors, [])
@ -1776,7 +1776,7 @@ class TestContainerController(unittest.TestCase):
controller = proxy_server.ContainerController(self.app, 'a', 'c') controller = proxy_server.ContainerController(self.app, 'a', 'c')
proxy_server.http_connect = fake_http_connect(200, 201, 201, 201) proxy_server.http_connect = fake_http_connect(200, 201, 201, 201)
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method}) req = Request.blank('/a/c', environ={'REQUEST_METHOD': method})
req.account = 'a' self.app.update_request(req)
resp = getattr(controller, method)(req) resp = getattr(controller, method)(req)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
@ -1784,16 +1784,14 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method}, req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
headers={'X-Container-Meta-' + headers={'X-Container-Meta-' +
('a' * MAX_META_NAME_LENGTH): 'v'}) ('a' * MAX_META_NAME_LENGTH): 'v'})
req.account = 'a' self.app.update_request(req)
req.container = 'c'
resp = getattr(controller, method)(req) resp = getattr(controller, method)(req)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
proxy_server.http_connect = fake_http_connect(201, 201, 201) proxy_server.http_connect = fake_http_connect(201, 201, 201)
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method}, req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
headers={'X-Container-Meta-' + headers={'X-Container-Meta-' +
('a' * (MAX_META_NAME_LENGTH + 1)): 'v'}) ('a' * (MAX_META_NAME_LENGTH + 1)): 'v'})
req.account = 'a' self.app.update_request(req)
req.container = 'c'
resp = getattr(controller, method)(req) resp = getattr(controller, method)(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -1801,16 +1799,14 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method}, req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
headers={'X-Container-Meta-Too-Long': headers={'X-Container-Meta-Too-Long':
'a' * MAX_META_VALUE_LENGTH}) 'a' * MAX_META_VALUE_LENGTH})
req.account = 'a' self.app.update_request(req)
req.container = 'c'
resp = getattr(controller, method)(req) resp = getattr(controller, method)(req)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
proxy_server.http_connect = fake_http_connect(201, 201, 201) proxy_server.http_connect = fake_http_connect(201, 201, 201)
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method}, req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
headers={'X-Container-Meta-Too-Long': headers={'X-Container-Meta-Too-Long':
'a' * (MAX_META_VALUE_LENGTH + 1)}) 'a' * (MAX_META_VALUE_LENGTH + 1)})
req.account = 'a' self.app.update_request(req)
req.container = 'c'
resp = getattr(controller, method)(req) resp = getattr(controller, method)(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -1820,8 +1816,7 @@ class TestContainerController(unittest.TestCase):
headers['X-Container-Meta-%d' % x] = 'v' headers['X-Container-Meta-%d' % x] = 'v'
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method}, req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
headers=headers) headers=headers)
req.account = 'a' self.app.update_request(req)
req.container = 'c'
resp = getattr(controller, method)(req) resp = getattr(controller, method)(req)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
proxy_server.http_connect = fake_http_connect(201, 201, 201) proxy_server.http_connect = fake_http_connect(201, 201, 201)
@ -1830,8 +1825,7 @@ class TestContainerController(unittest.TestCase):
headers['X-Container-Meta-%d' % x] = 'v' headers['X-Container-Meta-%d' % x] = 'v'
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method}, req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
headers=headers) headers=headers)
req.account = 'a' self.app.update_request(req)
req.container = 'c'
resp = getattr(controller, method)(req) resp = getattr(controller, method)(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -1849,8 +1843,7 @@ class TestContainerController(unittest.TestCase):
'a' * (MAX_META_OVERALL_SIZE - size - 1) 'a' * (MAX_META_OVERALL_SIZE - size - 1)
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method}, req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
headers=headers) headers=headers)
req.account = 'a' self.app.update_request(req)
req.container = 'c'
resp = getattr(controller, method)(req) resp = getattr(controller, method)(req)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
proxy_server.http_connect = fake_http_connect(201, 201, 201) proxy_server.http_connect = fake_http_connect(201, 201, 201)
@ -1858,8 +1851,7 @@ class TestContainerController(unittest.TestCase):
'a' * (MAX_META_OVERALL_SIZE - size) 'a' * (MAX_META_OVERALL_SIZE - size)
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method}, req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
headers=headers) headers=headers)
req.account = 'a' self.app.update_request(req)
req.container = 'c'
resp = getattr(controller, method)(req) resp = getattr(controller, method)(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -1875,12 +1867,12 @@ class TestAccountController(unittest.TestCase):
with save_globals(): with save_globals():
proxy_server.http_connect = fake_http_connect(*statuses) proxy_server.http_connect = fake_http_connect(*statuses)
req = Request.blank('/a', {}) req = Request.blank('/a', {})
req.account = 'a' self.app.update_request(req)
res = method(req) res = method(req)
self.assertEquals(res.status_int, expected) self.assertEquals(res.status_int, expected)
proxy_server.http_connect = fake_http_connect(*statuses) proxy_server.http_connect = fake_http_connect(*statuses)
req = Request.blank('/a/', {}) req = Request.blank('/a/', {})
req.account = 'a' self.app.update_request(req)
res = method(req) res = method(req)
self.assertEquals(res.status_int, expected) self.assertEquals(res.status_int, expected)
@ -1930,7 +1922,7 @@ class TestAccountController(unittest.TestCase):
dev['port'] = 1 ## can't connect on this port dev['port'] = 1 ## can't connect on this port
controller = proxy_server.AccountController(self.app, 'account') controller = proxy_server.AccountController(self.app, 'account')
req = Request.blank('/account', environ={'REQUEST_METHOD': 'HEAD'}) req = Request.blank('/account', environ={'REQUEST_METHOD': 'HEAD'})
req.account = 'account' self.app.update_request(req)
resp = controller.HEAD(req) resp = controller.HEAD(req)
self.assertEquals(resp.status_int, 503) self.assertEquals(resp.status_int, 503)
@ -1941,7 +1933,7 @@ class TestAccountController(unittest.TestCase):
dev['port'] = -1 ## invalid port number dev['port'] = -1 ## invalid port number
controller = proxy_server.AccountController(self.app, 'account') controller = proxy_server.AccountController(self.app, 'account')
req = Request.blank('/account', environ={'REQUEST_METHOD': 'HEAD'}) req = Request.blank('/account', environ={'REQUEST_METHOD': 'HEAD'})
req.account = 'account' self.app.update_request(req)
resp = controller.HEAD(req) resp = controller.HEAD(req)
self.assertEquals(resp.status_int, 503) self.assertEquals(resp.status_int, 503)
@ -1950,7 +1942,7 @@ class TestAccountController(unittest.TestCase):
proxy_server.http_connect = fake_http_connect(200, 200, body='{}') proxy_server.http_connect = fake_http_connect(200, 200, body='{}')
controller = proxy_server.AccountController(self.app, 'account') controller = proxy_server.AccountController(self.app, 'account')
req = Request.blank('/a?format=json') req = Request.blank('/a?format=json')
req.account = 'a' self.app.update_request(req)
res = controller.GET(req) res = controller.GET(req)
res.body res.body
self.assert_(hasattr(res, 'bytes_transferred')) self.assert_(hasattr(res, 'bytes_transferred'))
@ -1961,7 +1953,7 @@ class TestAccountController(unittest.TestCase):
proxy_server.http_connect = fake_http_connect(200, 200, body='{}') proxy_server.http_connect = fake_http_connect(200, 200, body='{}')
controller = proxy_server.AccountController(self.app, 'account') controller = proxy_server.AccountController(self.app, 'account')
req = Request.blank('/a?format=json') req = Request.blank('/a?format=json')
req.account = 'a' self.app.update_request(req)
orig_object_chunk_size = self.app.object_chunk_size orig_object_chunk_size = self.app.object_chunk_size
try: try:
self.app.object_chunk_size = 1 self.app.object_chunk_size = 1
@ -1999,7 +1991,7 @@ class TestAccountController(unittest.TestCase):
give_connect=test_connect) give_connect=test_connect)
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
headers={test_header: test_value}) headers={test_header: test_value})
req.account = 'a' self.app.update_request(req)
res = controller.POST(req) res = controller.POST(req)
self.assertEquals(test_errors, []) self.assertEquals(test_errors, [])
@ -2008,7 +2000,7 @@ class TestAccountController(unittest.TestCase):
controller = proxy_server.AccountController(self.app, 'a') controller = proxy_server.AccountController(self.app, 'a')
proxy_server.http_connect = fake_http_connect(204, 204, 204) proxy_server.http_connect = fake_http_connect(204, 204, 204)
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'}) req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'})
req.account = 'a' self.app.update_request(req)
resp = controller.POST(req) resp = controller.POST(req)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
@ -2016,14 +2008,14 @@ class TestAccountController(unittest.TestCase):
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
headers={'X-Account-Meta-' + headers={'X-Account-Meta-' +
('a' * MAX_META_NAME_LENGTH): 'v'}) ('a' * MAX_META_NAME_LENGTH): 'v'})
req.account = 'a' self.app.update_request(req)
resp = controller.POST(req) resp = controller.POST(req)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
proxy_server.http_connect = fake_http_connect(204, 204, 204) proxy_server.http_connect = fake_http_connect(204, 204, 204)
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
headers={'X-Account-Meta-' + headers={'X-Account-Meta-' +
('a' * (MAX_META_NAME_LENGTH + 1)): 'v'}) ('a' * (MAX_META_NAME_LENGTH + 1)): 'v'})
req.account = 'a' self.app.update_request(req)
resp = controller.POST(req) resp = controller.POST(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -2031,14 +2023,14 @@ class TestAccountController(unittest.TestCase):
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
headers={'X-Account-Meta-Too-Long': headers={'X-Account-Meta-Too-Long':
'a' * MAX_META_VALUE_LENGTH}) 'a' * MAX_META_VALUE_LENGTH})
req.account = 'a' self.app.update_request(req)
resp = controller.POST(req) resp = controller.POST(req)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
proxy_server.http_connect = fake_http_connect(204, 204, 204) proxy_server.http_connect = fake_http_connect(204, 204, 204)
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
headers={'X-Account-Meta-Too-Long': headers={'X-Account-Meta-Too-Long':
'a' * (MAX_META_VALUE_LENGTH + 1)}) 'a' * (MAX_META_VALUE_LENGTH + 1)})
req.account = 'a' self.app.update_request(req)
resp = controller.POST(req) resp = controller.POST(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -2048,7 +2040,7 @@ class TestAccountController(unittest.TestCase):
headers['X-Account-Meta-%d' % x] = 'v' headers['X-Account-Meta-%d' % x] = 'v'
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
headers=headers) headers=headers)
req.account = 'a' self.app.update_request(req)
resp = controller.POST(req) resp = controller.POST(req)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
proxy_server.http_connect = fake_http_connect(204, 204, 204) proxy_server.http_connect = fake_http_connect(204, 204, 204)
@ -2057,7 +2049,7 @@ class TestAccountController(unittest.TestCase):
headers['X-Account-Meta-%d' % x] = 'v' headers['X-Account-Meta-%d' % x] = 'v'
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
headers=headers) headers=headers)
req.account = 'a' self.app.update_request(req)
resp = controller.POST(req) resp = controller.POST(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
@ -2075,7 +2067,7 @@ class TestAccountController(unittest.TestCase):
'a' * (MAX_META_OVERALL_SIZE - size - 1) 'a' * (MAX_META_OVERALL_SIZE - size - 1)
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
headers=headers) headers=headers)
req.account = 'a' self.app.update_request(req)
resp = controller.POST(req) resp = controller.POST(req)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
proxy_server.http_connect = fake_http_connect(204, 204, 204) proxy_server.http_connect = fake_http_connect(204, 204, 204)
@ -2083,7 +2075,7 @@ class TestAccountController(unittest.TestCase):
'a' * (MAX_META_OVERALL_SIZE - size) 'a' * (MAX_META_OVERALL_SIZE - size)
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
headers=headers) headers=headers)
req.account = 'a' self.app.update_request(req)
resp = controller.POST(req) resp = controller.POST(req)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)