From 6e10f1b4c90e444c8978e4b3cfe650dc0fc810fc Mon Sep 17 00:00:00 2001 From: bhagyashris Date: Thu, 24 Mar 2016 10:01:59 +0000 Subject: [PATCH] Return BadRequest for 4 byte unicode characters Various create and update apis are returning 500 error when you pass 4 byte unicode characters in the request. This patch fixes the issue to return HTTP 400 Bad Request. 1. md-namespace-create 2. md-namespace-update 3. md-property-create 4. md-property-update 5. md-object-create 6. md-object-update 7. md-tag-create 8. md-tag-update APIImpact: For all of the above APIs, it will return 400 error instead of 500 if user passes 4 byte unicode characters in the request. Closes-Bug: #1570789 Change-Id: I8233cf95310aa2671ebc62995c58208024fc38a3 --- glance/api/v2/metadef_namespaces.py | 9 +- glance/api/v2/metadef_objects.py | 8 ++ glance/api/v2/metadef_properties.py | 8 ++ glance/api/v2/metadef_tags.py | 8 ++ glance/db/simple/api.py | 8 ++ glance/db/sqlalchemy/api.py | 8 ++ .../tests/unit/v2/test_metadef_resources.py | 84 +++++++++++++++++++ 7 files changed, 132 insertions(+), 1 deletion(-) diff --git a/glance/api/v2/metadef_namespaces.py b/glance/api/v2/metadef_namespaces.py index a8444e7587..7820f6c740 100644 --- a/glance/api/v2/metadef_namespaces.py +++ b/glance/api/v2/metadef_namespaces.py @@ -162,7 +162,10 @@ class NamespaceController(object): **self._to_property_dict(name, value) )) prop_repo.add(new_property_type) - + except exception.Invalid as e: + msg = (_("Couldn't create metadata namespace: %s") + % encodeutils.exception_to_unicode(e)) + raise webob.exc.HTTPBadRequest(explanation=msg) except exception.Forbidden as e: self._cleanup_namespace(ns_repo, namespace, namespace_created) LOG.debug("User not permitted to create metadata namespace") @@ -285,6 +288,10 @@ class NamespaceController(object): ns_obj.owner = ( wsme_utils._get_value(user_ns.owner) or req.context.owner) updated_namespace = namespace_repo.save(ns_obj) + except exception.Invalid as e: + msg = (_("Couldn't update metadata namespace: %s") + % encodeutils.exception_to_unicode(e)) + raise webob.exc.HTTPBadRequest(explanation=msg) except exception.Forbidden as e: LOG.debug("User not permitted to update metadata namespace " "'%s'", namespace) diff --git a/glance/api/v2/metadef_objects.py b/glance/api/v2/metadef_objects.py index 9d231bd16e..feb41ff926 100644 --- a/glance/api/v2/metadef_objects.py +++ b/glance/api/v2/metadef_objects.py @@ -61,6 +61,10 @@ class MetadefObjectsController(object): LOG.debug("User not permitted to create metadata object within " "'%s' namespace", namespace) raise webob.exc.HTTPForbidden(explanation=e.msg) + except exception.Invalid as e: + msg = (_("Couldn't create metadata object: %s") + % encodeutils.exception_to_unicode(e)) + raise webob.exc.HTTPBadRequest(explanation=msg) except exception.NotFound as e: raise webob.exc.HTTPNotFound(explanation=e.msg) except exception.Duplicate as e: @@ -132,6 +136,10 @@ class MetadefObjectsController(object): metadef_object.properties = wsme_utils._get_value( metadata_object.properties) updated_metadata_obj = meta_repo.save(metadef_object) + except exception.Invalid as e: + msg = (_("Couldn't update metadata object: %s") + % encodeutils.exception_to_unicode(e)) + raise webob.exc.HTTPBadRequest(explanation=msg) except exception.Forbidden as e: LOG.debug("User not permitted to update metadata object '%s' " "within '%s' namespace ", object_name, namespace) diff --git a/glance/api/v2/metadef_properties.py b/glance/api/v2/metadef_properties.py index ff6df70021..9824ca58e8 100644 --- a/glance/api/v2/metadef_properties.py +++ b/glance/api/v2/metadef_properties.py @@ -123,6 +123,10 @@ class NamespacePropertiesController(object): LOG.debug("User not permitted to create metadata property within " "'%s' namespace", namespace) raise webob.exc.HTTPForbidden(explanation=e.msg) + except exception.Invalid as e: + msg = (_("Couldn't create metadata property: %s") + % encodeutils.exception_to_unicode(e)) + raise webob.exc.HTTPBadRequest(explanation=msg) except exception.NotFound as e: raise webob.exc.HTTPNotFound(explanation=e.msg) except exception.Duplicate as e: @@ -140,6 +144,10 @@ class NamespacePropertiesController(object): db_property_type.name = property_type.name db_property_type.schema = (self._to_dict(property_type))['schema'] updated_property_type = prop_repo.save(db_property_type) + except exception.Invalid as e: + msg = (_("Couldn't update metadata property: %s") + % encodeutils.exception_to_unicode(e)) + raise webob.exc.HTTPBadRequest(explanation=msg) except exception.Forbidden as e: LOG.debug("User not permitted to update metadata property '%s' " "within '%s' namespace", property_name, namespace) diff --git a/glance/api/v2/metadef_tags.py b/glance/api/v2/metadef_tags.py index 7ceba220a0..80f64af8d6 100644 --- a/glance/api/v2/metadef_tags.py +++ b/glance/api/v2/metadef_tags.py @@ -56,6 +56,10 @@ class TagsController(object): namespace=namespace, **tag_name_as_dict) tag_repo.add(new_meta_tag) + except exception.Invalid as e: + msg = (_("Couldn't create metadata tag: %s") + % encodeutils.exception_to_unicode(e)) + raise webob.exc.HTTPBadRequest(explanation=msg) except exception.Forbidden as e: LOG.debug("User not permitted to create metadata tag within " "'%s' namespace", namespace) @@ -152,6 +156,10 @@ class TagsController(object): metadef_tag.name = wsme_utils._get_value( metadata_tag.name) updated_metadata_tag = meta_repo.save(metadef_tag) + except exception.Invalid as e: + msg = (_("Couldn't update metadata tag: %s") + % encodeutils.exception_to_unicode(e)) + raise webob.exc.HTTPBadRequest(explanation=msg) except exception.Forbidden as e: LOG.debug("User not permitted to update metadata tag '%s' " "within '%s' namespace", tag_name, namespace) diff --git a/glance/db/simple/api.py b/glance/db/simple/api.py index 4f4b203b52..d203f81457 100644 --- a/glance/db/simple/api.py +++ b/glance/db/simple/api.py @@ -1107,6 +1107,7 @@ def _metadef_delete_namespace_content(get_func, key, context, namespace_name): @log_call +@utils.no_4byte_params def metadef_namespace_create(context, values): """Create a namespace object""" global DATA @@ -1140,6 +1141,7 @@ def metadef_namespace_create(context, values): @log_call +@utils.no_4byte_params def metadef_namespace_update(context, namespace_id, values): """Update a namespace object""" global DATA @@ -1327,6 +1329,7 @@ def metadef_object_get_all(context, namespace_name): @log_call +@utils.no_4byte_params def metadef_object_create(context, namespace_name, values): """Create a metadef object""" global DATA @@ -1367,6 +1370,7 @@ def metadef_object_create(context, namespace_name, values): @log_call +@utils.no_4byte_params def metadef_object_update(context, namespace_name, object_id, values): """Update a metadef object""" global DATA @@ -1450,6 +1454,7 @@ def metadef_property_count(context, namespace_name): @log_call +@utils.no_4byte_params def metadef_property_create(context, namespace_name, values): """Create a metadef property""" global DATA @@ -1493,6 +1498,7 @@ def metadef_property_create(context, namespace_name, values): @log_call +@utils.no_4byte_params def metadef_property_update(context, namespace_name, property_id, values): """Update a metadef property""" global DATA @@ -1785,6 +1791,7 @@ def metadef_tag_get_all(context, namespace_name, filters=None, marker=None, @log_call +@utils.no_4byte_params def metadef_tag_create(context, namespace_name, values): """Create a metadef tag""" global DATA @@ -1867,6 +1874,7 @@ def metadef_tag_create_tags(context, namespace_name, tag_list): @log_call +@utils.no_4byte_params def metadef_tag_update(context, namespace_name, id, values): """Update a metadef tag""" global DATA diff --git a/glance/db/sqlalchemy/api.py b/glance/db/sqlalchemy/api.py index 66050f3081..5552fa190d 100644 --- a/glance/db/sqlalchemy/api.py +++ b/glance/db/sqlalchemy/api.py @@ -1591,12 +1591,14 @@ def metadef_namespace_get(context, namespace_name, session=None): context, namespace_name, session) +@utils.no_4byte_params def metadef_namespace_create(context, values, session=None): """Create a namespace or raise if it already exists.""" session = session or get_session() return metadef_namespace_api.create(context, values, session) +@utils.no_4byte_params def metadef_namespace_update(context, namespace_id, namespace_dict, session=None): """Update a namespace or raise if it does not exist or not visible""" @@ -1626,6 +1628,7 @@ def metadef_object_get(context, namespace_name, object_name, session=None): context, namespace_name, object_name, session) +@utils.no_4byte_params def metadef_object_create(context, namespace_name, object_dict, session=None): """Create a metadata-schema object or raise if it already exists.""" @@ -1634,6 +1637,7 @@ def metadef_object_create(context, namespace_name, object_dict, context, namespace_name, object_dict, session) +@utils.no_4byte_params def metadef_object_update(context, namespace_name, object_id, object_dict, session=None): """Update an object or raise if it does not exist or not visible.""" @@ -1678,6 +1682,7 @@ def metadef_property_get(context, namespace_name, context, namespace_name, property_name, session) +@utils.no_4byte_params def metadef_property_create(context, namespace_name, property_dict, session=None): """Create a metadef property or raise if it already exists.""" @@ -1686,6 +1691,7 @@ def metadef_property_create(context, namespace_name, property_dict, context, namespace_name, property_dict, session) +@utils.no_4byte_params def metadef_property_update(context, namespace_name, property_id, property_dict, session=None): """Update an object or raise if it does not exist or not visible.""" @@ -1788,6 +1794,7 @@ def metadef_tag_get(context, namespace_name, name, session=None): context, namespace_name, name, session) +@utils.no_4byte_params def metadef_tag_create(context, namespace_name, tag_dict, session=None): """Create a metadata-schema tag or raise if it already exists.""" @@ -1804,6 +1811,7 @@ def metadef_tag_create_tags(context, namespace_name, tag_list, context, namespace_name, tag_list, session) +@utils.no_4byte_params def metadef_tag_update(context, namespace_name, id, tag_dict, session=None): """Update an tag or raise if it does not exist or not visible.""" diff --git a/glance/tests/unit/v2/test_metadef_resources.py b/glance/tests/unit/v2/test_metadef_resources.py index 15f54042a7..ebb7fbac37 100644 --- a/glance/tests/unit/v2/test_metadef_resources.py +++ b/glance/tests/unit/v2/test_metadef_resources.py @@ -606,6 +606,16 @@ class TestMetadefsControllers(base.IsolatedUnitTest): namespace = self.namespace_controller.show(request, NAMESPACE4) self.assertEqual(NAMESPACE4, namespace.namespace) + def test_namespace_create_with_4byte_character(self): + request = unit_test_utils.get_fake_request() + + namespace = namespaces.Namespace() + namespace.namespace = u'\U0001f693' + + self.assertRaises(webob.exc.HTTPBadRequest, + self.namespace_controller.create, request, + namespace) + def test_namespace_create_duplicate(self): request = unit_test_utils.get_fake_request() @@ -810,6 +820,16 @@ class TestMetadefsControllers(base.IsolatedUnitTest): self.assertRaises(webob.exc.HTTPNotFound, self.namespace_controller.show, request, NAMESPACE1) + def test_namespace_update_with_4byte_character(self): + request = unit_test_utils.get_fake_request() + + namespace = self.namespace_controller.show(request, NAMESPACE1) + namespace.namespace = u'\U0001f693' + + self.assertRaises(webob.exc.HTTPBadRequest, + self.namespace_controller.update, request, + namespace, NAMESPACE1) + def test_namespace_update_name_conflict(self): request = unit_test_utils.get_fake_request() namespace = self.namespace_controller.show(request, NAMESPACE1) @@ -964,6 +984,18 @@ class TestMetadefsControllers(base.IsolatedUnitTest): self.assertEqual('string', property.type) self.assertEqual('title', property.title) + def test_property_create_with_4byte_character(self): + request = unit_test_utils.get_fake_request() + + property = properties.PropertyType() + property.name = u'\U0001f693' + property.type = 'string' + property.title = 'title' + + self.assertRaises(webob.exc.HTTPBadRequest, + self.property_controller.create, + request, NAMESPACE1, property) + def test_property_create_with_operators(self): request = unit_test_utils.get_fake_request() @@ -1131,6 +1163,19 @@ class TestMetadefsControllers(base.IsolatedUnitTest): PROPERTY1, property) self.assertNotificationsLog([]) + def test_property_update_with_4byte_character(self): + request = unit_test_utils.get_fake_request(tenant=TENANT3) + + property = self.property_controller.show(request, NAMESPACE3, + PROPERTY1) + property.name = u'\U0001f693' + property.type = 'string' + property.title = 'title' + + self.assertRaises(webob.exc.HTTPBadRequest, + self.property_controller.update, request, + NAMESPACE3, PROPERTY1, property) + def test_property_update_non_existing(self): request = unit_test_utils.get_fake_request(tenant=TENANT3) @@ -1313,6 +1358,18 @@ class TestMetadefsControllers(base.IsolatedUnitTest): NAMESPACE1) self.assertNotificationsLog([]) + def test_object_create_with_4byte_character(self): + request = unit_test_utils.get_fake_request() + + object = objects.MetadefObject() + object.name = u'\U0001f693' + object.required = [] + object.properties = {} + + self.assertRaises(webob.exc.HTTPBadRequest, + self.object_controller.create, request, + object, NAMESPACE1) + def test_object_create_non_existing_namespace(self): request = unit_test_utils.get_fake_request() @@ -1416,6 +1473,16 @@ class TestMetadefsControllers(base.IsolatedUnitTest): object = self.object_controller.show(request, NAMESPACE1, OBJECT2) self.assertEqual(OBJECT2, object.name) + def test_object_update_with_4byte_character(self): + request = unit_test_utils.get_fake_request() + + object = self.object_controller.show(request, NAMESPACE1, OBJECT1) + object.name = u'\U0001f693' + + self.assertRaises(webob.exc.HTTPBadRequest, + self.object_controller.update, request, + object, NAMESPACE1, OBJECT1) + def test_object_update_conflict(self): request = unit_test_utils.get_fake_request(tenant=TENANT3) @@ -1745,6 +1812,13 @@ class TestMetadefsControllers(base.IsolatedUnitTest): tag = self.tag_controller.show(request, NAMESPACE1, TAG2) self.assertEqual(TAG2, tag.name) + def test_tag_create_with_4byte_character(self): + request = unit_test_utils.get_fake_request() + + self.assertRaises(webob.exc.HTTPBadRequest, + self.tag_controller.create, + request, NAMESPACE1, u'\U0001f693') + def test_tag_create_tags(self): request = unit_test_utils.get_fake_request() @@ -1872,6 +1946,16 @@ class TestMetadefsControllers(base.IsolatedUnitTest): tag = self.tag_controller.show(request, NAMESPACE1, TAG2) self.assertEqual(TAG2, tag.name) + def test_tag_update_with_4byte_character(self): + request = unit_test_utils.get_fake_request() + + tag = self.tag_controller.show(request, NAMESPACE1, TAG1) + tag.name = u'\U0001f693' + + self.assertRaises(webob.exc.HTTPBadRequest, + self.tag_controller.update, request, tag, + NAMESPACE1, TAG1) + def test_tag_update_conflict(self): request = unit_test_utils.get_fake_request(tenant=TENANT3)