Stop staticweb revealing container existence to unauth'd requests

When a container has `X-Container-Meta-Web-Listings: false` then
staticweb will return a 404 in response to a GET or HEAD on the
container, regardless of whether the request is auth'd. That provides
a way to probe for container existence. It should return a 401 if the
request is not auth'd.

This patch adds a call to swift.authorize before returning the 404.

Closes-Bug: 1506116
Change-Id: I382323b49dc8f6d67bf4494db7084a860a10db59
This commit is contained in:
Alistair Coles
2015-10-14 15:49:35 +01:00
committed by Alistair Coles
parent 9e53bb47ef
commit 75ab3cb788
2 changed files with 56 additions and 5 deletions

View File

@@ -131,7 +131,8 @@ from swift.common.utils import human_readable, split_path, config_true_value, \
quote, register_swift_info, get_logger
from swift.common.wsgi import make_env, WSGIContext
from swift.common.http import is_success, is_redirection, HTTP_NOT_FOUND
from swift.common.swob import Response, HTTPMovedPermanently, HTTPNotFound
from swift.common.swob import Response, HTTPMovedPermanently, HTTPNotFound, \
Request
from swift.proxy.controllers.base import get_container_info
@@ -196,10 +197,12 @@ class _StaticWebContext(WSGIContext):
self._error, self._listings, self._listings_css and self._dir_type.
:param env: The WSGI environment dict.
:return container_info: The container_info dict.
"""
self._index = self._error = self._listings = self._listings_css = \
self._dir_type = None
container_info = get_container_info(env, self.app, swift_source='SW')
container_info = get_container_info(
env, self.app, swift_source='SW')
if is_success(container_info['status']):
meta = container_info.get('meta', {})
self._index = meta.get('web-index', '').strip()
@@ -208,6 +211,7 @@ class _StaticWebContext(WSGIContext):
self._listings_label = meta.get('web-listings-label', '').strip()
self._listings_css = meta.get('web-listings-css', '').strip()
self._dir_type = meta.get('web-directory-type', '').strip()
return container_info
def _listing(self, env, start_response, prefix=None):
"""
@@ -356,7 +360,15 @@ class _StaticWebContext(WSGIContext):
:param env: The original WSGI environment dict.
:param start_response: The original WSGI start_response hook.
"""
self._get_container_info(env)
container_info = self._get_container_info(env)
req = Request(env)
req.acl = container_info['read_acl']
# we checked earlier that swift.authorize is set in env
aresp = env['swift.authorize'](req)
if aresp:
resp = aresp(env, self._start_response)
return self._error_response(resp, env, start_response)
if not self._listings and not self._index:
if config_true_value(env.get('HTTP_X_WEB_MODE', 'f')):
return HTTPNotFound()(env, start_response)

View File

@@ -41,7 +41,8 @@ meta_map = {
'web-error': 'error.html'}},
'c6b': {'meta': {'web-listings': 't',
'web-listings-label': 'foo'}},
'c7': {'meta': {'web-listings': 'f'}},
'c7': {'meta': {'web-listings': 'f',
'web-error': 'error.html'}},
'c8': {'meta': {'web-error': 'error.html',
'web-listings': 't',
'web-listings-css':
@@ -202,6 +203,16 @@ class FakeApp(object):
'''.strip())(env, start_response)
elif env['PATH_INFO'] in ('/v1/a/c7', '/v1/a/c7/'):
return self.listing(env, start_response)
elif env['PATH_INFO'] == '/v1/a/c7/404error.html':
return Response(status='404 Not Found')(env, start_response)
elif env['PATH_INFO'] == '/v1/a/c7/401error.html':
return Response(status='200 Ok', body='''
<html>
<body style="background: #000000; color: #ffaaaa">
<p>Hey, you're not authorized to see this!</p>
</body>
</html>
'''.strip())(env, start_response)
elif env['PATH_INFO'] in ('/v1/a/c8', '/v1/a/c8/'):
return self.listing(env, start_response)
elif env['PATH_INFO'] == '/v1/a/c8/subdir/':
@@ -663,9 +674,37 @@ class TestStaticWeb(unittest.TestCase):
self.assertIn(label, resp.body)
def test_container7listing(self):
# container7 has web-listings = f, web-error=error.html
resp = Request.blank('/v1/a/c7/').get_response(self.test_staticweb)
self.assertEqual(resp.status_int, 404)
self.assertTrue('Web Listing Disabled' in resp.body)
self.assertIn("Web Listing Disabled", resp.body)
# expect 301 if auth'd but no trailing '/'
resp = Request.blank('/v1/a/c7').get_response(self.test_staticweb)
self.assertEqual(resp.status_int, 301)
# expect default 401 if request is not auth'd and no trailing '/'
test_staticweb = FakeAuthFilter(
staticweb.filter_factory({})(self.app), deny_listing=True,
deny_objects=True)
resp = Request.blank('/v1/a/c7').get_response(test_staticweb)
self.assertEqual(resp.status_int, 401)
self.assertNotIn("Hey, you're not authorized to see this!", resp.body)
# expect custom 401 if request is not auth'd for listing
test_staticweb = FakeAuthFilter(
staticweb.filter_factory({})(self.app), deny_listing=True)
resp = Request.blank('/v1/a/c7/').get_response(test_staticweb)
self.assertEqual(resp.status_int, 401)
self.assertIn("Hey, you're not authorized to see this!", resp.body)
# expect default 401 if request is not auth'd for listing or object GET
test_staticweb = FakeAuthFilter(
staticweb.filter_factory({})(self.app), deny_listing=True,
deny_objects=True)
resp = Request.blank('/v1/a/c7/').get_response(test_staticweb)
self.assertEqual(resp.status_int, 401)
self.assertNotIn("Hey, you're not authorized to see this!", resp.body)
def test_container8listingcss(self):
resp = Request.blank(