Add sort key validation in v2 api

Since v2 api has no sort key validation and the default
pagination check is used it's possible to request something
like /images?sort_key=_sa_class_manager, which causes an
inner SQL exception with 500 response code from the server.

This code validates input sort key and raises an exception
if the parameter is out of the supported keys list.

Closes-bug: 1400366

Change-Id: I0cf58ad198375a2f6f58bd7820cbb9d86003247a
This commit is contained in:
Mike Fedosin 2014-12-08 16:22:05 +03:00
parent 12f12fb82e
commit f9820a25d3
2 changed files with 33 additions and 8 deletions

View File

@ -298,16 +298,20 @@ class ImagesController(object):
class RequestDeserializer(wsgi.JSONRequestDeserializer):
_disallowed_properties = ['direct_url', 'self', 'file', 'schema']
_readonly_properties = ['created_at', 'updated_at', 'status', 'checksum',
_disallowed_properties = ('direct_url', 'self', 'file', 'schema')
_readonly_properties = ('created_at', 'updated_at', 'status', 'checksum',
'size', 'virtual_size', 'direct_url', 'self',
'file', 'schema']
_reserved_properties = ['owner', 'is_public', 'location', 'deleted',
'deleted_at']
_base_properties = ['checksum', 'created_at', 'container_format',
'file', 'schema')
_reserved_properties = ('owner', 'is_public', 'location', 'deleted',
'deleted_at')
_base_properties = ('checksum', 'created_at', 'container_format',
'disk_format', 'id', 'min_disk', 'min_ram', 'name',
'size', 'virtual_size', 'status', 'tags',
'updated_at', 'visibility', 'protected']
'updated_at', 'visibility', 'protected')
_available_sort_keys = ('name', 'status', 'container_format',
'disk_format', 'size', 'id', 'created_at',
'updated_at')
_path_depth_limits = {'locations': {'add': 2, 'remove': 2, 'replace': 1}}
def __init__(self, schema=None):
@ -535,6 +539,16 @@ class RequestDeserializer(wsgi.JSONRequestDeserializer):
return limit
def _validate_sort_key(self, sort_key):
if sort_key not in self._available_sort_keys:
msg = _('Invalid sort key: %(sort_key)s. '
'It must be one of the following: %(available)s.') % \
{'sort_key': sort_key,
'available': ', '.join(self._available_sort_keys)}
raise webob.exc.HTTPBadRequest(explanation=msg)
return sort_key
def _validate_sort_dir(self, sort_dir):
if sort_dir not in ['asc', 'desc']:
msg = _('Invalid sort direction: %s') % sort_dir
@ -577,7 +591,8 @@ class RequestDeserializer(wsgi.JSONRequestDeserializer):
tags.append(params.pop('tag').strip())
query_params = {
'sort_key': params.pop('sort_key', 'created_at'),
'sort_key': self._validate_sort_key(
params.pop('sort_key', 'created_at')),
'sort_dir': self._validate_sort_dir(sort_dir),
'filters': self._get_filters(params),
'member_status': self._validate_member_status(member_status),

View File

@ -2542,6 +2542,16 @@ class TestImagesDeserializer(test_utils.BaseTestCase):
'filters': {}}
self.assertEqual(expected, output)
def test_index_sort_private_key(self):
request = unit_test_utils.get_fake_request('/images?sort_key=min_ram')
self.assertRaises(webob.exc.HTTPBadRequest,
self.deserializer.index, request)
def test_index_sort_key_bad_value(self):
request = unit_test_utils.get_fake_request('/images?sort_key=blah')
self.assertRaises(webob.exc.HTTPBadRequest,
self.deserializer.index, request)
def test_index_sort_dir_bad_value(self):
request = unit_test_utils.get_fake_request('/images?sort_dir=blah')
self.assertRaises(webob.exc.HTTPBadRequest,