def __init__(self, base_url, lookup, ent_path, ent_info, flowdir, test_script, path2port=None, mako_dir='', port_min=60000, port_max=61000, test_tool_conf=''): self.baseurl = base_url self.lookup = lookup self.ent_path = ent_path self.ent_info = ent_info self.flowdir = flowdir self.path2port = path2port self.mako_dir = mako_dir self.test_tool_conf = test_tool_conf self.test_script = test_script self.assigned_ports = AssignedPorts('assigned_ports.json', port_min, port_max) self.assigned_ports.load() self.running_processes = self.assigned_ports.sync(test_script) # self.ent_path = ent_path self.rest = REST(base_url, ent_path, ent_info) sys.path.insert(0, ".") ttc = importlib.import_module(test_tool_conf) self.test_tool_base = ttc.BASE if not self.test_tool_base.endswith('/'): self.test_tool_base += '/'
def test_port(): pmin = 60000 pmax = 60004 # test_script, flowdir, rest, port_min, port_max, # test_tool_base, test_tool_conf, prehtml, app = AssignedPorts('assport', pmin, pmax) _port1 = app.register_port(quote_plus('https://example.com'), 'one') assert _port1 == pmin _port2 = app.register_port(quote_plus('https://example.com'), 'two') assert _port2 != _port1 assert pmin < _port2 <= pmax _port3 = app.register_port(quote_plus('https://example.com'), 'three') assert _port3 not in [_port1, _port2] assert pmin < _port3 <= pmax _port4 = app.register_port(quote_plus('https://example.com'), 'four') assert _port4 not in [_port1, _port2, _port3] assert pmin < _port4 <= pmax _port5 = app.register_port(quote_plus('https://example.com'), 'five') assert _port5 not in [_port1, _port2, _port3, _port4] assert pmin < _port4 <= pmax try: _ = app.register_port(quote_plus('https://example.com'), 'six') except OutOfRange: assert True else: assert False del app[app.make_key('https://example.com', 'three')] _port6 = app.register_port(quote_plus('https://example.com'), 'six') assert _port6 not in [_port1, _port2, _port4, _port5] assert pmin < _port4 <= pmax
def test_port_ass(): fname = 'assport2.json' f = open(fname, 'w') f.write(json.dumps(PORT_INFO)) f.close() dup = find_duplicates(fname) if dup: ap = AssignedPorts(fname, 60000, 61000) ap.load() for port, iss_list in dup.items(): print(port) for iss in iss_list[1:]: # let the first one keep the port del ap[iss] ap.register_port(*iss.split('][')) dup = find_duplicates(fname) assert dup == {}
if args.path: if _conf.baseurl.endswith('/'): _base_url = '{}{}/'.format(_conf.baseurl, args.path) else: _base_url = '{}/{}/'.format(_conf.BASE_URL, args.path) elif args.port: if _conf.BASE_URL.endswith('/'): _base_url = '{}:{}/'.format(_conf.BASE_URL[:-1], args.port) else: _base_url = '{}:{}/'.format(_conf.BASE_URL, args.port) else: _base_url = _conf.BASE_URL rest = REST(_base_url) _assigned_ports = AssignedPorts('assigned_ports.json', _conf.PORT_MIN, _conf.PORT_MAX) _assigned_ports.load() _vers = get_version() cherrypy.tree.mount( Entity(_conf.ENT_PATH, _html, rest, _assigned_ports, _ttc.BASE, version=_vers), '/entity') _app = Application(_conf.TEST_SCRIPT, _conf.FLOWDIR, rest, _assigned_ports, _ttc.BASE, args.test_tool_conf, args.htmldir) cherrypy.tree.mount( Action(rest, _ttc, _html, _conf.ENT_PATH, _conf.ENT_INFO, tool_params, _app, version=_vers), '/action')
res = {'tool': tool} if cli_reg: res["client"] = {"registration_response": cli_reg} if prov_info: try: res['client']['provider_info'] = prov_info except KeyError: res['client'] = {'provider_info': prov_info} return port, res if __name__ == '__main__': sys.path.insert(0, '.') rest = REST('', '../entities') assigned_port = AssignedPorts('../aasigned_ports', 60000, 64000) for fil in sys.argv[1:]: if fil.endswith('.py'): print(fil) port, cnf = convert(fil[:-3]) try: iss = cnf['tool']['issuer'] except KeyError: iss = cnf['client']['provider_info']['issuer'] qiss = quote_plus(iss.lower()) if qiss.startswith('http'): qtag = quote_plus(cnf['tool']['tag']) fname = rest.entity_file_name(qiss, qtag) _key = '{}:{}'.format(qiss, qtag) if not os.path.isfile(fname):
class Application(object): def __init__(self, base_url, lookup, ent_path, ent_info, flowdir, test_script, path2port=None, mako_dir='', port_min=60000, port_max=61000, test_tool_conf=''): self.baseurl = base_url self.lookup = lookup self.ent_path = ent_path self.ent_info = ent_info self.flowdir = flowdir self.path2port = path2port self.mako_dir = mako_dir self.test_tool_conf = test_tool_conf self.test_script = test_script self.assigned_ports = AssignedPorts('assigned_ports.json', port_min, port_max) self.assigned_ports.load() self.running_processes = self.assigned_ports.sync(test_script) # self.ent_path = ent_path self.rest = REST(base_url, ent_path, ent_info) sys.path.insert(0, ".") ttc = importlib.import_module(test_tool_conf) self.test_tool_base = ttc.BASE if not self.test_tool_base.endswith('/'): self.test_tool_base += '/' def get_pid(self, parts): lp = [unquote_plus(p) for p in parts] qp = [quote_plus(p) for p in lp] try: return self.running_processes[self.key(*qp)] except KeyError: return 0 def return_port(self, qiss, qtag): """ Unmake an assignment. That is return an assigned port to the free list. :param qiss: quoted identifier :param qtag: quoted tag """ try: del self.assigned_ports[self.assigned_ports.make_key(qiss, qtag)] except KeyError: pass def run_test_instance(self, iss, tag): _port = self.assigned_ports.register_port(iss, tag) args = [ self.test_script, "-i", unquote_plus(iss), "-t", unquote_plus(tag), "-p", str(_port), "-M", self.mako_dir, "-f", self.flowdir ] if self.path2port: args.extend(["-m", self.path2port]) ppmap = read_path2port_map(self.path2port) try: _path = ppmap[str(_port)] except KeyError: _errtxt = 'Port not in path2port map file {}'.format( self.path2port) logger.error(_errtxt) return ServiceError(_errtxt) url = '{}{}'.format(self.test_tool_base, _path) else: url = '{}:{}'.format(self.test_tool_base[:-1], _port) typ, _econf = self.rest.read_conf(iss, tag) if _econf['tool']['insecure']: args.append('-k') args.append(self.test_tool_conf) # If already running - kill try: pid = isrunning(unquote_plus(iss), unquote_plus(tag)) except KeyError: pass else: if pid: logger.info('kill {}'.format(pid)) subprocess.call(['kill', str(pid)]) # Now get it running args.append('&') logger.info("Test tool command: {}".format(" ".join(args))) # spawn independent process os.system(" ".join(args)) pid = 0 for i in range(0, 10): time.sleep(1) pid = isrunning(unquote_plus(iss), unquote_plus(tag)) if pid: break if pid: logger.info("process id: {}".format(pid)) self.running_processes[self.key(iss, tag)] = pid return url else: return None def form_handling(self, path, io): iss, tag = get_iss_and_tag(path) if path == 'form/init': resp = Response() return io.new_iss() elif path.startswith('form/create'): return io.new_instance(iss, tag) elif path.startswith('form/update'): return io.update_instance(iss, tag) elif path.startswith('form/delete'): return io.delete_instance(iss, tag, pid=self.get_pid([iss, tag]), app=self) else: resp = NotFound() return resp(io.environ, io.start_response) def basic_entity_configuration(self, io): q = parse_qs(io.environ.get('QUERY_STRING')) # construct profile profile = to_profile(q) _ent_conf = create_model(profile, ent_info_path=self.ent_info) state = {} if not do_discovery(profile): _ent_conf['client']['provider_info']['issuer'] = q['iss'][0] if not do_registration(profile): # need to create a redirect_uri, means I need to register a port _port = self.assigned_ports.register_port(q['iss'][0], q['tag'][0]) _ent_conf['client']['registration_response'][ 'redirect_uris'] = '{}:{}/authz_cb'.format( self.test_tool_base[:-1], _port) _ent_conf['tool']['tag'] = q['tag'][0] _ent_conf['tool']['issuer'] = q['iss'][0] _ent_conf['tool']['profile'] = profile _qiss = quote_plus(q['iss'][0]) _qtag = quote_plus(q['tag'][0]) io.rest.write(_qiss, _qtag, _ent_conf) return '{}form/update/{}/{}'.format(self.baseurl, _qiss, _qtag) def application(self, environ, start_response): logger.info("Connection from: %s" % environ["REMOTE_ADDR"]) path = environ.get('PATH_INFO', '').lstrip('/') logger.info("path: %s" % path) _io = IO(rest=self.rest, environ=environ, start_response=start_response, lookup=self.lookup, baseurl=self.baseurl) if path == "robots.txt": return _io.static("static/robots.txt") elif path == "favicon.ico": return _io.static("static/favicon.ico") elif path.startswith("static/"): return _io.static(path) elif path.startswith("export/"): return _io.static(path) if path == '': return _io.main() if path == 'new': return _io.new_iss() if path == 'entity': return _io.list_iss() elif path.startswith('entity/'): p = path.split('/') while p[-1] == '': p = p[:-1] if len(p) == 2: return _io.list_tag(p[1]) elif len(p) == 3: return _io.show_tag(p) elif len(p) == 4: _com = p[-1] if _com == 'action': _qs = parse_qs(environ.get('QUERY_STRING')) try: _act = _qs['action'][0] except KeyError: resp = BadRequest('missing query parameter') return resp(environ, start_response) if _act == 'delete': return _io.delete_instance(p[1:3], pid=self.get_pid(p[1:3]), app=self) elif _act == 'restart': return _io.restart_instance(self, p[1:3]) elif _act == 'configure': return _io.update_instance(*p[1:3]) else: resp = BadRequest('Unknown action') return resp(environ, start_response) elif path.startswith('form/'): return self.form_handling(path, _io) elif path == 'create': loc = self.basic_entity_configuration(_io) resp = SeeOther(loc) return resp(_io.environ, _io.start_response) elif path.startswith('run/'): _iss, _tag = get_iss_and_tag(path) if _iss == '' or _tag == '': resp = BadRequest('Path must be of the form /run/<iss>/<tag>') return resp(environ, start_response) _qiss = quote_plus(_iss) _qtag = quote_plus(_tag) _info = parse_qs(get_post(environ)) ent_conf = expand_dict(_info) if not verify_config(ent_conf): resp = BadRequest('Incorrect configuration') else: self.rest.write(_qiss, _qtag, ent_conf) resp = self.run_test_instance(_qiss, _qtag) if not isinstance(resp, Response): resp = SeeOther(resp) return resp(_io.environ, _io.start_response) elif path.startswith('model/'): p = path.split('/') prof = p[1] if verify_profile(prof): info = create_model(prof) if info: res = Response(json.dumps(info), content='applicaton/json') else: res = ServiceError() else: res = BadRequest('Syntax error in profile specification') return res(environ, start_response) elif path.startswith('register/'): _iss, _tag = get_iss_and_tag(path) _qiss = quote_plus(_iss) _qtag = quote_plus(_tag) _met = environ.get('REQUEST_METHOD') if _met == 'GET': return self.assigned_ports.register_port(_qiss, _qtag) elif _met == 'DELETE': return self.return_port(_qiss, _qtag) else: # check if this a REST request _iss, _tag = get_iss_and_tag(path) _qiss = quote_plus(_iss) _qtag = quote_plus(_tag) _path = '/{}/{}'.format(_qiss, _qtag) _met = environ.get('REQUEST_METHOD') if _met == 'GET': resp = self.rest.read(_qiss, _qtag, _path) elif _met == 'POST': resp = self.rest.replace(_qiss, _qtag, get_post(environ), _path) elif _met == 'PUT': resp = self.rest.store(_qiss, _qtag, get_post(environ)) elif _met == 'DELETE': resp = self.rest.delete(_qiss, _qtag) else: resp = BadRequest('Unsupported request method') return resp(environ, start_response)
class Application(object): def __init__(self, base_url, lookup, ent_path, ent_info, flowdir, test_script, path2port=None, mako_dir='', port_min=60000, port_max=61000, test_tool_conf=''): self.baseurl = base_url self.lookup = lookup self.ent_path = ent_path self.ent_info = ent_info self.flowdir = flowdir self.path2port = path2port self.mako_dir = mako_dir self.test_tool_conf = test_tool_conf self.test_script = test_script self.assigned_ports = AssignedPorts('assigned_ports.json', port_min, port_max) self.assigned_ports.load() self.running_processes = self.assigned_ports.sync(test_script) # self.ent_path = ent_path self.rest = REST(base_url, ent_path, ent_info) sys.path.insert(0, ".") ttc = importlib.import_module(test_tool_conf) self.test_tool_base = ttc.BASE if not self.test_tool_base.endswith('/'): self.test_tool_base += '/' def get_pid(self, parts): lp = [unquote_plus(p) for p in parts] qp = [quote_plus(p) for p in lp] try: return self.running_processes[self.key(*qp)] except KeyError: return 0 def return_port(self, qiss, qtag): """ Unmake an assignment. That is return an assigned port to the free list. :param qiss: quoted identifier :param qtag: quoted tag """ try: del self.assigned_ports[self.assigned_ports.make_key(qiss, qtag)] except KeyError: pass def run_test_instance(self, iss, tag): _port = self.assigned_ports.register_port(iss, tag) args = [self.test_script] args.extend(["-i", shlex.quote(unquote_plus(iss))]) args.extend(["-t", shlex.quote(unquote_plus(tag))]) args.extend(["-p", str(_port)]) args.extend(["-M", self.mako_dir]) args.extend(["-f", self.flowdir]) if self.path2port: args.extend(["-m", self.path2port]) ppmap = read_path2port_map(self.path2port) try: _path = ppmap[str(_port)] except KeyError: _errtxt = 'Port not in path2port map file {}'.format( self.path2port) logger.error(_errtxt) return ServiceError(_errtxt) url = '{}{}'.format(self.test_tool_base, _path) else: url = '{}:{}'.format(self.test_tool_base[:-1], _port) typ, _econf = self.rest.read_conf(iss, tag) if _econf['tool']['insecure']: args.append('-k') args.append(self.test_tool_conf) # If already running - kill try: pid = isrunning(unquote_plus(iss), unquote_plus(tag)) except KeyError: pass else: if pid: logger.info('kill {}'.format(pid)) subprocess.call(['kill', str(pid)]) # Now get it running args.append('&') cmd = " ".join(args) logger.info("Test tool command: {}".format(cmd)) # spawn independent process os.system(cmd) pid = 0 for i in range(0,10): time.sleep(1) pid = isrunning(unquote_plus(iss), unquote_plus(tag)) if pid: break if pid: logger.info("process id: {}".format(pid)) self.running_processes[self.key(iss, tag)] = pid return url else: return None def form_handling(self, path, io): iss, tag = get_iss_and_tag(path) if path == 'form/init': resp = Response() return io.new_iss() elif path.startswith('form/create'): return io.new_instance(iss, tag) elif path.startswith('form/update'): return io.update_instance(iss, tag) elif path.startswith('form/delete'): return io.delete_instance(iss, tag, pid=self.get_pid([iss, tag]), app=self) else: resp = NotFound() return resp(io.environ, io.start_response) def basic_entity_configuration(self, io): q = parse_qs(io.environ.get('QUERY_STRING')) # construct profile profile = to_profile(q) _ent_conf = create_model(profile, ent_info_path=self.ent_info) state = {} if not do_discovery(profile): _ent_conf['client']['provider_info']['issuer'] = q['iss'][0] if not do_registration(profile): # need to create a redirect_uri, means I need to register a port _port = self.assigned_ports.register_port(q['iss'][0], q['tag'][0]) _ent_conf['client']['registration_response'][ 'redirect_uris'] = '{}:{}/authz_cb'.format( self.test_tool_base[:-1], _port) _ent_conf['tool']['tag'] = q['tag'][0] _ent_conf['tool']['issuer'] = q['iss'][0] _ent_conf['tool']['profile'] = profile _qiss = quote_plus(q['iss'][0]) _qtag = quote_plus(q['tag'][0]) io.rest.write(_qiss, _qtag, _ent_conf) return '{}form/update/{}/{}'.format(self.baseurl, _qiss, _qtag) def application(self, environ, start_response): logger.info("Connection from: %s" % environ["REMOTE_ADDR"]) path = environ.get('PATH_INFO', '').lstrip('/') logger.info("path: %s" % path) _io = IO(rest=self.rest, environ=environ, start_response=start_response, lookup=self.lookup, baseurl=self.baseurl) if path == "robots.txt": return _io.static("static/robots.txt") elif path == "favicon.ico": return _io.static("static/favicon.ico") elif path.startswith("static/"): return _io.static(path) elif path.startswith("export/"): return _io.static(path) if path == '': return _io.main() if path == 'new': return _io.new_iss() if path == 'entity': return _io.list_iss() elif path.startswith('entity/'): p = path.split('/') while p[-1] == '': p = p[:-1] if len(p) == 2: return _io.list_tag(p[1]) elif len(p) == 3: return _io.show_tag(p) elif len(p) == 4: _com = p[-1] if _com == 'action': _qs = parse_qs(environ.get('QUERY_STRING')) try: _act = _qs['action'][0] except KeyError: resp = BadRequest('missing query parameter') return resp(environ, start_response) if _act == 'delete': return _io.delete_instance(p[1:3], pid=self.get_pid(p[1:3]), app=self) elif _act == 'restart': return _io.restart_instance(self, p[1:3]) elif _act == 'configure': return _io.update_instance(*p[1:3]) else: resp = BadRequest('Unknown action') return resp(environ, start_response) elif path.startswith('form/'): return self.form_handling(path, _io) elif path == 'create': loc = self.basic_entity_configuration(_io) resp = SeeOther(loc) return resp(_io.environ, _io.start_response) elif path.startswith('run/'): _iss, _tag = get_iss_and_tag(path) if _iss == '' or _tag == '': resp = BadRequest('Path must be of the form /run/<iss>/<tag>') return resp(environ, start_response) _qiss = quote_plus(_iss) _qtag = quote_plus(_tag) _info = parse_qs(get_post(environ)) ent_conf = expand_dict(_info) if not verify_config(ent_conf): resp = BadRequest('Incorrect configuration') else: self.rest.write(_qiss, _qtag, ent_conf) resp = self.run_test_instance(_qiss, _qtag) if not isinstance(resp, Response): resp = SeeOther(resp) return resp(_io.environ, _io.start_response) elif path.startswith('model/'): p = path.split('/') prof = p[1] if verify_profile(prof): info = create_model(prof) if info: res = Response(json.dumps(info), content='applicaton/json') else: res = ServiceError() else: res = BadRequest('Syntax error in profile specification') return res(environ, start_response) elif path.startswith('register/'): _iss, _tag = get_iss_and_tag(path) _qiss = quote_plus(_iss) _qtag = quote_plus(_tag) _met = environ.get('REQUEST_METHOD') if _met == 'GET': return self.assigned_ports.register_port(_qiss, _qtag) elif _met == 'DELETE': return self.return_port(_qiss, _qtag) else: # check if this a REST request _iss, _tag = get_iss_and_tag(path) _qiss = quote_plus(_iss) _qtag = quote_plus(_tag) _path = '/{}/{}'.format(_qiss, _qtag) _met = environ.get('REQUEST_METHOD') if _met == 'GET': resp = self.rest.read(_qiss, _qtag, _path) elif _met == 'POST': resp = self.rest.replace(_qiss, _qtag, get_post(environ), _path) elif _met == 'PUT': resp = self.rest.store(_qiss, _qtag, get_post(environ)) elif _met == 'DELETE': resp = self.rest.delete(_qiss, _qtag) else: resp = BadRequest('Unsupported request method') return resp(environ, start_response)
#!/usr/bin/env python3 import json from urllib.parse import quote_plus from oidctest.app_conf import REST from oidctest.ass_port import AssignedPorts old = REST('', entpath='entities') old_info = old.items() present = REST('', entpath='entities.present') present_info = present.items() assigned_port = AssignedPorts('./assigned_ports.json', 60001, 64000) assigned_port.load() pap = AssignedPorts('./assigned_ports.json.present', 60001, 64000) pap.load() def new_port(iss, tag, proposal=0): _k = pap.make_key(iss, tag) _p = 0 if proposal: if proposal not in assigned_port.values(): _p = proposal else: print("!!!! Can't use proposed port") if not _p: try: _p = pap[_k] except KeyError:
res = {'tool': tool} if cli_reg: res["client"] = {"registration_response": cli_reg} if prov_info: try: res['client']['provider_info'] = prov_info except KeyError: res['client'] = {'provider_info': prov_info} return port, res if __name__ == '__main__': sys.path.insert(0, '.') rest = REST('', '../entities') assigned_port = AssignedPorts('../assigned_ports.json', 60000, 64000) for fil in sys.argv[1:]: if fil.endswith('.py'): print(fil) port, cnf = convert(fil[:-3]) try: iss = cnf['tool']['issuer'] except KeyError: iss = cnf['client']['provider_info']['issuer'] qiss = quote_plus(iss.lower()) if iss.startswith('http'): qtag = quote_plus(cnf['tool']['tag']) fname = rest.entity_file_name(qiss, qtag) _key = assigned_port.make_key(iss, cnf['tool']['tag']) if not os.path.isfile(fname):
from urllib.parse import quote_plus, unquote_plus from oidctest.ass_port import AssignedPorts def print_conf(c): iss, tag = c.split('][', 2) fname = os.path.join('entities', quote_plus(unquote_plus(iss)), quote_plus(unquote_plus(tag))) cnf = json.loads(open(fname, 'r').read()) print(">>>", fname) print(json.dumps(cnf, sort_keys=True, indent=2, separators=(',', ': '))) folder = os.path.abspath(os.curdir) ap = AssignedPorts('{}/assigned_ports.json'.format(folder), 0, 0) ap.load() #info = open('assigned_ports.json').read() #ap = json.loads(info) inv_ap = dict([(v, k) for k, v in ap.items()]) parser = argparse.ArgumentParser() parser.add_argument('-d', dest='delete') parser.add_argument('-p', dest='port', type=int) parser.add_argument('-l', dest='list', action='store_true') parser.add_argument('-m', dest='match') parser.add_argument('-o', dest='open', action="store_true") args = parser.parse_args()
import os from urllib.parse import quote_plus, unquote_plus from oidctest.ass_port import AssignedPorts def print_conf(c): iss, tag = c.split('][', 2) fname= os.path.join('entities', quote_plus(unquote_plus(iss)), quote_plus(unquote_plus(tag))) cnf = json.loads(open(fname,'r').read()) print(">>>", fname) print(json.dumps(cnf, sort_keys=True, indent=2, separators=(',', ': '))) folder = os.path.abspath(os.curdir) ap = AssignedPorts('{}/assigned_ports.json'.format(folder),0,0) ap.load() #info = open('assigned_ports.json').read() #ap = json.loads(info) inv_ap = dict([(v, k) for k, v in ap.items()]) parser = argparse.ArgumentParser() parser.add_argument('-d', dest='delete') parser.add_argument('-p', dest='port', type=int) parser.add_argument('-l', dest='list', action='store_true') parser.add_argument('-m', dest='match') parser.add_argument('-o', dest='open', action="store_true") args = parser.parse_args()