added auth, request parser, sql_tests
This commit is contained in:
parent
19598a404b
commit
3d3b3f44ee
|
@ -0,0 +1,28 @@
|
||||||
|
_syntribos()
|
||||||
|
{
|
||||||
|
local cur prev opts
|
||||||
|
COMPREPLY=()
|
||||||
|
cur=$(echo "${COMP_WORDS[COMP_CWORD]}"|sed 's/\\/\\\\/g')
|
||||||
|
prev=$(echo "${COMP_WORDS[COMP_CWORD-1]}"|sed 's/\\/\\\\/g')
|
||||||
|
|
||||||
|
if [[ ${COMP_CWORD} == 1 ]]; then
|
||||||
|
opts=$(python -c "from cafe.drivers.unittest.autocomplete import print_configs;print_configs()" 2>/dev/null)
|
||||||
|
elif [[ ${COMP_CWORD} == 2 ]]; then
|
||||||
|
COMPREPLY=( $(compgen -o filenames -A file "$cur") )
|
||||||
|
elif [[ ${cur} == -* ]]; then
|
||||||
|
opts="--help --test-types"
|
||||||
|
else
|
||||||
|
opts=$(python -c "from syntribos.runner import Runner;Runner.populate_tests();from syntribos.tests.base import test_table;from pprint import pprint;[pprint(i) for i in test_table.keys()]" 2>/dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${COMP_CWORD} -ne 2 ]]; then
|
||||||
|
opts=$(echo $opts|sed 's/\\/\\\\/g')
|
||||||
|
COMPREPLY=( $(compgen -W '${opts}' -- ${cur}) )
|
||||||
|
COMPREPLY="${COMPREPLY} "
|
||||||
|
fi
|
||||||
|
#sed for windows backslash
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
complete -o nospace -F _syntribos syntribos
|
6
setup.py
6
setup.py
|
@ -1,5 +1,5 @@
|
||||||
"""
|
"""
|
||||||
Copyright 2013 Rackspace
|
Copyright 2015 Rackspace
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -18,7 +18,7 @@ from setuptools import setup, find_packages
|
||||||
|
|
||||||
requires = open('pip-requires').readlines()
|
requires = open('pip-requires').readlines()
|
||||||
setup(
|
setup(
|
||||||
name='apiscan',
|
name='syntribos',
|
||||||
version='0.0.1',
|
version='0.0.1',
|
||||||
description=('API Security Scanner'),
|
description=('API Security Scanner'),
|
||||||
long_description='{0}\n\n{1}'.format(
|
long_description='{0}\n\n{1}'.format(
|
||||||
|
@ -31,6 +31,8 @@ setup(
|
||||||
install_requires=requires,
|
install_requires=requires,
|
||||||
license=open('LICENSE').read(),
|
license=open('LICENSE').read(),
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
|
entry_points={'console_scripts': [
|
||||||
|
'syntribos = syntribos.runner:entry_point']},
|
||||||
classifiers=(
|
classifiers=(
|
||||||
'Development Status :: 1 - Planning',
|
'Development Status :: 1 - Planning',
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
|
|
|
@ -1,92 +1,84 @@
|
||||||
import json
|
import json
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
from cafe.drivers.unittest.datasets import DatasetList
|
from cafe.engine.behaviors import BaseBehavior
|
||||||
|
|
||||||
|
|
||||||
class DynamicDataGen(DatasetList):
|
class FuzzBehavior(BaseBehavior):
|
||||||
strings = None
|
@classmethod
|
||||||
|
def fuzz_body(cls, strings, data, skip_var, name):
|
||||||
def __init__(self, name, data, ignore_var):
|
for str_num, stri in enumerate(strings, 1):
|
||||||
for stri in self.strings:
|
|
||||||
ctr = 0
|
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
for dic in self._build_combinations(
|
model_iter = cls._build_combinations(stri, data, skip_var)
|
||||||
name, stri, data, ignore_var):
|
|
||||||
self.append_new_dataset(
|
|
||||||
"{0}-{1}-{2}".format(self.test_name, name, ctr), {
|
|
||||||
"model": json.dumps(dic).replace(
|
|
||||||
ignore_var, "")})
|
|
||||||
ctr += 1
|
|
||||||
elif isinstance(data, ElementTree.Element):
|
elif isinstance(data, ElementTree.Element):
|
||||||
for element in self._build_xml_combinations(
|
model_iter = cls._build_xml_combinations(stri, data, skip_var)
|
||||||
name, stri, data, ignore_var):
|
|
||||||
self.append_new_dataset(
|
|
||||||
"{0}-{1}-{2}".format(self.test_name, name, ctr), {
|
|
||||||
"model": ElementTree.tostring(element).replace(
|
|
||||||
ignore_var, "")})
|
|
||||||
ctr += 1
|
|
||||||
else:
|
else:
|
||||||
raise TypeError("Format not recognized!")
|
raise TypeError("Format not recognized!")
|
||||||
|
for model_num, model in enumerate(model_iter, 1):
|
||||||
|
name = "{0}_str{1}_model{2}".format(name, str_num, model_num)
|
||||||
|
if isinstance(dict):
|
||||||
|
string = json.dumps(model)
|
||||||
|
else:
|
||||||
|
string = ElementTree.tostring(model)
|
||||||
|
string = string.replace(skip_var, "")
|
||||||
|
yield (name, string)
|
||||||
|
|
||||||
def _build_combinations(self, name, stri, dic, ignore_var):
|
@classmethod
|
||||||
|
def _build_combinations(cls, stri, dic, skip_var):
|
||||||
for key, val in dic.iteritems():
|
for key, val in dic.iteritems():
|
||||||
if ignore_var in key:
|
if skip_var in key:
|
||||||
continue
|
continue
|
||||||
elif isinstance(val, dict):
|
elif isinstance(val, dict):
|
||||||
for ret in self._build_combinations(
|
for ret in cls._build_combinations(stri, val, skip_var):
|
||||||
name, stri, val, ignore_var):
|
yield cls._merge_dictionaries(dic, {key: ret})
|
||||||
yield self._merge_dictionaries(dic, {key: ret})
|
|
||||||
elif isinstance(val, list):
|
elif isinstance(val, list):
|
||||||
for i, v in enumerate(val):
|
for i, v in enumerate(val):
|
||||||
list_ = [_ for _ in val]
|
list_ = [_ for _ in val]
|
||||||
if isinstance(v, dict):
|
if isinstance(v, dict):
|
||||||
for ret in self._build_combinations(
|
for ret in cls._build_combinations(stri, v, skip_var):
|
||||||
name, stri, v, ignore_var):
|
|
||||||
list_[i] = ret.copy()
|
list_[i] = ret.copy()
|
||||||
yield self._merge_dictionaries(dic, {key: list_})
|
yield cls._merge_dictionaries(dic, {key: list_})
|
||||||
else:
|
else:
|
||||||
list_[i] = stri
|
list_[i] = stri
|
||||||
yield self._merge_dictionaries(dic, {key: list_})
|
yield cls._merge_dictionaries(dic, {key: list_})
|
||||||
else:
|
else:
|
||||||
yield self._merge_dictionaries(dic, {key: stri})
|
yield cls._merge_dictionaries(dic, {key: stri})
|
||||||
|
|
||||||
def _merge_dictionaries(self, x, y):
|
@staticmethod
|
||||||
|
def _merge_dictionaries(x, y):
|
||||||
z = x.copy()
|
z = x.copy()
|
||||||
z.update(y)
|
z.update(y)
|
||||||
return z
|
return z
|
||||||
|
|
||||||
def _build_xml_combinations(self, name, stri, ele, ignore_var):
|
@classmethod
|
||||||
if ignore_var not in ele.tag:
|
def _build_xml_combinations(cls, stri, ele, skip_var):
|
||||||
|
if skip_var not in ele.tag:
|
||||||
if ele.text is not None:
|
if ele.text is not None:
|
||||||
yield self._update_element(ele, stri)
|
yield cls._update_element(ele, stri)
|
||||||
for attr in self._build_combinations(
|
for attr in cls._build_combinations(stri, ele.attrib, skip_var):
|
||||||
name, stri, ele.attrib, ignore_var):
|
yield cls._update_attribs(ele, attr)
|
||||||
yield self._update_attribs(ele, attr)
|
|
||||||
for i, element in enumerate(list(ele)):
|
for i, element in enumerate(list(ele)):
|
||||||
for ret in self._build_xml_combinations(
|
for ret in cls._build_xml_combinations(
|
||||||
name, stri, element, ignore_var):
|
stri, element, skip_var):
|
||||||
list_ = [_ for _ in ele.getchildren()]
|
list_ = [_ for _ in ele.getchildren()]
|
||||||
list_[i] = ret.copy()
|
list_[i] = ret.copy()
|
||||||
yield self._update_inner_element(ele, list_)
|
yield cls._update_inner_element(ele, list_)
|
||||||
|
|
||||||
def _update_element(self, ele, stri):
|
@staticmethod
|
||||||
|
def _update_element(ele, stri):
|
||||||
ret = ele.copy()
|
ret = ele.copy()
|
||||||
ret.text = stri
|
ret.text = stri
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _update_attribs(self, ele, attribs):
|
@staticmethod
|
||||||
|
def _update_attribs(ele, attribs):
|
||||||
ret = ele.copy()
|
ret = ele.copy()
|
||||||
ret.attrib = attribs
|
ret.attrib = attribs
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _update_inner_element(self, ele, list_):
|
@staticmethod
|
||||||
|
def _update_inner_element(ele, list_):
|
||||||
ret = ele.copy()
|
ret = ele.copy()
|
||||||
for i, v in enumerate(list_):
|
for i, v in enumerate(list_):
|
||||||
ret[i] = v
|
ret[i] = v
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class ExampleDynamicDataGen(DynamicDataGen):
|
|
||||||
strings = ["abc", "def"]
|
|
||||||
test_name = "Example"
|
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
from cafe.engine.behaviors import BaseBehavior
|
||||||
|
from cafe.engine.http.client import AutoMarshallingHTTPClient
|
||||||
|
|
||||||
|
from syntribos.extensions.rax_auth.models import auth_models
|
||||||
|
from syntribos.extensions.rax_auth.auth_config import (
|
||||||
|
UserAuthConfig, UserConfig)
|
||||||
|
|
||||||
|
|
||||||
|
class TokensBehavior(BaseBehavior):
|
||||||
|
@classmethod
|
||||||
|
def get_access_data_config(cls, user_config, userauth_config):
|
||||||
|
return cls.get_access_data(
|
||||||
|
url=user_config.endpoint or userauth_config.endpoint,
|
||||||
|
username=user_config.username,
|
||||||
|
password=user_config.password,
|
||||||
|
tenant_name=user_config.tenant_name,
|
||||||
|
tenant_id=user_config.tenant_id,
|
||||||
|
token=user_config.token,
|
||||||
|
api_key=user_config.api_key,
|
||||||
|
serialize_format=userauth_config.serialize_format,
|
||||||
|
deserialize_format=userauth_config.deserialize_format)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_access_data(cls, *args, **kwargs):
|
||||||
|
return cls.authenticate(*args, **kwargs).entity
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def authenticate(
|
||||||
|
cls, url, username=None, password=None, tenant_name=None,
|
||||||
|
tenant_id=None, token=None, api_key=None, rsa_key=None,
|
||||||
|
domain=None, serialize_format="json", deserialize_format="json"):
|
||||||
|
url = '{0}/tokens'.format(url)
|
||||||
|
client = AutoMarshallingHTTPClient(
|
||||||
|
serialize_format, deserialize_format)
|
||||||
|
|
||||||
|
client.default_headers["Content-Type"] = "application/{0}".format(
|
||||||
|
serialize_format)
|
||||||
|
client.default_headers["Accept"] = "application/{0}".format(
|
||||||
|
deserialize_format)
|
||||||
|
|
||||||
|
kwargs = {}
|
||||||
|
kwargs["tenant_name"] = tenant_name
|
||||||
|
kwargs["tenant_id"] = tenant_id
|
||||||
|
|
||||||
|
if password is not None:
|
||||||
|
kwargs["password_creds"] = auth_models.PasswordCredentials(
|
||||||
|
username=username, password=password)
|
||||||
|
|
||||||
|
if token is not None:
|
||||||
|
kwargs["token_creds"] = auth_models.Token(id_=token)
|
||||||
|
|
||||||
|
if api_key is not None:
|
||||||
|
kwargs["api_key_creds"] = auth_models.APIKeyCredentials(
|
||||||
|
username=username, api_key=api_key)
|
||||||
|
|
||||||
|
request_entity = auth_models.Auth(**kwargs)
|
||||||
|
|
||||||
|
r = client.request(
|
||||||
|
"POST", url, request_entity=request_entity,
|
||||||
|
response_entity_type=auth_models.AuthResponse)
|
||||||
|
if not r.ok:
|
||||||
|
raise Exception("Failed to authenticate")
|
||||||
|
|
||||||
|
r.entity = auth_models.AuthResponse.deserialize(
|
||||||
|
r.content, deserialize_format)
|
||||||
|
if r.entity is None:
|
||||||
|
raise Exception("Failed to parse Auth response Body")
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def get_access(section_name):
|
||||||
|
return TokensBehavior.get_access_data_config(
|
||||||
|
UserConfig(section_name=section_name), UserAuthConfig())
|
|
@ -0,0 +1,52 @@
|
||||||
|
from cafe.engine.models.data_interfaces import ConfigSectionInterface
|
||||||
|
|
||||||
|
|
||||||
|
class UserAuthConfig(ConfigSectionInterface):
|
||||||
|
SECTION_NAME = 'auth'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def endpoint(self):
|
||||||
|
return self.get("endpoint")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serialize_format(self):
|
||||||
|
return self.get("serialize_format", "json")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def deserialize_format(self):
|
||||||
|
return self.get("deserialize_format", "json")
|
||||||
|
|
||||||
|
|
||||||
|
class UserConfig(ConfigSectionInterface):
|
||||||
|
SECTION_NAME = 'user'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def username(self):
|
||||||
|
return self.get("username")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def password(self):
|
||||||
|
return self.get_raw("password")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def api_key(self):
|
||||||
|
return self.get_raw("api_key")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tenant_id(self):
|
||||||
|
return self.get("tenant_id")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tenant_name(self):
|
||||||
|
return self.get("tenant_name")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def token(self):
|
||||||
|
return self.get("token")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def endpoint(self):
|
||||||
|
"""Added to allow different users to auth at different endpoints. For
|
||||||
|
example the admin user needs to use an internal endpoint.
|
||||||
|
"""
|
||||||
|
return self.get("endpoint")
|
|
@ -0,0 +1,452 @@
|
||||||
|
import json
|
||||||
|
from xml.etree import ElementTree as ET
|
||||||
|
from cafe.engine.models.base import (
|
||||||
|
AutoMarshallingModel, AutoMarshallingListModel)
|
||||||
|
|
||||||
|
|
||||||
|
class V2_0Constants(object):
|
||||||
|
XML_NS = 'http://docs.openstack.org/identity/api/v2.0'
|
||||||
|
XML_NS_OPENSTACK_COMMON = 'http://docs.openstack.org/common/api/v1.0'
|
||||||
|
XML_NS_XSI = 'http://www.w3.org/2001/XMLSchema-instance'
|
||||||
|
XML_NS_OS_KSADM = \
|
||||||
|
'http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0'
|
||||||
|
XML_NS_OS_KSEC2 = \
|
||||||
|
'http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0'
|
||||||
|
XML_NS_RAX_KSQA = \
|
||||||
|
'http://docs.rackspace.com/identity/api/ext/RAX-KSQA/v1.0'
|
||||||
|
XML_NS_RAX_KSKEY = \
|
||||||
|
'http://docs.rackspace.com/identity/api/ext/RAX-KSKEY/v1.0'
|
||||||
|
XML_NS_RAX_AUTH = \
|
||||||
|
'http://docs.rackspace.com/identity/api/ext/RAX-AUTH/v1.0'
|
||||||
|
XML_NS_RAX_KSGRP = \
|
||||||
|
'http://docs.rackspace.com/identity/api/ext/RAX-KSGRP/v1.0'
|
||||||
|
XML_NS_ATOM = 'http://www.w3.org/2005/Atom'
|
||||||
|
|
||||||
|
|
||||||
|
class BaseIdentityModel(AutoMarshallingModel):
|
||||||
|
_namespaces = V2_0Constants
|
||||||
|
|
||||||
|
def __init__(self, kwargs):
|
||||||
|
super(BaseIdentityModel, self).__init__()
|
||||||
|
for var in kwargs:
|
||||||
|
if var != "self" and not var.startswith("_"):
|
||||||
|
setattr(self, var, kwargs.get(var))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _remove_xml_namespaces(cls, element):
|
||||||
|
for key, value in cls._namespaces.__dict__.items():
|
||||||
|
if key.startswith("__"):
|
||||||
|
continue
|
||||||
|
element = cls._remove_namespace(element, value)
|
||||||
|
return element
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _remove_namespace(cls, element, XML_NS):
|
||||||
|
return cls._remove_xml_etree_namespace(element, XML_NS)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _json_to_obj(cls, serialized_str):
|
||||||
|
data_dict = json.loads(serialized_str)
|
||||||
|
return cls._dict_to_obj(data_dict)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _xml_to_obj(cls, serialized_str):
|
||||||
|
element = ET.fromstring(serialized_str)
|
||||||
|
return cls._xml_ele_to_obj(
|
||||||
|
cls._remove_xml_namespaces(element))
|
||||||
|
|
||||||
|
def _obj_to_json(self):
|
||||||
|
return json.dumps(self._obj_to_dict())
|
||||||
|
|
||||||
|
def _obj_to_xml(self):
|
||||||
|
element = self._obj_to_xml_ele()
|
||||||
|
return ET.tostring(element)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _find(element, tag):
|
||||||
|
if element is None:
|
||||||
|
return ET.Element(None)
|
||||||
|
new_element = element.find(tag)
|
||||||
|
if new_element is None:
|
||||||
|
return ET.Element(None)
|
||||||
|
return new_element
|
||||||
|
|
||||||
|
|
||||||
|
class BaseIdentityListModel(AutoMarshallingListModel, BaseIdentityModel):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EmptyModel(object):
|
||||||
|
def _obj_to_dict(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _obj_to_xml_ele(self):
|
||||||
|
return ET.Element(None)
|
||||||
|
|
||||||
|
|
||||||
|
class AuthResponse(BaseIdentityModel):
|
||||||
|
def __init__(
|
||||||
|
self, token=None, service_catalog=None, user=None):
|
||||||
|
super(AuthResponse, self).__init__(locals())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _dict_to_obj(cls, data):
|
||||||
|
return cls(
|
||||||
|
token=AuthResponseToken._dict_to_obj(data.get("token")),
|
||||||
|
user=User._dict_to_obj(data.get("user")),
|
||||||
|
service_catalog=ServiceCatalog._dict_to_obj(
|
||||||
|
data.get("serviceCatalog")))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _json_to_obj(cls, serialized_str):
|
||||||
|
data = json.loads(serialized_str)
|
||||||
|
return cls._dict_to_obj(data.get("access"))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _xml_ele_to_obj(cls, element):
|
||||||
|
service_catalog = ServiceCatalog._xml_ele_to_obj(
|
||||||
|
cls._find(element, "serviceCatalog"))
|
||||||
|
return cls(
|
||||||
|
token=AuthResponseToken._xml_ele_to_obj(
|
||||||
|
cls._find(element, "token")),
|
||||||
|
user=User._xml_ele_to_obj(cls._find(element, "user")),
|
||||||
|
service_catalog=service_catalog)
|
||||||
|
|
||||||
|
def get_service(self, name):
|
||||||
|
for service in self.service_catalog:
|
||||||
|
if service.name == name:
|
||||||
|
return service
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class Tenant(BaseIdentityModel):
|
||||||
|
def __init__(self, name=None, id_=None):
|
||||||
|
super(Tenant, self).__init__(locals())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _xml_ele_to_obj(cls, element):
|
||||||
|
if element is None:
|
||||||
|
return cls()
|
||||||
|
return cls(
|
||||||
|
name=element.attrib.get("name"), id_=element.attrib.get("id"))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _dict_to_obj(cls, data):
|
||||||
|
if data is None:
|
||||||
|
return cls()
|
||||||
|
return cls(
|
||||||
|
name=data.get("name"), id_=data.get("id"))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _json_to_obj(cls, serialized_str):
|
||||||
|
data = json.loads(serialized_str)
|
||||||
|
return cls._dict_to_obj(data.get("tenant"))
|
||||||
|
|
||||||
|
|
||||||
|
class AuthResponseToken(BaseIdentityModel):
|
||||||
|
def __init__(
|
||||||
|
self, id_=None, expires=None, tenant=None, authenticated_by=None):
|
||||||
|
super(AuthResponseToken, self).__init__(locals())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _dict_to_obj(cls, data):
|
||||||
|
return cls(id_=data.get("id"),
|
||||||
|
expires=data.get("expires"),
|
||||||
|
tenant=Tenant._dict_to_obj(data.get("tenant")),
|
||||||
|
authenticated_by=data.get("RAX-AUTH:authenticatedBy"))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _xml_ele_to_obj(cls, element):
|
||||||
|
authenticated_by = cls._find(element, "authenticatedBy")
|
||||||
|
authenticated_by = authenticated_by.findtext("credential")
|
||||||
|
return cls(
|
||||||
|
id_=element.attrib.get("id"),
|
||||||
|
expires=element.attrib.get("expires"),
|
||||||
|
tenant=Tenant._xml_ele_to_obj(cls._find(element, "tenant")),
|
||||||
|
authenticated_by=authenticated_by)
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceCatalog(BaseIdentityListModel):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _dict_to_obj(cls, data):
|
||||||
|
return ServiceCatalog(
|
||||||
|
[Service._dict_to_obj(service) for service in data])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _xml_ele_to_obj(cls, element):
|
||||||
|
return ServiceCatalog(
|
||||||
|
[Service._xml_ele_to_obj(service) for service in element])
|
||||||
|
|
||||||
|
|
||||||
|
class User(BaseIdentityModel):
|
||||||
|
def __init__(
|
||||||
|
self, id_=None, name=None, roles=None,
|
||||||
|
rax_auth_default_region=None, rax_auth_federated=None):
|
||||||
|
super(User, self).__init__(locals())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _dict_to_obj(cls, data):
|
||||||
|
if data is None:
|
||||||
|
return cls()
|
||||||
|
region = data.get("RAX-AUTH:defaultRegion")
|
||||||
|
if isinstance(region, list):
|
||||||
|
region = region[0]
|
||||||
|
return cls(
|
||||||
|
id_=data.get("id"),
|
||||||
|
name=data.get("name"),
|
||||||
|
roles=Roles._dict_to_obj(data.get("roles")),
|
||||||
|
rax_auth_default_region=region,
|
||||||
|
rax_auth_federated=data.get("RAX-AUTH:federated"))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _xml_ele_to_obj(cls, element):
|
||||||
|
return cls(
|
||||||
|
id_=element.attrib.get("id"),
|
||||||
|
name=element.attrib.get("name"),
|
||||||
|
roles=Roles._xml_ele_to_obj(cls._find(element, "roles")),
|
||||||
|
rax_auth_default_region=element.attrib.get("defaultRegion"),
|
||||||
|
rax_auth_federated=element.attrib.get("federated"))
|
||||||
|
|
||||||
|
|
||||||
|
class Service(BaseIdentityModel):
|
||||||
|
def __init__(self, endpoints=None, name=None, type_=None):
|
||||||
|
super(Service, self).__init__(locals())
|
||||||
|
|
||||||
|
def get_endpoint(self, region):
|
||||||
|
"""
|
||||||
|
Returns the endpoint that matches the provided region,
|
||||||
|
or None if such an endpoint is not found
|
||||||
|
"""
|
||||||
|
for endpoint in self.endpoints:
|
||||||
|
if getattr(endpoint, "region"):
|
||||||
|
if str(endpoint.region).lower() == str(region).lower():
|
||||||
|
return endpoint
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _dict_to_obj(cls, data):
|
||||||
|
return cls(
|
||||||
|
endpoints=Endpoints._dict_to_obj(data.get("endpoints")),
|
||||||
|
name=data.get("name"), type_=data.get("type"))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _xml_ele_to_obj(cls, element):
|
||||||
|
return cls(
|
||||||
|
endpoints=Endpoints._xml_ele_to_obj(
|
||||||
|
element.findall("endpoint")),
|
||||||
|
name=element.attrib.get("name"),
|
||||||
|
type_=element.attrib.get("type"))
|
||||||
|
|
||||||
|
|
||||||
|
class Endpoints(BaseIdentityListModel):
|
||||||
|
@classmethod
|
||||||
|
def _xml_ele_to_obj(cls, elements):
|
||||||
|
if not elements:
|
||||||
|
return cls()
|
||||||
|
return cls([Endpoint._xml_ele_to_obj(endp) for endp in elements])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _dict_to_obj(cls, data):
|
||||||
|
if not data:
|
||||||
|
return cls()
|
||||||
|
return cls([Endpoint._dict_to_obj(endpoint) for endpoint in data])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _json_to_obj(cls, string):
|
||||||
|
data = json.loads(string)
|
||||||
|
return cls._dict_to_obj(data.get("endpoints"))
|
||||||
|
|
||||||
|
|
||||||
|
class Endpoint(BaseIdentityModel):
|
||||||
|
def __init__(self, id_=None, tenant_id=None, region=None, type_=None,
|
||||||
|
public_url=None, internal_url=None, admin_url=None,
|
||||||
|
version_id=None, version_info=None, version_list=None,
|
||||||
|
name=None):
|
||||||
|
super(Endpoint, self).__init__(locals())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _xml_ele_to_obj(cls, element):
|
||||||
|
version = element.find("version")
|
||||||
|
version_attrib = version.attrib if version is not None else {}
|
||||||
|
return cls(
|
||||||
|
id_=element.attrib.get("id"),
|
||||||
|
tenant_id=element.attrib.get("tenantId"),
|
||||||
|
region=element.attrib.get("region"),
|
||||||
|
type_=element.attrib.get("type"),
|
||||||
|
name=element.attrib.get("name"),
|
||||||
|
public_url=element.attrib.get("publicURL"),
|
||||||
|
internal_url=element.attrib.get("internalURL"),
|
||||||
|
admin_url=element.attrib.get("adminURL"),
|
||||||
|
version_id=version_attrib.get("id"),
|
||||||
|
version_info=version_attrib.get("info"),
|
||||||
|
version_list=version_attrib.get("list"))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _dict_to_obj(cls, data):
|
||||||
|
return cls(
|
||||||
|
id_=data.get("id"),
|
||||||
|
tenant_id=data.get("tenantId"),
|
||||||
|
region=data.get("region"),
|
||||||
|
type_=data.get("type"),
|
||||||
|
name=data.get("name"),
|
||||||
|
public_url=data.get("publicURL"),
|
||||||
|
internal_url=data.get("internalURL"),
|
||||||
|
admin_url=data.get("adminURL"),
|
||||||
|
version_id=data.get("versionId"),
|
||||||
|
version_info=data.get("versionInfo"),
|
||||||
|
version_list=data.get("versionList"))
|
||||||
|
|
||||||
|
|
||||||
|
class Roles(BaseIdentityListModel):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _xml_ele_to_obj(cls, elements):
|
||||||
|
return Roles(
|
||||||
|
[Role._xml_ele_to_obj(element) for element in elements])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _dict_to_obj(cls, data):
|
||||||
|
return Roles([Role._dict_to_obj(obj) for obj in data])
|
||||||
|
|
||||||
|
|
||||||
|
class Role(BaseIdentityModel):
|
||||||
|
def __init__(
|
||||||
|
self, id_=None, name=None, description=None,
|
||||||
|
rax_auth_propagate=None, tenant_id=None, service_id=None):
|
||||||
|
super(Role, self).__init__(locals())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _xml_ele_to_obj(cls, element):
|
||||||
|
if element is None:
|
||||||
|
return None
|
||||||
|
return cls(
|
||||||
|
id_=element.attrib.get("id"), name=element.attrib.get("name"),
|
||||||
|
description=element.attrib.get("description"),
|
||||||
|
rax_auth_propagate=element.attrib.get("propagate"),
|
||||||
|
service_id=element.attrib.get("serviceId"),
|
||||||
|
tenant_id=element.attrib.get("tenantId"))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _dict_to_obj(cls, data):
|
||||||
|
if data is None:
|
||||||
|
return None
|
||||||
|
return cls(
|
||||||
|
id_=data.get("id"), name=data.get("name"),
|
||||||
|
description=data.get("description"),
|
||||||
|
rax_auth_propagate=data.get("rax-auth:propagate"),
|
||||||
|
service_id=data.get("serviceId"),
|
||||||
|
tenant_id=data.get("tenantId"))
|
||||||
|
|
||||||
|
|
||||||
|
class Auth(BaseIdentityModel):
|
||||||
|
xmlns = V2_0Constants.XML_NS
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, password_creds=None, rsa_creds=None, token_creds=None,
|
||||||
|
api_key_creds=None, domain=None, tenant_name=None, tenant_id=None):
|
||||||
|
password_creds = password_creds or EmptyModel()
|
||||||
|
token_creds = token_creds or EmptyModel()
|
||||||
|
api_key_creds = api_key_creds or EmptyModel()
|
||||||
|
super(Auth, self).__init__(locals())
|
||||||
|
|
||||||
|
def _obj_to_dict(self):
|
||||||
|
attrs = {
|
||||||
|
"tenantName": self.tenant_name,
|
||||||
|
"tenantId": self.tenant_id,
|
||||||
|
"passwordCredentials": self.password_creds._obj_to_dict(),
|
||||||
|
"RAX-KSKEY:apiKeyCredentials": self.api_key_creds._obj_to_dict(),
|
||||||
|
"token": self.token_creds._obj_to_dict()}
|
||||||
|
return {'auth': self._remove_empty_values(attrs)}
|
||||||
|
|
||||||
|
def _obj_to_xml_ele(self):
|
||||||
|
element = ET.Element('auth')
|
||||||
|
element = self._set_xml_etree_element(
|
||||||
|
element, {"tenantName": self.tenant_name, "xmlns": self.xmlns,
|
||||||
|
"tenantId": self.tenant_id})
|
||||||
|
element.append(self.password_creds._obj_to_xml_ele())
|
||||||
|
element.append(self.rsa_creds._obj_to_xml_ele())
|
||||||
|
element.append(self.token_creds._obj_to_xml_ele())
|
||||||
|
element.append(self.api_key_creds._obj_to_xml_ele())
|
||||||
|
element.append(self.domain._obj_to_xml_ele())
|
||||||
|
return element
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordCredentials(BaseIdentityModel):
|
||||||
|
|
||||||
|
def __init__(self, username=None, password=None):
|
||||||
|
super(PasswordCredentials, self).__init__(locals())
|
||||||
|
|
||||||
|
def _obj_to_dict(self):
|
||||||
|
attrs = {"username": self.username, "password": self.password}
|
||||||
|
return self._remove_empty_values(attrs)
|
||||||
|
|
||||||
|
def _obj_to_xml_ele(self):
|
||||||
|
element = ET.Element('passwordCredentials')
|
||||||
|
attrs = {"username": self.username, "password": self.password}
|
||||||
|
return self._set_xml_etree_element(element, attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class Token(BaseIdentityModel):
|
||||||
|
def __init__(self, id_=None):
|
||||||
|
super(Token, self).__init__(locals())
|
||||||
|
|
||||||
|
def _obj_to_dict(self):
|
||||||
|
attrs = {"id": self.id_}
|
||||||
|
return self._remove_empty_values(attrs)
|
||||||
|
|
||||||
|
def _obj_to_xml_ele(self):
|
||||||
|
element = ET.Element('token')
|
||||||
|
attrs = {"id": self.id_}
|
||||||
|
return self._set_xml_etree_element(element, attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class APIKeyCredentials(BaseIdentityModel):
|
||||||
|
def __init__(self, username=None, api_key=None):
|
||||||
|
xmlns = V2_0Constants.XML_NS_RAX_KSKEY
|
||||||
|
super(APIKeyCredentials, self).__init__(locals())
|
||||||
|
|
||||||
|
def _obj_to_dict(self):
|
||||||
|
attrs = {"username": self.username, "apiKey": self.api_key}
|
||||||
|
return self._remove_empty_values(attrs)
|
||||||
|
|
||||||
|
def _obj_to_xml_ele(self):
|
||||||
|
element = ET.Element('apiKeyCredentials')
|
||||||
|
attrs = {
|
||||||
|
"username": self.username, "apiKey": self.api_key,
|
||||||
|
"xmlns": self.xmlns}
|
||||||
|
return self._set_xml_etree_element(element, attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class RSACredentials(BaseIdentityModel):
|
||||||
|
xmlns = V2_0Constants.XML_NS_RAX_AUTH
|
||||||
|
|
||||||
|
def __init__(self, username=None, rsa_key=None):
|
||||||
|
super(RSACredentials, self).__init__(locals())
|
||||||
|
|
||||||
|
def _obj_to_dict(self):
|
||||||
|
attrs = {"username": self.username, "tokenKey": self.rsa_key}
|
||||||
|
return self._remove_empty_values(attrs)
|
||||||
|
|
||||||
|
def _obj_to_xml_ele(self):
|
||||||
|
element = ET.Element('RAX-AUTH:rsaCredentials')
|
||||||
|
attrs = {
|
||||||
|
"username": self.username, "tokenKey": self.rsa_key,
|
||||||
|
"xmlns:RAX-AUTH": self.xmlns}
|
||||||
|
return self._set_xml_etree_element(element, attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class Domain(BaseIdentityModel):
|
||||||
|
xmlns = V2_0Constants.XML_NS_RAX_AUTH
|
||||||
|
|
||||||
|
def __init__(self, name=None):
|
||||||
|
super(Domain, self).__init__(locals())
|
||||||
|
|
||||||
|
def _obj_to_dict(self):
|
||||||
|
attrs = {"name": self.name}
|
||||||
|
return self._remove_empty_values(attrs)
|
||||||
|
|
||||||
|
def _obj_to_xml_ele(self):
|
||||||
|
element = ET.Element("RAX-AUTH:domain")
|
||||||
|
attrs = {"name": self.name, "xmlns:RAX-AUTH": self.xmlns}
|
||||||
|
return self._set_xml_etree_element(element, attrs)
|
|
@ -0,0 +1,45 @@
|
||||||
|
import urlparse
|
||||||
|
|
||||||
|
from cafe.engine.behaviors import BaseBehavior
|
||||||
|
|
||||||
|
|
||||||
|
class RequestObject(object):
|
||||||
|
def __init__(
|
||||||
|
self, method, url, headers=None, params=None, data=None):
|
||||||
|
self.method = method
|
||||||
|
self.url = url
|
||||||
|
self.headers = headers or {}
|
||||||
|
self.params = params or {}
|
||||||
|
self.data = data or ""
|
||||||
|
|
||||||
|
|
||||||
|
class RequestCreator(BaseBehavior):
|
||||||
|
@staticmethod
|
||||||
|
def _parse(string, endpoint):
|
||||||
|
params = None
|
||||||
|
lines = string.splitlines()
|
||||||
|
method, url, http_version = lines[0].split()
|
||||||
|
url = url.split("?", 1)
|
||||||
|
if len(url) > 1:
|
||||||
|
params = {}
|
||||||
|
for param in url[1].split("&"):
|
||||||
|
param = param.split("=", 1)
|
||||||
|
if len(param) > 1:
|
||||||
|
params[param[0]] = param[1]
|
||||||
|
else:
|
||||||
|
params[param[0]] = ""
|
||||||
|
url = url[0]
|
||||||
|
url = urlparse.urljoin(endpoint, url)
|
||||||
|
for index, line in enumerate(lines):
|
||||||
|
if line == "":
|
||||||
|
break
|
||||||
|
headers = {}
|
||||||
|
for line in lines[1:index]:
|
||||||
|
key, value = line.split(":", 1)
|
||||||
|
headers[key] = value.strip()
|
||||||
|
data = "\n".join(lines[index+1:])
|
||||||
|
return RequestObject(method, url, headers, params, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_request():
|
||||||
|
pass
|
|
@ -0,0 +1,141 @@
|
||||||
|
from __future__ import print_function
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import pkgutil
|
||||||
|
import requests
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from cafe.common.reporting.cclogging import init_root_log_handler
|
||||||
|
from cafe.configurator.managers import TestEnvManager
|
||||||
|
from cafe.drivers.unittest.arguments import ConfigAction
|
||||||
|
from cafe.drivers.base import print_exception
|
||||||
|
|
||||||
|
from syntribos import tests as package
|
||||||
|
#from syntribos.request_parser import RequestParser
|
||||||
|
|
||||||
|
|
||||||
|
class InputType(object):
|
||||||
|
def __init__(self, mode, bufsize):
|
||||||
|
self._mode = mode
|
||||||
|
self._bufsize = bufsize
|
||||||
|
|
||||||
|
def __call__(self, string):
|
||||||
|
if string == '-':
|
||||||
|
fp = sys.stdin
|
||||||
|
yield fp.name, fp.read()
|
||||||
|
elif os.path.isdir(string):
|
||||||
|
for path, _, files in os.walk(string):
|
||||||
|
for file_ in files:
|
||||||
|
file_path = os.path.join(path, file_)
|
||||||
|
fp = open(file_path, self._mode, self._bufsize)
|
||||||
|
yield file_path, fp.read()
|
||||||
|
fp.close()
|
||||||
|
elif os.path.isfile(string):
|
||||||
|
try:
|
||||||
|
fp = open(string, self._mode, self._bufsize)
|
||||||
|
yield fp.name, fp.read()
|
||||||
|
fp.close()
|
||||||
|
except Exception as e:
|
||||||
|
message = "can't open {}:{}"
|
||||||
|
raise Exception(message.format(string, e))
|
||||||
|
else:
|
||||||
|
message = "can't open {} not a readable file or dir"
|
||||||
|
raise Exception(message.format(string))
|
||||||
|
|
||||||
|
|
||||||
|
class SyntribosCLI(argparse.ArgumentParser):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(SyntribosCLI, self).__init__(*args, **kwargs)
|
||||||
|
self._add_args()
|
||||||
|
|
||||||
|
def _add_args(self):
|
||||||
|
self.add_argument(
|
||||||
|
"config", metavar="<config>", action=ConfigAction,
|
||||||
|
help="test config. Looks in the ~/.opencafe/configs directory."
|
||||||
|
"Example: compute/dev.environ")
|
||||||
|
|
||||||
|
self.add_argument(
|
||||||
|
"input", metavar="<input_file>", type=InputType('rb', 0),
|
||||||
|
help="<input file|directory of files|-(for stdin)>")
|
||||||
|
|
||||||
|
self.add_argument(
|
||||||
|
"-t", "--test_types", metavar="TEST_TYPES", nargs="*", default=[],
|
||||||
|
help="Test types to run against api")
|
||||||
|
|
||||||
|
|
||||||
|
class Runner(object):
|
||||||
|
@classmethod
|
||||||
|
def populate_tests(cls):
|
||||||
|
if not os.environ.get("CAFE_CONFIG_FILE_PATH"):
|
||||||
|
os.environ["CAFE_CONFIG_FILE_PATH"] = "/dev/null"
|
||||||
|
for importer, modname, ispkg in pkgutil.walk_packages(
|
||||||
|
path=package.__path__,
|
||||||
|
prefix=package.__name__ + '.',
|
||||||
|
onerror=lambda x: None):
|
||||||
|
__import__(modname, fromlist=[])
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def print_symbol():
|
||||||
|
""" Syntribos radiation symbol """
|
||||||
|
border = '-' * 40
|
||||||
|
symbol = """
|
||||||
|
Syntribos
|
||||||
|
xxxxxxx
|
||||||
|
x xxxxxxxxxxxxx x
|
||||||
|
x xxxxxxxxxxx x
|
||||||
|
xxxxxxxxx
|
||||||
|
x xxxxxxx x
|
||||||
|
xxxxx
|
||||||
|
x xxx x
|
||||||
|
x
|
||||||
|
xxxxxxxxxxxxxxx xxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxx xxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxx xxxxxxxxxxx
|
||||||
|
xxxxxxxxx xxxxxxxxx
|
||||||
|
xxxxxx xxxxxx
|
||||||
|
xxx xxx
|
||||||
|
x x
|
||||||
|
x
|
||||||
|
=== Automated API Scanning ==="""
|
||||||
|
|
||||||
|
print(border)
|
||||||
|
print(symbol)
|
||||||
|
print(border)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def print_log():
|
||||||
|
test_log = os.environ.get("CAFE_TEST_LOG_PATH")
|
||||||
|
if test_log:
|
||||||
|
print("=" * 150)
|
||||||
|
print("LOG PATH..........: {0}".format(test_log))
|
||||||
|
print("=" * 150)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run(cls):
|
||||||
|
requests.packages.urllib3.disable_warnings()
|
||||||
|
try:
|
||||||
|
cls.print_symbol()
|
||||||
|
usage = """
|
||||||
|
syntribos <config> <input_file> --test-types=TEST_TYPES
|
||||||
|
syntribos <config> <input_file> -t TEST_TYPE TEST_TYPE ...
|
||||||
|
syntribos <config> <input_file>
|
||||||
|
"""
|
||||||
|
args, unknown = SyntribosCLI(usage=usage).parse_known_args()
|
||||||
|
test_env_manager = TestEnvManager(
|
||||||
|
"", args.config, test_repo_package_name="os")
|
||||||
|
test_env_manager.finalize()
|
||||||
|
cls.print_log()
|
||||||
|
init_root_log_handler()
|
||||||
|
cls.populate_tests()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print_exception(
|
||||||
|
file_="runner.py", method="entry_point", exception=e)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def entry_point():
|
||||||
|
return Runner.run()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
entry_point()
|
|
@ -0,0 +1,78 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
from cafe.engine.models.data_interfaces import ConfigSectionInterface
|
||||||
|
from cafe.engine.http.client import HTTPClient
|
||||||
|
|
||||||
|
|
||||||
|
data_dir = os.environ.get("CAFE_DATA_DIR_PATH")
|
||||||
|
test_table = {}
|
||||||
|
|
||||||
|
|
||||||
|
class TestType(type):
|
||||||
|
def __new__(cls, cls_name, cls_parents, cls_attr):
|
||||||
|
new_class = super(TestType, cls).__new__(
|
||||||
|
cls, cls_name, cls_parents, cls_attr)
|
||||||
|
test_name = getattr(new_class, "test_name", None)
|
||||||
|
if test_name is not None:
|
||||||
|
if test_name in test_table:
|
||||||
|
msg = "Test name already used {}".format(test_name)
|
||||||
|
raise Exception(msg)
|
||||||
|
test_table[test_name] = new_class
|
||||||
|
return new_class
|
||||||
|
|
||||||
|
|
||||||
|
class BaseConfig(ConfigSectionInterface):
|
||||||
|
SECTION_NAME = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def percent(self):
|
||||||
|
return self.get("percent")
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTest(object):
|
||||||
|
"""
|
||||||
|
Base for building new tests
|
||||||
|
"""
|
||||||
|
__metaclass__ = TestType
|
||||||
|
test_name = None
|
||||||
|
test_type = None
|
||||||
|
filename = None
|
||||||
|
config = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate_test(cls, response):
|
||||||
|
return all([
|
||||||
|
response.status_code < 500,
|
||||||
|
cls.validate_length(response, cls.config.percent)])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_strings(cls):
|
||||||
|
path = os.path.join(data_dir, cls.filename)
|
||||||
|
return open(path, "rb")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate_length(cls, response, percent=5):
|
||||||
|
if getattr(cls, "init_response", False) is False:
|
||||||
|
raise NotImplemented
|
||||||
|
resp_len = len(response.content)
|
||||||
|
req_len = len(response.request.data)
|
||||||
|
iresp_len = len(cls.init_response.content)
|
||||||
|
ireq_len = len(cls.init_response.request.data)
|
||||||
|
request_diff = req_len - ireq_len
|
||||||
|
response_diff = resp_len - iresp_len
|
||||||
|
if request_diff == response_diff:
|
||||||
|
return True
|
||||||
|
elif resp_len == iresp_len:
|
||||||
|
return True
|
||||||
|
elif percent:
|
||||||
|
if abs(float(response_diff) / iresp_len) <= (percent / 100.0):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run_test(cls, request, init_response):
|
||||||
|
client = HTTPClient()
|
||||||
|
r = client.request(
|
||||||
|
method=request.method, url=request.url, headers=request.headers,
|
||||||
|
params=request.params, data=request.data)
|
||||||
|
return cls.validate_test(r, init_response)
|
|
@ -0,0 +1,23 @@
|
||||||
|
from syntribos.tests.base import BaseTest, BaseConfig
|
||||||
|
|
||||||
|
|
||||||
|
class SQLInjectionBody(BaseTest):
|
||||||
|
test_name = "SQL_INJECTION_BODY"
|
||||||
|
test_type = "BODY"
|
||||||
|
filename = "sql-injection.txt"
|
||||||
|
config = BaseConfig(section_name=test_name)
|
||||||
|
|
||||||
|
|
||||||
|
class SQLInjectionParams(SQLInjectionBody):
|
||||||
|
test_name = "SQL_INJECTION_PARAMS"
|
||||||
|
test_type = "PARAMS"
|
||||||
|
|
||||||
|
|
||||||
|
class SQLInjectionHeaders(SQLInjectionBody):
|
||||||
|
test_name = "SQL_INJECTION_HEADERS"
|
||||||
|
test_type = "HEADERS"
|
||||||
|
|
||||||
|
|
||||||
|
class SQLInjectionURL(SQLInjectionBody):
|
||||||
|
test_name = "SQL_INJECTION_URL"
|
||||||
|
test_type = "URL"
|
Loading…
Reference in New Issue