Skip to content

Commit

Permalink
Add ipv4 and ipv6 validation
Browse files Browse the repository at this point in the history
Fixes bug 891264

Change-Id: Ie5975a6ee8129392b308d405ab5cb9303bdd0a89
  • Loading branch information
ameade committed Jan 16, 2012
1 parent 46f90f7 commit 918d999
Show file tree
Hide file tree
Showing 2 changed files with 197 additions and 2 deletions.
35 changes: 33 additions & 2 deletions nova/api/openstack/compute/servers.py
Expand Up @@ -16,6 +16,7 @@

import base64
import os
import socket
from xml.dom import minidom

from webob import exc
Expand Down Expand Up @@ -568,6 +569,20 @@ def _validate_user_data(self, user_data):
expl = _('Userdata content cannot be decoded')
raise exc.HTTPBadRequest(explanation=expl)

def _validate_access_ipv4(self, address):
try:
socket.inet_aton(address)
except socket.error:
expl = _('accessIPv4 is not proper IPv4 format')
raise exc.HTTPBadRequest(explanation=expl)

def _validate_access_ipv6(self, address):
try:
socket.inet_pton(socket.AF_INET6, address)
except socket.error:
expl = _('accessIPv4 is not proper IPv4 format')
raise exc.HTTPBadRequest(explanation=expl)

@wsgi.serializers(xml=ServerTemplate)
@exception.novaclient_converter
@scheduler_api.redirect_handler
Expand Down Expand Up @@ -634,6 +649,14 @@ def create(self, req, body):
requested_networks = self._get_requested_networks(
requested_networks)

(access_ip_v4, ) = server_dict.get('accessIPv4'),
if access_ip_v4 is not None:
self._validate_access_ipv4(access_ip_v4)

(access_ip_v6, ) = server_dict.get('accessIPv6'),
if access_ip_v6 is not None:
self._validate_access_ipv6(access_ip_v6)

try:
flavor_id = self._flavor_id_from_req_data(body)
except ValueError as error:
Expand Down Expand Up @@ -687,8 +710,8 @@ def create(self, req, body):
display_description=name,
key_name=key_name,
metadata=server_dict.get('metadata', {}),
access_ip_v4=server_dict.get('accessIPv4'),
access_ip_v6=server_dict.get('accessIPv6'),
access_ip_v4=access_ip_v4,
access_ip_v6=access_ip_v6,
injected_files=injected_files,
admin_password=password,
zone_blob=zone_blob,
Expand Down Expand Up @@ -767,10 +790,12 @@ def update(self, req, id, body):

if 'accessIPv4' in body['server']:
access_ipv4 = body['server']['accessIPv4']
self._validate_access_ipv4(access_ipv4)
update_dict['access_ip_v4'] = access_ipv4.strip()

if 'accessIPv6' in body['server']:
access_ipv6 = body['server']['accessIPv6']
self._validate_access_ipv6(access_ipv6)
update_dict['access_ip_v6'] = access_ipv6.strip()

if 'auto_disk_config' in body['server']:
Expand Down Expand Up @@ -1008,6 +1033,12 @@ def _action_rebuild(self, req, id, body):
'metadata': 'metadata',
}

if 'accessIPv4' in body:
self._validate_access_ipv4(body['accessIPv4'])

if 'accessIPv6' in body:
self._validate_access_ipv6(body['accessIPv6'])

kwargs = {}

for request_attribute, instance_attribute in attr_map.items():
Expand Down
164 changes: 164 additions & 0 deletions nova/tests/api/openstack/compute/test_servers.py
Expand Up @@ -1085,6 +1085,17 @@ def test_update_server_access_ipv4(self):
self.assertEqual(res_dict['server']['id'], FAKE_UUID)
self.assertEqual(res_dict['server']['accessIPv4'], '0.0.0.0')

def test_update_server_access_ipv4_bad_format(self):
self.stubs.Set(nova.db, 'instance_get',
return_server_with_attributes(access_ipv4='0.0.0.0'))
req = fakes.HTTPRequest.blank('/v2/fake/servers/%s' % FAKE_UUID)
req.method = 'PUT'
req.content_type = 'application/json'
body = {'server': {'accessIPv4': 'bad_format'}}
req.body = json.dumps(body)
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
req, FAKE_UUID, body)

def test_update_server_access_ipv6(self):
self.stubs.Set(nova.db, 'instance_get',
return_server_with_attributes(access_ipv6='beef::0123'))
Expand All @@ -1098,6 +1109,17 @@ def test_update_server_access_ipv6(self):
self.assertEqual(res_dict['server']['id'], FAKE_UUID)
self.assertEqual(res_dict['server']['accessIPv6'], 'beef::0123')

