OpenSecurity/bin/opensecurity_client_restful_server.py
changeset 134 f1c1c06c947d
parent 130 f770f1b2abf7
child 136 ac117cd7bab1
     1.1 --- a/OpenSecurity/bin/opensecurity_client_restful_server.py	Thu Apr 24 12:19:30 2014 +0200
     1.2 +++ b/OpenSecurity/bin/opensecurity_client_restful_server.py	Tue Apr 29 13:00:46 2014 +0200
     1.3 @@ -32,6 +32,7 @@
     1.4  # ------------------------------------------------------------
     1.5  # imports
     1.6  
     1.7 +import json
     1.8  import os
     1.9  import os.path
    1.10  import subprocess
    1.11 @@ -44,7 +45,6 @@
    1.12  
    1.13  # local
    1.14  from environment import Environment
    1.15 -from notification import Notification
    1.16  
    1.17  
    1.18  # ------------------------------------------------------------
    1.19 @@ -56,8 +56,8 @@
    1.20  
    1.21  """All the URLs we know mapping to class handler"""
    1.22  opensecurity_urls = (
    1.23 -    #'/application',             'os_application',
    1.24      '/credentials',             'os_credentials',
    1.25 +    '/keyfile',                 'os_keyfile',
    1.26      '/notification',            'os_notification',
    1.27      '/password',                'os_password',
    1.28      '/',                        'os_root'
    1.29 @@ -68,56 +68,8 @@
    1.30  # code
    1.31  
    1.32  
    1.33 -# class os_application:
    1.34 -#
    1.35 -# PRESUMLY DEAD CODE
    1.36 -#
    1.37 -    # """OpenSecurity '/application' handler.
    1.38 -    
    1.39 -    # This is called on GET /application?vm=VM-ID&app=APP-ID
    1.40 -    # This tries to access the vm identified with the label VM-ID
    1.41 -    # and launched the application identified APP-ID
    1.42 -    # """
    1.43 -    
    1.44 -    # def GET(self):
    1.45 -        
    1.46 -        # # pick the arguments
    1.47 -        # args = web.input()
    1.48 -        
    1.49 -        # # we _need_ a vm
    1.50 -        # if not "vm" in args:
    1.51 -            # raise web.badrequest('no vm given')
    1.52 -        
    1.53 -        # # we _need_ a app
    1.54 -        # if not "command" in args:
    1.55 -            # raise web.badrequest('no app given')
    1.56 -        
    1.57 -        # # check if we do have valid vm
    1.58 -        # v = [v for v in vms if v['name'] == args.vm]
    1.59 -        # if len(v) == 0:
    1.60 -            # raise web.notfound('vm not found')
    1.61 -        # v = v[0]
    1.62 -        
    1.63 -        # # check if we do have a valid app
    1.64 -        # a = [a for a in apps if a['name'] == args.app]
    1.65 -        # if len(a) == 0:
    1.66 -            # raise web.notfound('app not found')
    1.67 -        # a = a[0]
    1.68 -        
    1.69 -        # # invoke launch with 
    1.70 -        # res = "starting: launch " + v['user'] + " " + v['ip'] + " " + a['command']
    1.71 +class os_credentials:
    1.72  
    1.73 -        # launch_image = os.path.join(sys.path[0], 'launch.py')
    1.74 -        # process_command = [sys.executable, launch_image, v['user'], v['ip'], a['command']]
    1.75 -        # process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)
    1.76 -        # result = process.communicate()[0]
    1.77 -        # if process.returncode != 0:
    1.78 -            # return 'Launch of application aborted.'
    1.79 -        
    1.80 -        # return result
    1.81 -        
    1.82 -
    1.83 -class os_credentials:
    1.84      """OpenSecurity '/credentials' handler.
    1.85      
    1.86      This is called on GET /credentials?text=TEXT.
    1.87 @@ -134,18 +86,56 @@
    1.88          if not "text" in args:
    1.89              raise web.badrequest('no text given')
    1.90          
    1.91 -        # invoke the user dialog as a subprocess
    1.92 -        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.py')
    1.93 +        # remember remote ip
    1.94 +        remote_ip = web.ctx.environ['REMOTE_ADDR']
    1.95 +
    1.96 +        # create the process which queries the user
    1.97 +        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.pyw')
    1.98          process_command = [sys.executable, dlg_image, 'credentials', args.text]
    1.99 -        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)
   1.100 -        result = process.communicate()[0]
   1.101 -        if process.returncode != 0:
   1.102 -            return 'Credentials request has been aborted.'
   1.103 +        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)        
   1.104          
   1.105 -        return result
   1.106 +        # run process result handling in seprate thread (not to block main one)
   1.107 +        bouncer = UserResultBouncer(process, remote_ip, '/credentials')
   1.108 +        bouncer.start()
   1.109 +         
   1.110 +        return 'user queried for credentials'
   1.111 +
   1.112 +
   1.113 +class os_keyfile:
   1.114 +
   1.115 +    """OpenSecurity '/keyfile' handler.
   1.116 +    
   1.117 +    This is called on GET /keyfile?text=TEXT.
   1.118 +    Ideally this should pop up a user dialog to insert his
   1.119 +    password along with a keyfile.
   1.120 +    """
   1.121 +    
   1.122 +    def GET(self):
   1.123 +        
   1.124 +        # pick the arguments
   1.125 +        args = web.input()
   1.126 +        
   1.127 +        # we _need_ a text
   1.128 +        if not "text" in args:
   1.129 +            raise web.badrequest('no text given')
   1.130 +            
   1.131 +        # remember remote ip
   1.132 +        remote_ip = web.ctx.environ['REMOTE_ADDR']
   1.133 +        
   1.134 +        # create the process which queries the user
   1.135 +        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.pyw')
   1.136 +        process_command = [sys.executable, dlg_image, 'keyfile', args.text]
   1.137 +        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)        
   1.138 +        
   1.139 +        # run process result handling in seprate thread (not to block main one)
   1.140 +        bouncer = UserResultBouncer(process, remote_ip, '/keyfile')
   1.141 +        bouncer.start()
   1.142 +         
   1.143 +        return 'user queried for password and keyfile'
   1.144  
   1.145  
   1.146  class os_notification:
   1.147 +
   1.148      """OpenSecurity '/notification' handler.
   1.149      
   1.150      This is called on GET /notification?msgtype=TYPE&text=TEXT.
   1.151 @@ -157,14 +147,11 @@
   1.152          # pick the arguments
   1.153          args = web.input()
   1.154          
   1.155 -        if "message" in args:
   1.156 -            print args.message
   1.157 -        
   1.158          # we _need_ a type
   1.159          if not "msgtype" in args:
   1.160              raise web.badrequest('no msgtype given')
   1.161              
   1.162 -        if not args.msgtype in Notification.TYPES:
   1.163 +        if not args.msgtype in ['information', 'warning', 'critical']:
   1.164              raise web.badrequest('Unknown value for msgtype')
   1.165              
   1.166          # we _need_ a text
   1.167 @@ -175,47 +162,12 @@
   1.168          dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.py')
   1.169          process_command = [sys.executable, dlg_image, 'notification-' + args.msgtype, args.text]
   1.170          process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)
   1.171 +
   1.172          return "Ok"
   1.173  
   1.174 -class PasswordSender(threading.Thread):
   1.175 -    remote_ip = None
   1.176 -    args = None
   1.177 -    def __init__(self, remote_ip, args): 
   1.178 -        threading.Thread.__init__(self)
   1.179 -        self.args = args
   1.180 -        self.remote_ip = remote_ip
   1.181 - 
   1.182 -    def stop(self):
   1.183 -        self.running = False
   1.184 -        
   1.185 -    def run(self):
   1.186 -        # invoke the user dialog as a subprocess
   1.187 -        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.py')
   1.188 -        process_command = [sys.executable, dlg_image, 'password', self.args.text]
   1.189 -        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)
   1.190 -        result = process.communicate()[0]
   1.191 -        if process.returncode != 0:
   1.192 -            print 'password request has been aborted.'
   1.193 -            return
   1.194 -        
   1.195 -        # all ok, tell send request back appropriate destination
   1.196 -        try:
   1.197 -            password = result.split(':')[1].split("'")[1]
   1.198 -        except:
   1.199 -            print 'error in password parsing'
   1.200 -            return
   1.201 -        
   1.202 -        url_addr = 'http://' + self.remote_ip + ':58080/password'
   1.203 -        url_data = urllib.urlencode({ 'password': password})
   1.204 -        url = url_addr + '?' + url_data
   1.205 -        req = urllib2.Request(url)
   1.206 -        try:
   1.207 -            res = urllib2.urlopen(req)
   1.208 -        except:
   1.209 -            print 'failed to contact: ' + url_addr
   1.210 -            return 
   1.211  
   1.212  class os_password:
   1.213 +
   1.214      """OpenSecurity '/password' handler.
   1.215      
   1.216      This is called on GET /password?text=TEXT.
   1.217 @@ -235,13 +187,20 @@
   1.218          # remember remote ip
   1.219          remote_ip = web.ctx.environ['REMOTE_ADDR']
   1.220          
   1.221 -        sender = PasswordSender(remote_ip, args)
   1.222 -        sender.start()
   1.223 +        # create the process which queries the user
   1.224 +        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.pyw')
   1.225 +        process_command = [sys.executable, dlg_image, 'password', args.text]
   1.226 +        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)        
   1.227          
   1.228 -        return 'password told'
   1.229 +        # run process result handling in seprate thread (not to block main one)
   1.230 +        bouncer = UserResultBouncer(process, remote_ip, '/password')
   1.231 +        bouncer.start()
   1.232 +        
   1.233 +        return 'user queried for password'
   1.234  
   1.235  
   1.236  class os_root:
   1.237 +
   1.238      """OpenSecurity '/' handler"""
   1.239      
   1.240      def GET(self):
   1.241 @@ -271,6 +230,15 @@
   1.242      NOTE: check yout taskbar, the dialog window may not pop up in front of your browser window.
   1.243      
   1.244  
   1.245 +Request a combination of password and keyfile:
   1.246 +    (copy paste this into your browser's address field after the host:port)
   1.247 +    
   1.248 +    /keyfile?text=Your%20private%20RSA%20Keyfile%3A
   1.249 +    
   1.250 +    (eg.: http://127.0.0.1:8090//keyfile?text=Your%20private%20RSA%20Keyfile%3A)
   1.251 +    NOTE: check yout taskbar, the dialog window may not pop up in front of your browser window.
   1.252 +    
   1.253 +
   1.254  Start a Browser:
   1.255      (copy paste this into your browser's address field after the host:port)
   1.256  
   1.257 @@ -282,7 +250,57 @@
   1.258          return res
   1.259  
   1.260  
   1.261 +class UserResultBouncer(threading.Thread):
   1.262 +
   1.263 +    """A class to spawn off user I/O waiting and push the data back to the requesting services."""
   1.264 +
   1.265 +    def __init__(self, process, remote_ip, resource): 
   1.266 +
   1.267 +        """ctor"""
   1.268 +
   1.269 +        threading.Thread.__init__(self)
   1.270 +        self._process = process
   1.271 +        self._remote_ip = remote_ip
   1.272 +        self._resource = resource
   1.273 + 
   1.274 +    
   1.275 +    def stop(self):
   1.276 +
   1.277 +        """stop thread"""
   1.278 +        self.running = False
   1.279 +        
   1.280 +    
   1.281 +    def run(self):
   1.282 +
   1.283 +        """run the thread"""
   1.284 +
   1.285 +        # invoke the user dialog as a subprocess
   1.286 +        result = self._process.communicate()[0]
   1.287 +        if self._process.returncode != 0:
   1.288 +            print 'user request has been aborted.'
   1.289 +            return
   1.290 +        
   1.291 +        # all ok, tell send request back appropriate destination
   1.292 +        try:
   1.293 +            j = json.loads(result)
   1.294 +        except:
   1.295 +            print 'error in password parsing'
   1.296 +            return
   1.297 +        
   1.298 +        # TODO: it would be WAY easier and secure if we just 
   1.299 +        #       add the result json to a HTTP-POST here.
   1.300 +        url_addr = 'http://' + self._remote_ip + ':58080' + self._resource
   1.301 +        url = url_addr + '?' + urllib.urlencode(j)
   1.302 +        req = urllib2.Request(url)
   1.303 +        try:
   1.304 +            res = urllib2.urlopen(req)
   1.305 +        except:
   1.306 +            print 'failed to contact: ' + url_addr
   1.307 +            return 
   1.308 +
   1.309 +
   1.310  # start
   1.311  if __name__ == "__main__":
   1.312      server = web.application(opensecurity_urls, globals())
   1.313      server.run()
   1.314 +