Fix api exception with unicode tenant name.
There are a lot request debug logging in Trove, when some values of headers are encoded in utf8, UnicodeEncodeError will be raised by webob.Request. Override how webob.Request is represented will fix. Closes-Bug: #1720121 Change-Id: I91683b8dd24262b0f643e8d2bc7886a7c03be40a Signed-off-by: Zhao Chao <zhaochao1984@gmail.com>
This commit is contained in:
		| @@ -21,6 +21,7 @@ import webob.exc | ||||
|  | ||||
| from trove.common import exception | ||||
| from trove.common.i18n import _ | ||||
| from trove.common.utils import req_to_text | ||||
| from trove.common import wsgi | ||||
|  | ||||
| LOG = logging.getLogger(__name__) | ||||
| @@ -64,7 +65,8 @@ class TenantBasedAuth(object): | ||||
|             LOG.debug(strutils.mask_password( | ||||
|                       _("Authorized tenant '%(tenant_id)s' request: " | ||||
|                         "%(request)s") % | ||||
|                       {'tenant_id': tenant_id, 'request': request})) | ||||
|                       {'tenant_id': tenant_id, | ||||
|                        'request': req_to_text(request)})) | ||||
|             return True | ||||
|  | ||||
|         msg = _( | ||||
|   | ||||
| @@ -41,6 +41,7 @@ from xml.parsers import expat | ||||
|  | ||||
| from trove.common import base_exception | ||||
| from trove.common.i18n import _ | ||||
| from trove.common.utils import req_to_text | ||||
| from trove.common import xmlutils | ||||
|  | ||||
| socket_opts = [ | ||||
| @@ -332,6 +333,8 @@ class Request(webob.Request): | ||||
|             raise base_exception.InvalidContentType(content_type=content_type) | ||||
|         return content_type | ||||
|  | ||||
|     __str__ = req_to_text | ||||
|  | ||||
|  | ||||
| class Resource(object): | ||||
|     """ | ||||
|   | ||||
| @@ -26,6 +26,7 @@ import jinja2 | ||||
| from oslo_concurrency import processutils | ||||
| from oslo_log import log as logging | ||||
| from oslo_service import loopingcall | ||||
| from oslo_utils.encodeutils import safe_encode | ||||
| from oslo_utils import importutils | ||||
| from oslo_utils import strutils | ||||
| from passlib import pwd | ||||
| @@ -383,3 +384,28 @@ def to_mb(bytes): | ||||
|     size = bytes / 1024.0 ** 2 | ||||
|     # Make sure we don't return 0.0 if the size is greater than 0 | ||||
|     return max(round(size, 2), 0.01) | ||||
|  | ||||
|  | ||||
| def req_to_text(req): | ||||
|     """ | ||||
|     We do a lot request logging for debug, but if the value of one | ||||
|     requst header is encoded in utf-8, an UnicodeEncodeError will | ||||
|     be raised. So we should carefully encode request headers. | ||||
|  | ||||
|     To be consitent with webob, main procedures are copied from | ||||
|     webob.Request.as_bytes. | ||||
|     """ | ||||
|     url = req.url | ||||
|     host = req.host_url | ||||
|     assert url.startswith(host) | ||||
|     url = url[len(host):] | ||||
|     parts = [safe_encode('%s %s %s' % (req.method, url, req.http_version))] | ||||
|  | ||||
|     for k, v in sorted(req.headers.items()): | ||||
|         header = safe_encode('%s: %s' % (k, v)) | ||||
|         parts.append(header) | ||||
|  | ||||
|     if req.body: | ||||
|         parts.extend([b'', safe_encode(req.body)]) | ||||
|  | ||||
|     return b'\r\n'.join(parts).decode(req.charset) | ||||
|   | ||||
							
								
								
									
										35
									
								
								trove/tests/unittests/common/test_auth.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								trove/tests/unittests/common/test_auth.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| #    Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||
| #    not use this file except in compliance with the License. You may obtain | ||||
| #    a copy of the License at | ||||
| # | ||||
| #         http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| #    Unless required by applicable law or agreed to in writing, software | ||||
| #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| #    License for the specific language governing permissions and limitations | ||||
| #    under the License. | ||||
|  | ||||
| import webob | ||||
|  | ||||
| from trove.common import auth | ||||
| from trove.tests.unittests import trove_testtools | ||||
|  | ||||
|  | ||||
| class TestAuth(trove_testtools.TestCase): | ||||
|     def test_unicode_characters_in_headers(self): | ||||
|         middleware = auth.AuthorizationMiddleware( | ||||
|             "test_trove", | ||||
|             [auth.TenantBasedAuth()]) | ||||
|         tenant_id = 'test_tenant_id' | ||||
|         url = '/%s/instances' % tenant_id | ||||
|         req = webob.Request.blank(url) | ||||
|  | ||||
|         # test string with chinese characters | ||||
|         test_str = u'\u6d4b\u8bd5' | ||||
|         req.headers = { | ||||
|             'X-Tenant-ID': tenant_id, | ||||
|             'X-Auth-Project-Id': test_str | ||||
|         } | ||||
|         # invocation | ||||
|         middleware.process_request(req) | ||||
| @@ -22,6 +22,7 @@ from trove.common import exception | ||||
| from trove.common import utils | ||||
| from trove.tests.unittests import trove_testtools | ||||
| from trove.tests.util import utils as test_utils | ||||
| import webob | ||||
|  | ||||
|  | ||||
| class TestUtils(trove_testtools.TestCase): | ||||
| @@ -173,3 +174,15 @@ class TestUtils(trove_testtools.TestCase): | ||||
|         assert_retry(te.test_foo_2, TestEx3, 1, TestEx3) | ||||
|         assert_retry(te.test_foo_2, TestEx2, 3, TestEx2) | ||||
|         assert_retry(te.test_foo_2, [TestEx1, TestEx3, TestEx2], 2, TestEx3) | ||||
|  | ||||
|     def test_req_to_text(self): | ||||
|         req = webob.Request.blank('/') | ||||
|         expected = u'GET / HTTP/1.0\r\nHost: localhost:80' | ||||
|         self.assertEqual(expected, utils.req_to_text(req)) | ||||
|  | ||||
|         # add a header containing unicode characters | ||||
|         req.headers.update({ | ||||
|             'X-Auth-Project-Id': u'\u6d4b\u8bd5'}) | ||||
|         expected = (u'GET / HTTP/1.0\r\nHost: localhost:80\r\n' | ||||
|                     u'X-Auth-Project-Id: \u6d4b\u8bd5') | ||||
|         self.assertEqual(expected, utils.req_to_text(req)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Zhao Chao
					Zhao Chao