mirror of
https://github.com/ansible/awx.git
synced 2026-03-28 22:35:08 -02:30
Implements AC-380. Add validation for host (and group) names.
This commit is contained in:
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
# Python
|
# Python
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
import socket
|
||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
# PyYAML
|
# PyYAML
|
||||||
@@ -337,6 +339,31 @@ class HostSerializer(BaseSerializerWithVariables):
|
|||||||
d['groups'] = [{'id': g.id, 'name': g.name} for g in obj.groups.all()]
|
d['groups'] = [{'id': g.id, 'name': g.name} for g in obj.groups.all()]
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def validate_name(self, attrs, source):
|
||||||
|
name = unicode(attrs.get(source, ''))
|
||||||
|
# Allow hostname (except IPv6 for now) to specify the port # inline.
|
||||||
|
if name.count(':') == 1:
|
||||||
|
name, port = name.split(':')
|
||||||
|
try:
|
||||||
|
port = int(port)
|
||||||
|
if port < 1 or port > 65535:
|
||||||
|
raise ValueError
|
||||||
|
except ValueError:
|
||||||
|
raise serializers.ValidationError('Invalid port specification')
|
||||||
|
for family in (socket.AF_INET, socket.AF_INET6):
|
||||||
|
try:
|
||||||
|
socket.inet_pton(family, name)
|
||||||
|
return attrs
|
||||||
|
except socket.error:
|
||||||
|
pass
|
||||||
|
# Hostname should match the following regular expression and have at
|
||||||
|
# last one letter in the name (to catch invalid IPv4 addresses from
|
||||||
|
# above).
|
||||||
|
valid_host_re = r'^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$'
|
||||||
|
if re.match(valid_host_re, name) and re.match(r'^.*?[a-zA-Z].*?$', name):
|
||||||
|
return attrs
|
||||||
|
raise serializers.ValidationError('Invalid host name or IP')
|
||||||
|
|
||||||
class GroupSerializer(BaseSerializerWithVariables):
|
class GroupSerializer(BaseSerializerWithVariables):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -356,6 +383,12 @@ class GroupSerializer(BaseSerializerWithVariables):
|
|||||||
))
|
))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def validate_name(self, attrs, source):
|
||||||
|
name = attrs.get(source, '')
|
||||||
|
if name in ('all', '_meta'):
|
||||||
|
raise serializers.ValidationError('Invalid group name')
|
||||||
|
return attrs
|
||||||
|
|
||||||
class GroupTreeSerializer(GroupSerializer):
|
class GroupTreeSerializer(GroupSerializer):
|
||||||
|
|
||||||
children = serializers.SerializerMethodField('get_children')
|
children = serializers.SerializerMethodField('get_children')
|
||||||
|
|||||||
@@ -249,9 +249,9 @@ class InventoryTest(BaseTest):
|
|||||||
organization = self.organizations[0]
|
organization = self.organizations[0]
|
||||||
)
|
)
|
||||||
invalid = dict(name='asdf0.example.com')
|
invalid = dict(name='asdf0.example.com')
|
||||||
new_host_a = dict(name='asdf0.example.com', inventory=inv.pk)
|
new_host_a = dict(name='asdf0.example.com:1022', inventory=inv.pk)
|
||||||
new_host_b = dict(name='asdf1.example.com', inventory=inv.pk)
|
new_host_b = dict(name='asdf1.example.com', inventory=inv.pk)
|
||||||
new_host_c = dict(name='asdf2.example.com', inventory=inv.pk)
|
new_host_c = dict(name='127.1.2.3:2022', inventory=inv.pk)
|
||||||
new_host_d = dict(name='asdf3.example.com', inventory=inv.pk)
|
new_host_d = dict(name='asdf3.example.com', inventory=inv.pk)
|
||||||
new_host_e = dict(name='asdf4.example.com', inventory=inv.pk)
|
new_host_e = dict(name='asdf4.example.com', inventory=inv.pk)
|
||||||
host_data0 = self.post(hosts, data=invalid, expect=400, auth=self.get_super_credentials())
|
host_data0 = self.post(hosts, data=invalid, expect=400, auth=self.get_super_credentials())
|
||||||
@@ -296,6 +296,23 @@ class InventoryTest(BaseTest):
|
|||||||
self.assertEqual(Host.objects.get(id=host_data3['id']).variables, host_data3['variables'])
|
self.assertEqual(Host.objects.get(id=host_data3['id']).variables, host_data3['variables'])
|
||||||
self.assertEqual(Host.objects.get(id=host_data3['id']).variables_dict, {'angry': 'penguin'})
|
self.assertEqual(Host.objects.get(id=host_data3['id']).variables_dict, {'angry': 'penguin'})
|
||||||
|
|
||||||
|
# Try with invalid hostnames and invalid IPs.
|
||||||
|
data = dict(name='', inventory=inv.pk)
|
||||||
|
with self.current_user(self.super_django_user):
|
||||||
|
response = self.post(hosts, data=data, expect=400)
|
||||||
|
data = dict(name='not a valid host name', inventory=inv.pk)
|
||||||
|
with self.current_user(self.super_django_user):
|
||||||
|
response = self.post(hosts, data=data, expect=400)
|
||||||
|
data = dict(name='validhost:99999', inventory=inv.pk)
|
||||||
|
with self.current_user(self.super_django_user):
|
||||||
|
response = self.post(hosts, data=data, expect=400)
|
||||||
|
data = dict(name='123.234.345.456', inventory=inv.pk)
|
||||||
|
with self.current_user(self.super_django_user):
|
||||||
|
response = self.post(hosts, data=data, expect=400)
|
||||||
|
data = dict(name='2001::1::3F', inventory=inv.pk)
|
||||||
|
with self.current_user(self.super_django_user):
|
||||||
|
response = self.post(hosts, data=data, expect=400)
|
||||||
|
|
||||||
###########################################
|
###########################################
|
||||||
# GROUPS
|
# GROUPS
|
||||||
|
|
||||||
@@ -328,6 +345,15 @@ class InventoryTest(BaseTest):
|
|||||||
# hostnames must be unique inside an organization
|
# hostnames must be unique inside an organization
|
||||||
group_data4 = self.post(groups, data=new_group_c, expect=400, auth=self.get_other_credentials())
|
group_data4 = self.post(groups, data=new_group_c, expect=400, auth=self.get_other_credentials())
|
||||||
|
|
||||||
|
# Check that we don't allow creating reserved group names.
|
||||||
|
data = dict(name='all', inventory=inv.pk)
|
||||||
|
with self.current_user(self.super_django_user):
|
||||||
|
response = self.post(groups, data=data, expect=400)
|
||||||
|
data = dict(name='_meta', inventory=inv.pk)
|
||||||
|
with self.current_user(self.super_django_user):
|
||||||
|
response = self.post(groups, data=data, expect=400)
|
||||||
|
|
||||||
|
|
||||||
#################################################
|
#################################################
|
||||||
# HOSTS->inventories POST via subcollection
|
# HOSTS->inventories POST via subcollection
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user