Checks for invalid denylist regex patterns

Adds new field check method DenyListFields to validate
the pattern string. in addition, check for a zero
length string as well.

Closes-Bug: #1934252
Change-Id: I2b69025fc11125bb73a4e0f8c0dedad951399cbf
This commit is contained in:
dekehn 2022-01-20 20:38:06 +00:00 committed by Michael Johnson
parent 7e543c2d22
commit f44395870d
4 changed files with 85 additions and 2 deletions

View File

@ -20,8 +20,8 @@ from designate.objects import fields
class Blacklist(base.DictObjectMixin, base.PersistentObjectMixin,
base.DesignateObject):
fields = {
'pattern': fields.StringFields(maxLength=255),
'description': fields.StringFields(maxLength=160, nullable=True),
'pattern': fields.DenylistFields(maxLength=255),
'description': fields.DenylistFields(maxLength=160, nullable=True),
}
STRING_KEYS = [

View File

@ -452,3 +452,25 @@ class IPOrHost(IPV4AndV6AddressField):
if not re.match(StringFields.RE_ZONENAME, value):
raise ValueError("%s is not IP address or host name" % value)
return value
class DenylistFields(StringFields):
def __init__(self, **kwargs):
super(DenylistFields, self).__init__(**kwargs)
def coerce(self, obj, attr, value):
value = super(DenylistFields, self).coerce(obj, attr, value)
if value is None:
return self._null(obj, attr)
# determine the validity if a regex expression filter has been used.
msg = ("%s is not a valid regular expression" % value)
if not len(value):
raise ValueError(msg)
try:
re.compile(value)
except Exception:
raise ValueError(msg)
return value

View File

@ -165,3 +165,48 @@ class ApiV2BlacklistsTest(ApiV2TestCase):
url = '/blacklists?description=test'
self.policy({'find_blacklists': '@'})
self._assert_exception('bad_request', 400, self.client.get, url)
def test_create_invalid_denylist_pattern(self):
self.policy({'create_blacklist': '@'})
body = {
'description': u'This is the description.'
}
url = '/blacklists/'
# doing each pattern individually so upon error one can trace
# back to the exact line number
body['pattern'] = ''
self._assert_exception(
'invalid_object', 400, self.client.post_json, url, body)
body['pattern'] = '#(*&^%$%$#@$'
self._assert_exception(
'invalid_object', 400, self.client.post_json, url, body)
body['pattern'] = 'a' * 1000
self._assert_exception(
'invalid_object', 400, self.client.post_json, url, body)
def test_update_invalid_denylist_pattern(self):
blacklist = self.create_blacklist(fixture=0)
self.policy({'update_blacklist': '@'})
url = ('/blacklists/%s' % blacklist['id'])
# doing each pattern individually so upon error one can trace
# back to the exact line number
body = {'pattern': ''}
self._assert_exception(
'invalid_object', 400, self.client.patch_json, url, body,
status=400)
body = {'pattern': '#(*&^%$%$#@$'}
self._assert_exception(
'invalid_object', 400, self.client.patch_json, url, body,
status=400)
body = {'pattern': 'a' * 1000}
self._assert_exception(
'invalid_object', 400, self.client.patch_json, url, body,
status=400)

View File

@ -0,0 +1,16 @@
---
fixes:
- |
Fixes `bug 1934252`_ which ignored invalid denylist patterns. The fix
entailed checking the pattern string via regular expression compiler and
testing for zero length.
Previously you could create blacklist/denylist using string that cannot
be used either as a regex or as a zone name, for example:
patterns = ['', ``'#(*&^%$%$#@$']``
In addition, the server will return a 400 BadRequest response to an
invalid pattern.
.. _Bug 1934252: https://bugs.launchpad.net/designate/+bug/1934252