Merge "s3api: Fix handling of non-ascii access keys"

This commit is contained in:
Zuul 2024-03-25 21:40:58 +00:00 committed by Gerrit Code Review
commit 0e5aeb5045
6 changed files with 50 additions and 10 deletions

View File

@ -1142,7 +1142,7 @@ class S3Request(swob.Request):
Create a Swift request based on this request's environment.
"""
if self.account is None:
account = self.access_key
account = swob.str_to_wsgi(self.access_key)
else:
account = self.account

View File

@ -65,7 +65,7 @@ import six
from six.moves import urllib
from swift.common.swob import Request, HTTPBadRequest, HTTPUnauthorized, \
HTTPException
HTTPException, str_to_wsgi
from swift.common.utils import config_true_value, split_path, get_logger, \
cache_from_env, append_underscore
from swift.common.wsgi import ConfigFileError
@ -404,7 +404,7 @@ class S3Token(object):
self._logger.debug('Connecting with tenant: %s', tenant_to_connect)
new_tenant_name = '%s%s' % (self._reseller_prefix, tenant_to_connect)
environ['PATH_INFO'] = environ['PATH_INFO'].replace(
account, new_tenant_name, 1)
str_to_wsgi(account), str_to_wsgi(new_tenant_name), 1)
return self._app(environ, start_response)

View File

@ -184,9 +184,11 @@ import base64
from eventlet import Timeout
import six
from swift.common.memcached import MemcacheConnectionError
from swift.common.swob import Response, Request, wsgi_to_str
from swift.common.swob import HTTPBadRequest, HTTPForbidden, HTTPNotFound, \
HTTPUnauthorized, HTTPMethodNotAllowed, HTTPServiceUnavailable
from swift.common.swob import (
Response, Request, wsgi_to_str, str_to_wsgi, wsgi_unquote,
HTTPBadRequest, HTTPForbidden, HTTPNotFound,
HTTPUnauthorized, HTTPMethodNotAllowed, HTTPServiceUnavailable,
)
from swift.common.request_helpers import get_sys_meta_prefix
from swift.common.middleware.acl import (
@ -469,7 +471,7 @@ class TempAuth(object):
if not s3_auth_details['check_signature'](user['key']):
return None
env['PATH_INFO'] = env['PATH_INFO'].replace(
account_user, account_id, 1)
str_to_wsgi(account_user), wsgi_unquote(account_id), 1)
groups = self._get_user_groups(account, account_user, account_id)
return groups

View File

@ -46,10 +46,12 @@ class FakeAuthApp(object):
E.g. '/v1/test:tester/bucket/object' will become
'/v1/AUTH_test/bucket/object'. This method emulates the behavior.
"""
tenant_user = env['s3api.auth_details']['access_key']
tenant_user = swob.str_to_wsgi(env['s3api.auth_details']['access_key'])
tenant, user = tenant_user.rsplit(':', 1)
path = env['PATH_INFO']
# Make sure it's valid WSGI
swob.wsgi_to_str(path)
env['PATH_INFO'] = path.replace(tenant_user, 'AUTH_' + tenant)
@staticmethod

View File

@ -199,7 +199,8 @@ class S3TokenMiddlewareTestGood(S3TokenMiddlewareTestBase):
self.middleware(req.environ, self.start_fake_response)
self.assertEqual(self.response_status, 200)
def _assert_authorized(self, req, account_path='/v1/AUTH_TENANT_ID/'):
def _assert_authorized(self, req, account_path='/v1/AUTH_TENANT_ID/',
access_key='access'):
self.assertTrue(
req.path.startswith(account_path),
'%r does not start with %r' % (req.path, account_path))
@ -224,7 +225,7 @@ class S3TokenMiddlewareTestGood(S3TokenMiddlewareTestBase):
self.assertEqual(1, self.requests_mock.call_count)
request_call = self.requests_mock.request_history[0]
self.assertEqual(json.loads(request_call.body), {'credentials': {
'access': 'access',
'access': access_key,
'signature': 'signature',
'token': base64.urlsafe_b64encode(b'token').decode('ascii')}})
@ -501,6 +502,18 @@ class S3TokenMiddlewareTestGood(S3TokenMiddlewareTestBase):
self._assert_authorized(req, account_path='/v1/')
self.assertEqual(req.environ['PATH_INFO'], '/v1/AUTH_TENANT_ID/c/o')
def test_authorize_with_unicode_access_key(self):
req = Request.blank('/v1/acc\xc3\xa9sskey/c/o')
req.environ['s3api.auth_details'] = {
'access_key': u'acc\u00e9ss',
'signature': u'signature',
'string_to_sign': u'token',
}
req.get_response(self.middleware)
self._assert_authorized(req, account_path='/v1/',
access_key=u'acc\u00e9ss')
self.assertEqual(req.environ['PATH_INFO'], '/v1/AUTH_TENANT_ID/c/o')
def test_authorize_with_access_key_and_unquote_chars(self):
req = Request.blank('/v1/access%key=/c/o')
req.environ['s3api.auth_details'] = {

View File

@ -308,6 +308,29 @@ class TestAuth(unittest.TestCase):
self.assertEqual(req.environ['swift.authorize'],
local_auth.authorize)
def test_auth_with_s3api_unicode_authorization_good(self):
local_app = FakeApp()
conf = {u'user_t\u00e9st_t\u00e9ster': u'p\u00e1ss .admin'}
access_key = u't\u00e9st:t\u00e9ster'
if six.PY2:
conf = {k.encode('utf8'): v.encode('utf8')
for k, v in conf.items()}
access_key = access_key.encode('utf8')
local_auth = auth.filter_factory(conf)(local_app)
req = self._make_request('/v1/t\xc3\xa9st:t\xc3\xa9ster', environ={
's3api.auth_details': {
'access_key': access_key,
'signature': b64encode('sig'),
'string_to_sign': 't',
'check_signature': lambda secret: True}})
resp = req.get_response(local_auth)
self.assertEqual(resp.status_int, 404)
self.assertEqual(local_app.calls, 1)
self.assertEqual(req.environ['PATH_INFO'], '/v1/AUTH_t\xc3\xa9st')
self.assertEqual(req.environ['swift.authorize'],
local_auth.authorize)
def test_auth_with_swift3_authorization_invalid(self):
local_app = FakeApp()
local_auth = auth.filter_factory(