Skip to content

Commit

Permalink
Validate for blacklist chars in name at create
Browse files Browse the repository at this point in the history
Closes-Bug: 1379066

Change-Id: I9d289076b5c929d9137c795f60a0892175e4b5e5
  • Loading branch information
Hampapur Ajay committed Oct 9, 2014
1 parent 55d8ab9 commit fff8a7d
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/api-lib/vnc_api.py
Expand Up @@ -369,6 +369,8 @@ def _request_server(self, op, url, data=None, retry_on_error=True, retry_after_a
elif status == 503 or status == 504:
time.sleep(1)
continue
elif status == 400:
raise BadRequest(status, content)
else: # Unknown Error
raise HttpError(status, content)
# end while True
Expand Down
98 changes: 97 additions & 1 deletion src/config/api-server/tests/test_crud_basic.py
Expand Up @@ -642,7 +642,7 @@ def err_rabbitq_put(*args, **kwargs):

logger.info("Creating objects to hit max rabbit pending.")
# every create updates project quota
test_objs = self._create_test_objects(count=max_pend_upd/2+1)
test_objs = self._create_test_objects(count=max_pend_upd)

def asserts_on_max_pending():
self.assertEqual(e.status_code, 500)
Expand Down Expand Up @@ -738,6 +738,102 @@ def test_sandesh_trace(self):
print top_elem[0][0][-1].text
self.assertThat(top_elem[0][0][-1].text, Contains('delete'))
self.assertThat(top_elem[0][0][-1].text, Contains(test_obj.name))

def test_dup_create_with_same_uuid(self):
dom_name = self.id() + '-domain'
logger.info('Creating Domain %s', dom_name)
domain_obj = Domain(dom_name)
self._vnc_lib.domain_create(domain_obj)

project_name = self.id() + '-project'
logger.info('Creating Project %s', project_name)
orig_project_obj = Project(project_name, domain_obj)
self._vnc_lib.project_create(orig_project_obj)

logger.info('Creating Dup Project in default domain with same uuid')
dup_project_obj = Project(project_name)
dup_project_obj.uuid = orig_project_obj.uuid
with ExpectedException(RefsExistError) as e:
self._vnc_lib.project_create(dup_project_obj)

def test_put_on_wrong_type(self):
vn_name = self.id()+'-vn'
vn_obj = VirtualNetwork(vn_name)
self._add_detail('Creating network with name %s' %(vn_name))
self._vnc_lib.virtual_network_create(vn_obj)
listen_port = self._api_server._args.listen_port
uri = '/network-ipam/%s' %(vn_obj.uuid)
self._add_detail('Trying to update uuid as network-ipam, expecting 404')
code, msg = self._http_put(uri, json.dumps({'network-ipam': {'display_name': 'foobar'}}))
self.assertThat(code, Equals(404))

self._add_detail('Updating display_name as network, expecting success')
uri = '/virtual-network/%s' %(vn_obj.uuid)
code, msg = self._http_put(uri, json.dumps({'virtual-network': {'display_name': 'foobar'}}))
self.assertThat(code, Equals(200))
rb_obj = self._vnc_lib.virtual_network_read(id=vn_obj.uuid)
self.assertThat(rb_obj.display_name, Equals('foobar'))

def test_floatingip_as_instanceip(self):
ipam_fixt = self.useFixture(NetworkIpamTestFixtureGen(self._vnc_lib))

project_fixt = self.useFixture(ProjectTestFixtureGen(self._vnc_lib, 'default-project'))

subnet_vnc = IpamSubnetType(subnet=SubnetType('1.1.1.0', 24))
vnsn_data = VnSubnetsType([subnet_vnc])
logger.info("Creating a virtual network")
logger.info("Creating subnet 1.1.1.0/24")
vn_fixt = self.useFixture(VirtualNetworkTestFixtureGen(self._vnc_lib,
network_ipam_ref_infos=[(ipam_fixt.getObj(), vnsn_data)]))
vn_fixt.getObj().set_router_external(True)
self._vnc_lib.virtual_network_update(vn_fixt.getObj())

logger.info("Fetching floating-ip-pool")
fip_pool_fixt = self.useFixture(
FloatingIpPoolTestFixtureGen(self._vnc_lib, 'floating-ip-pool',
parent_fixt=vn_fixt))

logger.info("Creating auto-alloc floating-ip")
fip_fixt = self.useFixture(
FloatingIpTestFixtureGen(
self._vnc_lib, 'fip1', parent_fixt=fip_pool_fixt,
project_refs=[project_fixt.getObj()]))
ip_allocated = fip_fixt.getObj().floating_ip_address

logger.info("Creating auto-alloc instance-ip, expecting an error")
with self.assertRaises(cfgm_common.exceptions.PermissionDenied):
iip_fixt = self.useFixture(
InstanceIpTestFixtureGen(
self._vnc_lib, 'iip1', auto_prop_val=False,
instance_ip_address=ip_allocated,
virtual_network_refs=[vn_fixt.getObj()]))
# end test_floatingip_as_instanceip

def test_name_with_blacklist_char(self):
vn_name = self.id()+'-vn<1>'
vn_obj = VirtualNetwork(vn_name)
with ExpectedException(BadRequest) as e:
self._vnc_lib.virtual_network_create(vn_obj)

vn_name = self.id()+'-vn'
vn_obj = VirtualNetwork(vn_name)
self._vnc_lib.virtual_network_create(vn_obj)
self.assertTill(self.ifmap_has_ident, obj=vn_obj)

rt_name = self.id()+'-route-target<1>'
rt_obj = RouteTarget(rt_name)
with ExpectedException(BadRequest) as e:
self._vnc_lib.route_target_create(rt_obj)

rt_name = self.id()+'-route-target:1'
rt_obj = RouteTarget(rt_name)
self._vnc_lib.route_target_create(rt_obj)
self.assertTill(self.ifmap_has_ident, obj=rt_obj)

self._vnc_lib.virtual_network_delete(id=vn_obj.uuid)
self._vnc_lib.route_target_delete(id=rt_obj.uuid)
# end test_name_with_blacklist_char

# end class TestVncCfgApiServer

class TestLocalAuth(test_case.ApiServerTestCase):
Expand Down
23 changes: 23 additions & 0 deletions src/config/api-server/vnc_cfg_api_server.py
Expand Up @@ -201,6 +201,8 @@ class VncApiServer(VncApiServerGen):
"""
This is the manager class co-ordinating all classes present in the package
"""
_INVALID_NAME_CHARS = set('<>:')

def __new__(cls, *args, **kwargs):
obj = super(VncApiServer, cls).__new__(cls, *args, **kwargs)
bottle.route('/', 'GET', obj.homepage_http_get)
Expand Down Expand Up @@ -236,6 +238,7 @@ def __init__(self, args_str=None):
self._get_common = self._http_get_common
self._put_common = self._http_put_common
self._delete_common = self._http_delete_common
self._post_validate = self._http_post_validate
self._post_common = self._http_post_common

# Type overrides from generated code
Expand Down Expand Up @@ -1266,6 +1269,26 @@ def _http_delete_common(self, request, obj_type, uuid, parent_type):
return self._permissions.check_perms_write(request, parent_uuid)
# end _http_delete_common

def _http_post_validate(self, obj_type=None, obj_dict=None):
if not obj_dict:
return

def _check_field_present(fname):
fval = obj_dict.get(fname)
if not fval:
bottle.abort(400, "Bad Request, no %s in POST body" %(fname))
return fval
fq_name = _check_field_present('fq_name')
if obj_type[:].replace('-','_') == 'route_target':
invalid_chars = self._INVALID_NAME_CHARS - set(':')
else:
invalid_chars = self._INVALID_NAME_CHARS
if any((c in invalid_chars) for c in fq_name[-1]):
bottle.abort(400,
"Bad Request, name has one of invalid chars %s"
%(invalid_chars))
# end _http_post_validate

def _http_post_common(self, request, obj_type, obj_dict):
# If not connected to zookeeper do not allow operations that
# causes the state change
Expand Down
12 changes: 12 additions & 0 deletions src/config/common/exceptions.py
Expand Up @@ -9,6 +9,18 @@ class VncError(Exception):
# end class VncError


class BadRequest(Exception):
def __init__(self, status_code, content):
self.status_code = status_code
self.content = content
# end __init__

def __str__(self):
return 'HTTP Status: %s Content: %s' % (self.status_code, self.content)
# end __str__
# end class BadRequest


class NoIdError(VncError):

def __init__(self, unknown_id):
Expand Down
3 changes: 3 additions & 0 deletions src/config/common/tests/test_common.py
Expand Up @@ -27,6 +27,8 @@
bottle.catchall=False

import inspect
import novaclient
import novaclient.client

def lineno():
"""Returns the current line number in our program."""
Expand Down Expand Up @@ -276,6 +278,7 @@ def setUp(self):
self._api_svr_app = TestApp(bottle.app(), extra_environ=extra_env)
self._vnc_lib = VncApi('u', 'p', api_server_host=self._api_server_ip,
api_server_port=self._api_server_port)
self._vnc_lib._headers['X-Role'] = 'admin'

self._api_server_session = requests.Session()
adapter = requests.adapters.HTTPAdapter()
Expand Down
16 changes: 16 additions & 0 deletions src/config/common/tests/test_utils.py
Expand Up @@ -35,6 +35,22 @@
def stub(*args, **kwargs):
pass

class FakeApiConfigLog(object):
_all_logs = []
send = stub
def __init__(self, *args, **kwargs):
FakeApiConfigLog._all_logs.append(kwargs['api_log'])

@classmethod
def _print(cls):
for log in cls._all_logs:
x = copy.deepcopy(log.__dict__)
#body = x.pop('body')
#pprint(json.loads(body))
pprint(x)
print "\n"
# class FakeApiConfigLog


class CassandraCFs(object):
_all_cfs = {}
Expand Down
Expand Up @@ -570,7 +570,7 @@ def _resource_create(self, resource_type, obj):
obj.name += '-' + obj.uuid
obj.fq_name[-1] += '-' + obj.uuid
obj_uuid = getattr(self._vnc_lib, resource_type + '_create')(obj)
except PermissionDenied as e:
except (PermissionDenied, BadRequest) as e:
exc_info = {'type': 'BadRequest', 'message': str(e)}
bottle.abort(400, json.dumps(exc_info))

Expand Down

0 comments on commit fff8a7d

Please sign in to comment.