123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- import http.server
- import urllib.parse
- import json
- import re
- import ssl, socket
- import ISC
- import pprint
- import select
- import csv
- import random
- from hashlib import sha1
- try:
- import threading
- except ImportError:
- import dummy_threading as threading
- URL_PATTERN = re.compile('/([\w]+)(?:/([\w]+))?/?')
-
- class SecureHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
- '''
- Process GET and POST
- '''
-
- def parse_path(self, path):
- groups = URL_PATTERN.match(path)
- if not groups:
- return (NULL, NULL)
- return (groups.group(1), groups.group(2))
- def check_username(self,name):
- reader = csv.reader(open("passwd.csv"), delimiter="\t", quoting=csv.QUOTE_MINIMAL)
- for row in reader:
- if name==row[0]:
- self.user=[row[0],row[1],row[2]]
- return 1
- return 0
- def check(self):
- length = self.headers.get('content-length')
- nbytes = int(length)
- user_info = json.loads((self.rfile.read(nbytes)).decode())
- if not user_info:
- return ["error: invalid username or password"], http.client.UNAUTHORIZED
- if not self.check_username(user_info['username']):
- return ["error:the username doesn't exists"], http.client.UNAUTHORIZED
- if sha1((user_info['password'] + self.user[2]).encode()).hexdigest() != self.user[1] :
- return ["error:the username and passwd did not match!"], http.client.UNAUTHORIZED
- else :
- id = self.headers.get('cookie')
- self.server.session[id]['username'] = user_info['username']
- return ["login sucess !"], http.client.OK
- def do_GET(self):
- id = self.headers.get('cookie')
- if id not in self.server.session:
- self.server.session[id]={}
-
- reply_value = []
- if "username" not in self.server.session[id]:
- reply_value = ["please post username and passwd"]
- else:
- identifier, module = self.parse_path(self.path)
- if identifier != None:
- data = self.server.get_reply_data_for_GET(identifier, module)
- if data:
- reply_value = data
- self.send_response(200)
- self.end_headers()
- self.wfile.write(json.dumps(reply_value).encode())
-
- def do_POST(self):
- id = self.headers.get('cookie')
- if id not in self.server.session:
- self.server.session[id] = {}
- reply_msg = []
- rcode = 200
- if self.path == '/':
- reply_msg, rcode = self.check()
- elif "username" not in self.server.session[id]:
- reply_msg, rcode = ["please login!"], http.client.UNAUTHORIZED
- else:
- mod, cmd = self.parse_path(self.path)
- param = None
- len = self.headers.get('Content-Length')
- if len:
- post_str = str(self.rfile.read(int(len)).decode())
- print("command parameter:%s" % post_str)
- param = json.loads(post_str)
- reply_msg = self.server.send_command_to_module(mod, cmd, param)
- print('cmd-ctrld finish send message \'%s\' to module %s' % (cmd, mod))
-
- #TODO, set proper rcode
- self.send_response(rcode)
- self.end_headers()
- self.wfile.write(json.dumps(reply_msg).encode())
- class CommandControl():
- def __init__(self):
- self.cc = ISC.CC.Session()
- self.cc.group_subscribe('Cmd-Ctrld')
- self.cc.group_subscribe('Boss', 'Cmd-Ctrld')
- self.command_spec = self.get_cmd_specification()
- self.config_spec = self.get_data_specification()
- self.config_data = self.get_config_data()
- def get_cmd_specification(self):
- return self.send_command('ConfigManager', 'get_commands')
- def get_config_data(self):
- return self.send_command('ConfigManager', 'get_config')
- def update_config_data(self, module_name, command_name):
- if module_name == 'ConfigManager' and command_name == 'set_config':
- self.config_data = self.get_config_data()
- def get_data_specification(self):
- return self.send_command('ConfigManager', 'get_data_spec')
- def handle_recv_msg(self):
- # Handle received message, if 'shutdown' is received, return False
- (message, env) = self.cc.group_recvmsg(True)
- while message:
- if 'commands_update' in message:
- self.command_spec[message['commands_update'][0]] = message['commands_update'][1]
- elif 'specification_update' in message:
- msgvalue = message['specification_update']
- self.config_spec[msgvalue[0]] = msgvalue[1]
- elif 'command' in message and message['command'][0] == 'shutdown':
- return False;
- (message, env) = self.cc.group_recvmsg(True)
-
- return True
-
- def send_command(self, module_name, command_name, params = None):
- content = [command_name]
- if params:
- content.append(params)
- msg = {'command' : content}
- print('cmd-ctrld send command \'%s\' to %s' %(command_name, module_name))
- try:
- # Do special for Boss shutdown. TODO, avoid specicialism
- if module_name == 'Boss' and command_name == 'shutdown':
- self.cc.group_sendmsg(msg, module_name, 'boss')
- return {}
- self.cc.group_sendmsg(msg, module_name)
- answer, env = self.cc.group_recvmsg(False)
- if answer and 'result' in answer.keys() and type(answer['result']) == list:
- # TODO: with the new cc implementation, replace "1" by 1
- if answer['result'][0] == "1":
- # todo: exception
- print("Error: " + str(answer['result'][1]))
- return {}
- else:
- self.update_config_data(module_name, command_name)
- if len(answer['result']) > 1:
- return answer['result'][1]
- return {}
- else:
- print("Error: unexpected answer from %s" % module_name)
- except Exception as e:
- print(e)
- print('cmd-ctrld fail send command \'%s\' to %s' % (command_name, module_name))
- return {}
- class SecureHTTPServer(http.server.HTTPServer):
- def __init__(self, server_address, RequestHandlerClass):
- http.server.HTTPServer.__init__(self, server_address, RequestHandlerClass)
- self.session = {}
- self.cmdctrl = CommandControl()
- self.__is_shut_down = threading.Event()
- self.__serving = False
- def get_request(self):
- newsocket, fromaddr = self.socket.accept()
- try:
- connstream = ssl.wrap_socket(newsocket,
- server_side = True,
- certfile = 'create_your_cert.pem',
- keyfile = 'create_your_cert.pem',
- ssl_version = ssl.PROTOCOL_SSLv23)
- return (connstream, fromaddr)
- except ssl.SSLError as e :
- print("error happen***********")
- print(e)
-
-
- def get_reply_data_for_GET(self, id, module_name):
- if module_name is None:
- if id == 'command_spec':
- return self.cmdctrl.command_spec
- elif id == 'config_data':
- return self.cmdctrl.config_data
- elif id == 'config_spec':
- return self.cmdctrl.config_spec
- else:
- return None
- def serve_forever(self, poll_interval = 0.5):
- self.__serving = True
- self.__is_shut_down.clear()
- while self.__serving:
- if not self.cmdctrl.handle_recv_msg():
- break
- r, w, e = select.select([self], [], [], poll_interval)
- if r:
- self._handle_request_noblock()
- self.__is_shut_down.set()
-
- def shutdown(self):
- self.__serving = False
- self.__is_shut_down.wait()
- def send_command_to_module(self, module_name, command_name, params):
- return self.cmdctrl.send_command(module_name, command_name, params)
- def run(server_class = SecureHTTPServer, addr = 'localhost', port = 8080):
- print("cmd-ctrld module is starting on :%s port:%d" %(addr, port))
- httpd = server_class((addr, port), SecureHTTPRequestHandler)
- httpd.serve_forever()
- if __name__ == '__main__':
- try:
- run()
- except ISC.CC.SessionError as se:
- print("[cmd-ctrld] Error creating cmd-ctrld, "
- "is the command channel daemon running?")
- except KeyboardInterrupt:
- print("exit http server")
-
|