def test_update_server_access_ipv6_bad_format(self):
self.stubs.Set(nova.db, 'instance_get',
return_server_with_attributes(access_ipv6='beef::0123'))
req = fakes.HTTPRequest.blank('/v2/fake/servers/%s' % FAKE_UUID)
req.method = 'PUT'
req.content_type = 'application/json'
body = {'server': {'accessIPv6': 'bad_format'}}
req.body = json.dumps(body)
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
req, FAKE_UUID, body)

def test_update_server_adminPass_ignored(self):
inst_dict = dict(name='server_test', adminPass='bacon')
body = dict(server=inst_dict)
Expand All @@ -1122,6 +1144,80 @@ def server_update(context, id, params):
self.assertEqual(res_dict['server']['id'], FAKE_UUID)
self.assertEqual(res_dict['server']['name'], 'server_test')

def test_rebuild_instance_with_access_ipv4_bad_format(self):

def fake_get_instance(*args, **kwargs):
return fakes.stub_instance(1, vm_state=vm_states.ACTIVE)

self.stubs.Set(nova.db, 'instance_get', fake_get_instance)
# proper local hrefs must start with 'http://localhost/v2/'
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
image_href = 'http://localhost/v2/fake/images/%s' % image_uuid
access_ipv4 = 'bad_format'
access_ipv6 = 'fead::1234'
body = {
'rebuild': {
'name': 'new_name',
'imageRef': image_href,
'accessIPv4': access_ipv4,
'accessIPv6': access_ipv6,
'metadata': {
'hello': 'world',
'open': 'stack',
},
'personality': [
{
"path": "/etc/banner.txt",
"contents": "MQ==",
},
],
},
}

req = fakes.HTTPRequest.blank('/v2/fake/servers/a/action')
req.method = 'POST'
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._action_rebuild, req, 1, body)

def test_rebuild_instance_with_access_ipv6_bad_format(self):

def fake_get_instance(*args, **kwargs):
return fakes.stub_instance(1, vm_state=vm_states.ACTIVE)

self.stubs.Set(nova.db, 'instance_get', fake_get_instance)
# proper local hrefs must start with 'http://localhost/v2/'
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
image_href = 'http://localhost/v2/fake/images/%s' % image_uuid
access_ipv4 = '1.2.3.4'
access_ipv6 = 'bad_format'
body = {
'rebuild': {
'name': 'new_name',
'imageRef': image_href,
'accessIPv4': access_ipv4,
'accessIPv6': access_ipv6,
'metadata': {
'hello': 'world',
'open': 'stack',
},
'personality': [
{
"path": "/etc/banner.txt",
"contents": "MQ==",
},
],
},
}

req = fakes.HTTPRequest.blank('/v2/fake/servers/a/action')
req.method = 'POST'
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._action_rebuild, req, 1, body)

def test_get_all_server_details(self):
expected_flavor = {
"id": "1",
Expand Down Expand Up @@ -1571,6 +1667,74 @@ def test_create_instance_with_access_ip(self):
self.assertEqual(FLAGS.password_length, len(server['adminPass']))
self.assertEqual(FAKE_UUID, server['id'])

def test_create_instance_bad_format_access_ip_v4(self):
# proper local hrefs must start with 'http://localhost/v2/'
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
image_href = 'http://localhost/v2/fake/images/%s' % image_uuid
flavor_ref = 'http://localhost/fake/flavors/3'
access_ipv4 = 'bad_format'
access_ipv6 = 'fead::1234'
body = {
'server': {
'name': 'server_test',
'imageRef': image_href,
'flavorRef': flavor_ref,
'accessIPv4': access_ipv4,
'accessIPv6': access_ipv6,
'metadata': {
'hello': 'world',
'open': 'stack',
},
'personality': [
{
"path": "/etc/banner.txt",
"contents": "MQ==",
},
],
},
}

req = fakes.HTTPRequest.blank('/v2/fake/servers')
req.method = 'POST'
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
req, body)

def test_create_instance_bad_format_access_ip_v6(self):
# proper local hrefs must start with 'http://localhost/v2/'
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
image_href = 'http://localhost/v2/fake/images/%s' % image_uuid
flavor_ref = 'http://localhost/fake/flavors/3'
access_ipv4 = '1.2.3.4'
access_ipv6 = 'bad_format'
body = {
'server': {
'name': 'server_test',
'imageRef': image_href,
'flavorRef': flavor_ref,
'accessIPv4': access_ipv4,
'accessIPv6': access_ipv6,
'metadata': {
'hello': 'world',
'open': 'stack',
},
'personality': [
{
"path": "/etc/banner.txt",
"contents": "MQ==",
},
],
},
}

req = fakes.HTTPRequest.blank('/v2/fake/servers')
req.method = 'POST'
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
req, body)

def test_create_instance(self):
# proper local hrefs must start with 'http://localhost/v2/'
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
Expand Down

0 comments on commit 918d999

Please sign in to comment.