Deny the non-public method access

Current storlet_handler can allow to access the handler instance method
via HTTP verb and it may have a risk to be attacked like brute force.

likely:
  curl http://host/v1/a/c/o -X _parse_vaco -H 'X-Run-Storlet: foo'

Fortunately, current handler classes have a few methods inside so that
right now probably we don't have any security risk. However, we should
strict the method anyway via attatching swift.common.utils.public
decorator and the handle_request method should deny the access against
to non public method.

Change-Id: I22672089950f0d90217a352d82dd60eb1238f9c9
This commit is contained in:
Kota Tsuyuzaki
2016-06-13 20:33:33 -07:00
committed by Takashi Kajinami
parent b3e9f4fe7e
commit 02292792b1
2 changed files with 39 additions and 4 deletions

View File

@@ -22,7 +22,7 @@ from swift.common.swob import HTTPException, Response, \
HTTPPreconditionFailed, HTTPRequestedRangeNotSatisfiable, \
HTTPInternalServerError, wsgify
from swift.common.utils import config_true_value, get_logger, is_success, \
register_swift_info
register_swift_info, public
from swift.common.wsgi import make_subrequest
from swift.proxy.controllers.base import get_account_info
from storlet_gateway.common.exceptions import StorletRuntimeException, \
@@ -361,14 +361,20 @@ class StorletProxyHandler(BaseStorletHandler):
def handle_request(self):
if hasattr(self, self.request.method):
resp = getattr(self, self.request.method)()
return resp
try:
handler = getattr(self, self.request.method)
getattr(handler, 'publicly_accessible')
except AttributeError:
# TODO(kota_): add allowed_method list to Allow header
return HTTPMethodNotAllowed(request=self.request)
return handler()
else:
raise HTTPMethodNotAllowed(request=self.request)
def _call_gateway(self, resp):
return self.gateway.gatewayProxyGetFlow(self.request, resp)
@public
def GET(self):
"""
GET handler on Proxy
@@ -469,6 +475,7 @@ class StorletProxyHandler(BaseStorletHandler):
source_resp.headers['last-modified']
return resp
@public
def PUT(self):
"""
PUT handler on Proxy
@@ -489,6 +496,7 @@ class StorletProxyHandler(BaseStorletHandler):
self.gateway.gatewayProxyPutFlow(self.request)
return self.handle_put_copy_response(out_md, app_iter)
@public
def COPY(self):
"""
COPY handler on Proxy
@@ -541,7 +549,13 @@ class StorletObjectHandler(BaseStorletHandler):
def handle_request(self):
if hasattr(self, self.request.method):
return getattr(self, self.request.method)()
try:
handler = getattr(self, self.request.method)
getattr(handler, 'publicly_accessible')
except AttributeError:
# TODO(kota_): add allowed_method list to Allow header
return HTTPMethodNotAllowed(request=self.request)
return handler()
else:
# un-defined method should be NOT ALLOWED
raise HTTPMethodNotAllowed(request=self.request)
@@ -550,6 +564,7 @@ class StorletObjectHandler(BaseStorletHandler):
return self.gateway.gatewayObjectGetFlow(
self.request, resp)
@public
def GET(self):
"""
GET handler on object-server

View File

@@ -497,6 +497,15 @@ class TestStorletMiddlewareProxy(_TestStorletMiddleware):
for key in sheaders:
self.assertEqual(resp_headers[key], sheaders[key])
def test_storlets_with_invalid_method(self):
with storlet_enabled():
req = Request.blank(
'/v1/AUTH_a/c/o', environ={'REQUEST_METHOD': '_parse_vaco'},
headers={'X-Run-Storlet': 'Storlet-1.0.jar'})
app = self.get_app(self.app, self.conf)
app(req.environ, self.start_response)
self.assertEqual('405 Method Not Allowed', self.got_statuses[-1])
class TestStorletMiddlewareObject(_TestStorletMiddleware):
def setUp(self):
@@ -622,6 +631,17 @@ class TestStorletMiddlewareObject(_TestStorletMiddleware):
self.assertEqual('200 OK', self.got_statuses[-1])
self.assertEqual(resp, ['FAKE SEGMENT'])
def test_storlets_with_invalid_method(self):
target = '/sda1/p/AUTH_a/c/o'
req = Request.blank(
target, environ={'REQUEST_METHOD': '_parse_vaco'},
headers={'X-Backend-Storlet-Policy-Index': '0',
'X-Run-Storlet': 'Storlet-1.0.jar'})
app = self.get_app(self.app, self.conf)
app(req.environ, self.start_response)
self.assertEqual('405 Method Not Allowed', self.got_statuses[-1])
class TestStorletBaseHandler(unittest.TestCase):
def test_init_failed_via_base_handler(self):