Permalink
Browse files

Merge "Update middleware to use common pre_authed funcs"

  • Loading branch information...
2 parents d46411d + 0ec5eef commit a9b6355d15bac1d0916c8481d3ef58fb3ed3bb75 Jenkins committed with openstack-gerrit Mar 30, 2012
@@ -111,6 +111,7 @@
from urllib import quote, unquote
from swift.common.utils import get_logger, streq_const_time
+from swift.common.wsgi import make_pre_authed_env
#: The size of data to read from the form at any given time.
@@ -296,6 +297,8 @@ def __init__(self, app, conf):
self.conf = conf
#: The logger to use with this middleware.
self.logger = get_logger(conf, log_route='formpost')
+ #: The HTTP user agent to use with subrequests.
+ self.agent = '%(orig)s FormPost'
def __call__(self, env, start_response):
"""
@@ -413,22 +416,18 @@ def _perform_subrequest(self, env, start_response, attributes, fp, key):
max_file_size = int(attributes.get('max_file_size') or 0)
except ValueError:
raise FormInvalid('max_file_size not an integer')
- subenv = {'REQUEST_METHOD': 'PUT',
- 'SCRIPT_NAME': '',
- 'SERVER_NAME': env['SERVER_NAME'],
- 'SERVER_PORT': env['SERVER_PORT'],
- 'SERVER_PROTOCOL': env['SERVER_PROTOCOL'],
- 'HTTP_TRANSFER_ENCODING': 'chunked',
- 'wsgi.input': _CappedFileLikeObject(fp, max_file_size),
- 'swift.cache': env['swift.cache']}
- subenv['PATH_INFO'] = env['PATH_INFO']
+ subenv = make_pre_authed_env(env, 'PUT', agent=self.agent)
+ subenv['HTTP_TRANSFER_ENCODING'] = 'chunked'
+ subenv['wsgi.input'] = _CappedFileLikeObject(fp, max_file_size)
if subenv['PATH_INFO'][-1] != '/' and \
subenv['PATH_INFO'].count('/') < 4:
subenv['PATH_INFO'] += '/'
subenv['PATH_INFO'] += attributes['filename'] or 'filename'
if 'content-type' in attributes:
subenv['CONTENT_TYPE'] = \
attributes['content-type'] or 'application/octet-stream'
+ elif 'CONTENT_TYPE' in subenv:
+ del subenv['CONTENT_TYPE']
try:
if int(attributes.get('expires') or 0) < time():
return '401 Unauthorized', 'form expired'
@@ -445,15 +444,16 @@ def _perform_subrequest(self, env, start_response, attributes, fp, key):
if not streq_const_time(sig, (attributes.get('signature') or
'invalid')):
return '401 Unauthorized', 'invalid signature'
- subenv['swift.authorize'] = lambda req: None
- subenv['swift.authorize_override'] = True
- subenv['REMOTE_USER'] = '.wsgi.formpost'
substatus = [None]
def _start_response(status, headers, exc_info=None):
substatus[0] = status
- self.app(subenv, _start_response)
+ i = iter(self.app(subenv, _start_response))
+ try:
+ i.next()
+ except StopIteration:
+ pass
return substatus[0], ''
def _get_key(self, env):
@@ -474,27 +474,22 @@ def _get_key(self, env):
if memcache:
key = memcache.get('temp-url-key/%s' % account)
if not key:
- newenv = {'REQUEST_METHOD': 'HEAD', 'SCRIPT_NAME': '',
- 'PATH_INFO': '/v1/' + account, 'CONTENT_LENGTH': '0',
- 'SERVER_PROTOCOL': 'HTTP/1.0',
- 'HTTP_USER_AGENT': 'FormPost', 'wsgi.version': (1, 0),
- 'wsgi.url_scheme': 'http', 'wsgi.input': StringIO('')}
- for name in ('SERVER_NAME', 'SERVER_PORT', 'wsgi.errors',
- 'wsgi.multithread', 'wsgi.multiprocess',
- 'wsgi.run_once', 'swift.cache', 'swift.trans_id'):
- if name in env:
- newenv[name] = env[name]
- newenv['swift.authorize'] = lambda req: None
- newenv['swift.authorize_override'] = True
- newenv['REMOTE_USER'] = '.wsgi.formpost'
+ newenv = make_pre_authed_env(env, 'HEAD', '/v1/' + account,
+ self.agent)
+ newenv['CONTENT_LENGTH'] = '0'
+ newenv['wsgi.input'] = StringIO('')
key = [None]
def _start_response(status, response_headers, exc_info=None):
for h, v in response_headers:
if h.lower() == 'x-account-meta-temp-url-key':
key[0] = v
- self.app(newenv, _start_response)
+ i = iter(self.app(newenv, _start_response))
+ try:
+ i.next()
+ except StopIteration:
+ pass
key = key[0]
if key and memcache:
memcache.set('temp-url-key/%s' % account, key, timeout=60)
@@ -123,7 +123,8 @@
from swift.common.utils import cache_from_env, get_logger, human_readable, \
split_path, TRUE_VALUES
-from swift.common.wsgi import WSGIContext
+from swift.common.wsgi import make_pre_authed_env, make_pre_authed_request, \
+ WSGIContext
def quote(value, safe='/'):
@@ -157,6 +158,7 @@ def __init__(self, staticweb, version, account, container, obj):
self.logger = staticweb.logger
self.access_logger = staticweb.access_logger
self.log_headers = staticweb.log_headers
+ self.agent = '%(orig)s StaticWeb'
# Results from the last call to self._get_container_info.
self._index = self._error = self._listings = self._listings_css = None
@@ -177,11 +179,10 @@ def _error_response(self, response, env, start_response):
save_response_status = self._response_status
save_response_headers = self._response_headers
save_response_exc_info = self._response_exc_info
- tmp_env = self._get_escalated_env(env)
- tmp_env['REQUEST_METHOD'] = 'GET'
- tmp_env['PATH_INFO'] = '/%s/%s/%s/%s%s' % (self.version, self.account,
- self.container, self._get_status_int(), self._error)
- resp = self._app_call(tmp_env)
+ resp = self._app_call(make_pre_authed_env(env, 'GET',
+ '/%s/%s/%s/%s%s' % (self.version, self.account, self.container,
+ self._get_status_int(), self._error),
+ self.agent))
if self._get_status_int() // 100 == 2:
start_response(save_response_status, self._response_headers,
self._response_exc_info)
@@ -190,21 +191,6 @@ def _error_response(self, response, env, start_response):
save_response_exc_info)
return response
- def _get_escalated_env(self, env):
- """
- Returns a new fresh WSGI environment with escalated privileges to do
- backend checks, listings, etc. that the remote user wouldn't be able to
- accomplish directly.
- """
- new_env = {'REQUEST_METHOD': 'GET',
- 'HTTP_USER_AGENT': '%s StaticWeb' % env.get('HTTP_USER_AGENT')}
- for name in ('eventlet.posthooks', 'swift.trans_id', 'REMOTE_USER',
- 'SCRIPT_NAME', 'SERVER_NAME', 'SERVER_PORT',
- 'SERVER_PROTOCOL', 'swift.cache'):
- if name in env:
- new_env[name] = env[name]
- return new_env
-
def _get_container_info(self, env):
"""
Retrieves x-container-meta-web-index, x-container-meta-web-error,
@@ -224,11 +210,9 @@ def _get_container_info(self, env):
(self._index, self._error, self._listings,
self._listings_css) = cached_data
return
- tmp_env = self._get_escalated_env(env)
- tmp_env['REQUEST_METHOD'] = 'HEAD'
- req = Request.blank('/%s/%s/%s' % (self.version, self.account,
- self.container), environ=tmp_env)
- resp = req.get_response(self.app)
+ resp = make_pre_authed_request(env, 'HEAD',
+ '/%s/%s/%s' % (self.version, self.account, self.container),
+ agent=self.agent).get_response(self.app)
if resp.status_int // 100 == 2:
self._index = \
resp.headers.get('x-container-meta-web-index', '').strip()
@@ -256,10 +240,9 @@ def _listing(self, env, start_response, prefix=None):
if self._listings.lower() not in TRUE_VALUES:
resp = HTTPNotFound()(env, self._start_response)
return self._error_response(resp, env, start_response)
- tmp_env = self._get_escalated_env(env)
- tmp_env['REQUEST_METHOD'] = 'GET'
- tmp_env['PATH_INFO'] = \
- '/%s/%s/%s' % (self.version, self.account, self.container)
+ tmp_env = make_pre_authed_env(env, 'GET',
+ '/%s/%s/%s' % (self.version, self.account, self.container),
+ self.agent)
tmp_env['QUERY_STRING'] = 'delimiter=/&format=json'
if prefix:
tmp_env['QUERY_STRING'] += '&prefix=%s' % quote(prefix)
@@ -431,10 +414,10 @@ def handle_object(self, env, start_response):
return resp
if status_int == 404:
if env['PATH_INFO'][-1] != '/':
- tmp_env = self._get_escalated_env(env)
- tmp_env['REQUEST_METHOD'] = 'GET'
- tmp_env['PATH_INFO'] = '/%s/%s/%s' % (self.version,
- self.account, self.container)
+ tmp_env = make_pre_authed_env(env, 'GET',
+ '/%s/%s/%s' % (self.version, self.account,
+ self.container),
+ self.agent)
tmp_env['QUERY_STRING'] = 'limit=1&format=json&delimiter' \
'=/&limit=1&prefix=%s' % quote(self.obj + '/')
resp = self._app_call(tmp_env)
@@ -87,6 +87,7 @@
from urlparse import parse_qs
from swift.common.utils import get_logger
+from swift.common.wsgi import make_pre_authed_env
#: Default headers to remove from incoming requests. Simply a whitespace
@@ -211,6 +212,8 @@ def __init__(self, app, conf):
#: Lowercase, like `x-matches-remove-prefix-but-okay-*`.
self.outgoing_allow_headers_startswith = \
[h[:-1] for h in headers if h[-1] == '*']
+ #: HTTP user agent to use for subrequests.
+ self.agent = '%(orig)s TempURL'
def __call__(self, env, start_response):
"""
@@ -321,27 +324,22 @@ def _get_key(self, env, account):
if memcache:
key = memcache.get('temp-url-key/%s' % account)
if not key:
- newenv = {'REQUEST_METHOD': 'HEAD', 'SCRIPT_NAME': '',
- 'PATH_INFO': '/v1/' + account, 'CONTENT_LENGTH': '0',
- 'SERVER_PROTOCOL': 'HTTP/1.0',
- 'HTTP_USER_AGENT': 'TempURL', 'wsgi.version': (1, 0),
- 'wsgi.url_scheme': 'http', 'wsgi.input': StringIO('')}
- for name in ('SERVER_NAME', 'SERVER_PORT', 'wsgi.errors',
- 'wsgi.multithread', 'wsgi.multiprocess',
- 'wsgi.run_once', 'swift.cache', 'swift.trans_id'):
- if name in env:
- newenv[name] = env[name]
- newenv['swift.authorize'] = lambda req: None
- newenv['swift.authorize_override'] = True
- newenv['REMOTE_USER'] = '.wsgi.tempurl'
+ newenv = make_pre_authed_env(env, 'HEAD', '/v1/' + account,
+ self.agent)
+ newenv['CONTENT_LENGTH'] = '0'
+ newenv['wsgi.input'] = StringIO('')
key = [None]
def _start_response(status, response_headers, exc_info=None):
for h, v in response_headers:
if h.lower() == 'x-account-meta-temp-url-key':
key[0] = v
- self.app(newenv, _start_response)
+ i = iter(self.app(newenv, _start_response))
+ try:
+ i.next()
+ except StopIteration:
+ pass
key = key[0]
if key and memcache:
memcache.set('temp-url-key/%s' % account, key, timeout=60)
View
@@ -224,12 +224,12 @@ def _app_call(self, env):
Ensures start_response has been called before returning.
"""
resp = iter(self.app(env, self._start_response))
- first_chunk = []
try:
- first_chunk.append(resp.next())
+ first_chunk = resp.next()
except StopIteration:
- pass
- return chain(first_chunk, resp)
+ return iter([])
+ else: # We got a first_chunk
+ return chain([first_chunk], resp)
def _get_status_int(self):
"""
@@ -246,31 +246,74 @@ def _response_header_value(self, key):
return None
-def make_pre_authed_request(env, method, path, body=None, headers=None,
- agent='Swift'):
+def make_pre_authed_request(env, method=None, path=None, body=None,
+ headers=None, agent='Swift'):
"""
Makes a new webob.Request based on the current env but with the
parameters specified. Note that this request will be preauthorized.
- :param env: Current WSGI environment dictionary
- :param method: HTTP method of new request
- :param path: HTTP path of new request
- :param body: HTTP body of new request; None by default
- :param headers: Extra HTTP headers of new request; None by default
-
- :returns: webob.Request object
-
- (Stolen from Swauth: https://github.com/gholt/swauth)
+ :param env: The WSGI environment to base the new request on.
+ :param method: HTTP method of new request; default is from
+ the original env.
+ :param path: HTTP path of new request; default is from the
+ original env.
+ :param body: HTTP body of new request; empty by default.
+ :param headers: Extra HTTP headers of new request; None by
+ default.
+ :param agent: The HTTP user agent to use; default 'Swift'. You
+ can put %(orig)s in the agent to have it replaced
+ with the original env's HTTP_USER_AGENT, such as
+ '%(orig)s StaticWeb'. You also set agent to None to
+ use the original env's HTTP_USER_AGENT or '' to
+ have no HTTP_USER_AGENT.
+ :returns: Fresh webob.Request object.
"""
- newenv = {'REQUEST_METHOD': method, 'HTTP_USER_AGENT': agent}
- for name in ('swift.cache', 'swift.trans_id'):
- if name in env:
- newenv[name] = env[name]
- newenv['swift.authorize'] = lambda req: None
+ newenv = make_pre_authed_env(env, method, path, agent)
if not headers:
headers = {}
if body:
return Request.blank(path, environ=newenv, body=body,
headers=headers)
else:
return Request.blank(path, environ=newenv, headers=headers)
+
+
+def make_pre_authed_env(env, method=None, path=None, agent='Swift'):
+ """
+ Returns a new fresh WSGI environment with escalated privileges to
+ do backend checks, listings, etc. that the remote user wouldn't
+ be able to accomplish directly.
+
+ :param env: The WSGI environment to base the new environment on.
+ :param method: The new REQUEST_METHOD or None to use the
+ original.
+ :param path: The new PATH_INFO or None to use the original.
+ :param agent: The HTTP user agent to use; default 'Swift'. You
+ can put %(orig)s in the agent to have it replaced
+ with the original env's HTTP_USER_AGENT, such as
+ '%(orig)s StaticWeb'. You also set agent to None to
+ use the original env's HTTP_USER_AGENT or '' to
+ have no HTTP_USER_AGENT.
+ :returns: Fresh WSGI environment.
+ """
+ newenv = {}
+ for name in ('eventlet.posthooks', 'HTTP_USER_AGENT',
+ 'PATH_INFO', 'REMOTE_USER', 'REQUEST_METHOD',
+ 'SCRIPT_NAME', 'SERVER_NAME', 'SERVER_PORT',
+ 'SERVER_PROTOCOL', 'swift.cache', 'swift.source',
+ 'swift.trans_id'):
+ if name in env:
+ newenv[name] = env[name]
+ if method:
+ newenv['REQUEST_METHOD'] = method
+ if path:
+ newenv['PATH_INFO'] = path
+ if agent:
+ newenv['HTTP_USER_AGENT'] = (
+ agent % {'orig': env.get('HTTP_USER_AGENT', '')}).strip()
+ elif agent == '' and 'HTTP_USER_AGENT' in newenv:
+ del newenv['HTTP_USER_AGENT']
+ newenv['swift.authorize'] = lambda req: None
+ newenv['swift.authorize_override'] = True
+ newenv['REMOTE_USER'] = '.wsgi.pre_authed'
+ return newenv
@@ -74,7 +74,7 @@ def __call__(self, env, start_response):
env['wsgi.input'] = StringIO(body)
self.requests.append(Request.blank('', environ=env))
if env.get('swift.authorize_override') and \
- env.get('REMOTE_USER') != '.wsgi.formpost':
+ env.get('REMOTE_USER') != '.wsgi.pre_authed':
raise Exception('Invalid REMOTE_USER %r with '
'swift.authorize_override' % (env.get('REMOTE_USER'),))
if 'swift.authorize' in env:

0 comments on commit a9b6355

Please sign in to comment.