OpenSecurity/bin/opensecurityd.pyw
author BarthaM@N3SIM1218.D03.arc.local
Fri, 29 Aug 2014 10:56:26 +0100
changeset 219 9480e5ba1a82
parent 213 2e0b94e12bfc
child 220 f5805ee62d80
permissions -rwxr-xr-x
Improoved the update functionality:
- Additional validation of template existance
- Faster termination of worker threads
- Forced template folder cleanup
- etc.
     1 #!/bin/env python
     2 # -*- coding: utf-8 -*-
     3 
     4 # ------------------------------------------------------------
     5 # opensecurityd
     6 #   
     7 # the opensecurityd as RESTful server
     8 #
     9 # Autor: Oliver Maurhart, <oliver.maurhart@ait.ac.at>
    10 #        Mihai Bartha, <mihai.bartha@ait.ac.at>       
    11 #
    12 # Copyright (C) 2013 AIT Austrian Institute of Technology
    13 # AIT Austrian Institute of Technology GmbH
    14 # Donau-City-Strasse 1 | 1220 Vienna | Austria
    15 # http://www.ait.ac.at
    16 #
    17 # This program is free software; you can redistribute it and/or
    18 # modify it under the terms of the GNU General Public License
    19 # as published by the Free Software Foundation version 2.
    20 # 
    21 # This program is distributed in the hope that it will be useful,
    22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
    23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    24 # GNU General Public License for more details.
    25 # 
    26 # You should have received a copy of the GNU General Public License
    27 # along with this program; if not, write to the Free Software
    28 # Foundation, Inc., 51 Franklin Street, Fifth Floor, 
    29 # Boston, MA  02110-1301, USA.
    30 # ------------------------------------------------------------
    31 
    32 
    33 # ------------------------------------------------------------
    34 # imports
    35 
    36 import json
    37 import os
    38 import os.path
    39 import subprocess
    40 import sys
    41 import tempfile
    42 import web
    43 
    44 import vmmanager
    45 
    46 # local
    47 import __init__ as opensecurity
    48 from cygwin import Cygwin
    49 from environment import Environment
    50 from opensecurity_util import logger, showTrayMessage
    51 
    52 
    53 
    54 # ------------------------------------------------------------
    55 # const
    56 
    57 """All the URLs we know mapping to class handler"""
    58 opensecurity_urls = (
    59     '/browsing',                        'os_browsing',          # http://localhost:8080/browsing                                GET
    60     '/fetch_initial_image',             'os_fetch_image',       # http://localhost:8080/fetch_initial_image                     GET
    61     '/init',                            'os_init',              # http://localhost:8080/init                                    GET
    62     '/initial_image',                   'os_initial_image',     # http://localhost:8080/initial_image                           GET
    63     '/sdvms',                           'os_sdvms',             # http://localhost:8080/sdvms                                   GET, PUT
    64     '/sdvms/(.*)/application/(.*)',     'os_sdvm_application',  # http://localhost:8080/sdvms/[VMNAME]/application/[COMMAND]    GET
    65     '/sdvms/(.*)/ip',                   'os_sdvm_ip',           # http://localhost:8080/sdvms/[VMNAME]/ip                       GET
    66     '/sdvms/(.*)/start',                'os_sdvm_start',        # http://localhost:8080/sdvms/[VMNAME]/start                    GET
    67     '/sdvms/(.*)/stop',                 'os_sdvm_stop',         # http://localhost:8080/sdvms/[VMNAME]/stop                     GET
    68     '/sdvms/(.*)',                      'os_sdvm',              # http://localhost:8080/sdvms/[VMNAME]                          GET, DELETE
    69     '/setup',                           'os_setup',             # http://localhost:8080/setup                                   GET
    70     '/vms',                             'os_vms',               # http://localhost:8080/vms                                     GET
    71     '/vms/(.*)',                        'os_vm',                # http://localhost:8080/vms/[VMNAME]                            GET
    72     '/update_template',                 'os_update_template',   # http://localhost:8080/update_template                         GET
    73     '/terminate',                       'os_terminate',         # http://localhost:8080/terminate                               GET
    74     '/initialize',                      'os_initialize',        # http://localhost:8080/initialize                               GET
    75     '/',                                'os_root'               # http://localhost:8080/                                        GET
    76 )
    77 
    78 
    79 # ------------------------------------------------------------
    80 # vars
    81 
    82 # Global VMManager instance
    83 gvm_mgr = None
    84 
    85 # server instance
    86 server = None
    87 
    88 
    89 # ------------------------------------------------------------
    90 # code
    91 
    92 
    93 class os_browsing:
    94     """OpenSecurity '/browsing' handler
    95     
    96     - GET: Start and prepare a new SecurityVM for Internet Browsing. Return the name of the VM.
    97     """
    98     
    99     def GET(self):
   100         args = web.input()
   101         log_call(web.ctx.environ)
   102         global gvm_mgr
   103         try:
   104             proxy = None
   105             if 'ProxyServer' in args:
   106                 proxy = args['ProxyServer']
   107             result = gvm_mgr.handleBrowsingRequest(proxy)
   108             return result
   109         except:
   110             raise web.internalerror()
   111 
   112        
   113 class os_fetch_image:
   114     """OpenSecurity '/fetch_initial_image' handler
   115     
   116     - GET: fetch the initial image from the X-Net Servers
   117             The initial image is stored in the
   118             Virtual Box default machine path.
   119             The result to this call is a temprary file
   120             which shows the progress (or error state)
   121             of this call.
   122     """
   123     
   124     def GET(self):
   125         
   126         log_call(web.ctx.environ)
   127         global gvm_mgr
   128 
   129         trace_file_name = os.path.join(Environment('OpenSecurity').log_path, 'OpenSecurity_fetch_image.log')
   130         trace_file = open(trace_file_name, 'w+')
   131 
   132         machine_folder = Cygwin.cygPath(gvm_mgr.getMachineFolder()) 
   133         download_initial_image_script = Cygwin.cygPath(os.path.abspath(os.path.join(os.path.split(__file__)[0], 'download_initial_image.sh')))
   134         Cygwin.bashExecute('\\"' + download_initial_image_script + '\\" \'' + machine_folder + '\'', wait_return = False, stdout = trace_file, stderr = trace_file) 
   135 
   136         res = '{ "fetch_log": "' + trace_file_name.replace('\\', '\\\\') + '" }'
   137         return res
   138 
   139 
   140 class os_init:
   141     """OpenSecurity '/init' handler
   142     
   143     - GET: Do initial import of OsecVM.ova
   144     """
   145     
   146     def GET(self):
   147         log_call(web.ctx.environ)
   148         global gvm_mgr
   149 
   150         gvm_mgr.stop()
   151         gvm_mgr.cleanup()
   152         
   153         if gvm_mgr.vmRootName in gvm_mgr.listVM():
   154             gvm_mgr.poweroffVM(gvm_mgr.vmRootName)
   155             tmplateUUID = gvm_mgr.getTemplateUUID()
   156             if tmplateUUID != None:
   157                 logger.debug('found parent uuid ' + tmplateUUID)
   158                 gvm_mgr.detachStorage(gvm_mgr.vmRootName)
   159                 gvm_mgr.removeSnapshots(tmplateUUID)
   160                 gvm_mgr.removeImage(tmplateUUID)
   161             else:
   162                 logger.debug('parent uuid not found')
   163             gvm_mgr.removeVM(gvm_mgr.vmRootName)
   164         gvm_mgr.removeVMFolder(gvm_mgr.vmRootName)
   165         
   166         trace_file_name = os.path.join(Environment('OpenSecurity').log_path, 'OpenSecurity_initial_import.log')
   167         trace_file = open(trace_file_name, 'w+')
   168 
   169         vm_image = Cygwin.cygPath(gvm_mgr.getMachineFolder()) + '/OsecVM.ova'
   170         initial_import_script = Cygwin.cygPath(os.path.abspath(os.path.join(os.path.split(__file__)[0], 'initial_vm.sh')))
   171         Cygwin.bashExecute('\\"' + initial_import_script + '\\" \'' + vm_image + '\'', wait_return = False, stdout = trace_file, stderr = trace_file) 
   172         gvm_mgr.start()
   173         res = '{ "init_log": "' + trace_file_name.replace('\\', '\\\\') + '" }'
   174         return res
   175 
   176 
   177 class os_initial_image:
   178     """OpenSecurity '/initial_image' handler
   179     
   180     - GET: Return what we have as initial image.
   181     """
   182     
   183     def GET(self):
   184         log_call(web.ctx.environ)
   185         global gvm_mgr
   186         t = os.path.join(gvm_mgr.systemProperties['Default machine folder'], 'OsecVM.ova')
   187         res = ''
   188         if os.path.isfile(t):
   189             res = '{"initial_template": { '
   190             res += '"name": "OsecVM.ova", '
   191             res += '"path": "' + t.replace('\\', '\\\\') + '", '
   192             res += '"size": ' + str(os.path.getsize(t)) + ', ' 
   193             res += '"date": ' + str(os.path.getmtime(t)) + ''
   194             res += '}}'
   195         return res
   196 
   197 
   198 class os_root:
   199     """OpenSecurity '/' handler
   200     
   201     - GET: give information about current installation.
   202     """
   203     
   204     def GET(self):
   205         log_call(web.ctx.environ)
   206         global gvm_mgr
   207 
   208         # create a json string and pretty print it
   209         res = '{"os_server": { '
   210         res += '"version": "' + opensecurity.__version__ + '" '
   211         res += ', "virtual box systemproperties": ' + str(gvm_mgr.systemProperties).replace("'", '"') 
   212         res += ', "current temporary folder": "' + tempfile.gettempdir().replace('\\', '\\\\') + '"'
   213         res += ', "current log folder": "' + Environment('OpenSecurity').log_path.replace('\\', '\\\\') + '"'
   214 
   215         try:
   216             res += ', "whoami": "' + Cygwin.bashExecute('whoami')[1].strip() + '"'
   217         except:
   218             res += ', "whoami": "FAILED"'
   219 
   220         try:
   221             res += ', "mount": ' + str(Cygwin.bashExecute('mount')[1].split('\n')[:-1]).replace("'", '"')
   222         except:
   223             res += ', "mount": "FAILED"'
   224 
   225         try:
   226             res += ', "cygpath --windows ~": "' + Cygwin.bashExecute('cygpath --windows ~')[1].strip().replace('\\', '\\\\') + '"'
   227         except:
   228             res += ', "cygpath --windows ~": "FAILED"'
   229 
   230 
   231         res += ', "status message": "' + gvm_mgr.status_message.replace('"', "'") + '"'
   232 
   233         res += '}}'
   234 
   235         # loading it into json and print it again ensures
   236         # we really do have a valid RFC conform json string
   237         # created (as long as the python json module is RFC conform)
   238         return json.dumps(json.loads(res), indent = 4)
   239 
   240 
   241 
   242 class os_sdvm:
   243     """OpenSecurity '/sdvms/[VM]' handler
   244     
   245     - GET: Information about a specific SecurityVM
   246     - DELETE: Remove a specific
   247     """
   248     
   249     def GET(self, name):
   250         log_call(web.ctx.environ)
   251         global gvm_mgr
   252         return json.dumps(gvm_mgr.getVMInfo(name), indent = 4)
   253 
   254     def DELETE(self, name):
   255         log_call(web.ctx.environ)
   256         global gvm_mgr
   257         return gvm_mgr.removeVM(name)
   258             
   259 
   260 class os_sdvm_application:
   261     """OpenSecurity '/sdvms/[VM]/application/[CMD]' handler
   262     
   263     - GET: start application with given command in the VM.
   264     """
   265     
   266     def GET(self, name, command):
   267         log_call(web.ctx.environ)
   268         global gvm_mgr
   269         command = '/' + command
   270         showTrayMessage('Launching application in isolated VM...', 7000)
   271         result = Cygwin.sshExecuteX11(command, gvm_mgr.getHostOnlyIP(name), 'osecuser', Cygwin.cygPath(gvm_mgr.getMachineFolder()) + '/' + name + '/dvm_key'  )
   272         return 'Command ' + str(command) + ' started on VM "' + name + '" with IP ' + gvm_mgr.getHostOnlyIP(name)
   273     
   274 
   275 class os_sdvm_ip:
   276     """OpenSecurity '/sdvms/[VM]/ip' handler
   277     
   278     - GET: give IP of SecurityVM.
   279     """
   280     
   281     def GET(self, name):
   282         log_call(web.ctx.environ)
   283         global gvm_mgr
   284         return gvm_mgr.getHostOnlyIP(name)
   285             
   286 
   287 class os_sdvm_start:
   288     """OpenSecurity '/sdvms/[VM]/start' handler
   289     
   290     - GET: Start specific SecuirtyVM.
   291     """
   292     
   293     def GET(self, name):
   294         log_call(web.ctx.environ)
   295         global gvm_mgr
   296         return gvm_mgr.startVM(name)
   297             
   298 
   299 class os_sdvm_stop:
   300     """OpenSecurity '/sdvms/[VM]/stop' handler
   301     
   302     - GET: stop specific Secuirty VM.
   303     """
   304     
   305     def GET(self, name):
   306         log_call(web.ctx.environ)
   307         global gvm_mgr
   308         return gvm_mgr.stopVM(name)
   309             
   310 
   311 class os_sdvms:
   312     """OpenSecurity '/sdvms' handler
   313     
   314     - GET: list all available secuirty VMs.
   315     - POST: create new security vm.
   316     """
   317     
   318     def GET(self):
   319         """get the list of SDVMs"""
   320         log_call(web.ctx.environ)
   321         global gvm_mgr
   322 
   323         d = {}
   324         for sdvm in gvm_mgr.listSDVM():
   325             d[sdvm] = gvm_mgr.getHostOnlyIP(sdvm)
   326 
   327         return json.dumps(d, indent = 4)
   328             
   329     def POST(self):
   330         """create a new SDVM"""
   331         log_call(web.ctx.environ)
   332         global gvm_mgr
   333         
   334         # get a new vm-name
   335         name = gvm_mgr.generateSDVMName()
   336         try:
   337             gvm_mgr.createVM(name)
   338         except:
   339             raise web.internalerror()
   340             
   341         return name
   342             
   343 
   344 class os_setup:
   345     """OpenSecurity '/setup' handler
   346     
   347     - GET: Give user some info how to setup the OpenSecurity environment
   348     """
   349     
   350     def GET(self):
   351 
   352         log_call(web.ctx.environ)
   353 
   354         page = """
   355         <html>
   356         <body>
   357         <h1>Setup OpenSecurity</h1>
   358         In order to setup OpenSecurity an inital VM image has to be downloaded and imported:<br/>
   359         <ul>
   360             <li>Download initial VM image: <a href="/fetch_initial_image">fetch_initial_image</a>
   361             <li>Import initial VM: <a href="/init">init</a>
   362         </ul>
   363         </body>
   364         </html>
   365         """
   366         return page
   367 
   368 
   369 class os_terminate:
   370     """OpenSecurity '/terminate' handler
   371     
   372     - GET: terminate the opensecurityd.
   373 
   374     TODO: need to find a better way doing this, and not via the
   375           REST api. Maybe hack web.py server code?
   376     """
   377     
   378     def GET(self):
   379         log_call(web.ctx.environ)
   380         global gvm_mgr
   381         gvm_mgr.stop()
   382         gvm_mgr.cleanup()
   383         global server
   384         server.stop()
   385         return None
   386 
   387 class os_initialize:
   388     """OpenSecurity '/initialize' handler
   389     
   390     - GET: initialize / starts the vmmanager.
   391 
   392     """
   393     
   394     def GET(self):
   395         log_call(web.ctx.environ)
   396         global gvm_mgr
   397         gvm_mgr.cleanup()
   398         gvm_mgr.start()
   399         global server
   400         server.run()
   401         return None
   402 
   403 class os_update_template:
   404     """OpenSecurity '/update_template' handler
   405     
   406     - GET: update template vm
   407     """
   408     
   409     def GET(self):
   410         #return gvm_mgr.guestExecute('SecurityDVM', 'sudo apt-get -y update')
   411         global gvm_mgr
   412         log_call(web.ctx.environ)
   413         return gvm_mgr.updateTemplate()
   414 
   415 
   416 class os_vm:
   417     """OpenSecurity '/vms/[VM]' handler
   418     
   419     - GET: list information of arbitrary VM.
   420     """
   421     
   422     def GET(self, name):
   423         log_call(web.ctx.environ)
   424         global gvm_mgr
   425         return gvm_mgr.getVMInfo(name)
   426             
   427 
   428 class os_vms:
   429     """OpenSecurity '/vms' handler
   430     
   431     - GET: list all (also non Security) VMs.
   432     """
   433     
   434     def GET(self):
   435         log_call(web.ctx.environ)
   436         global gvm_mgr
   437         return str(gvm_mgr.listVM()).replace("'",'"')
   438             
   439 
   440 def log_call(web_environ):
   441     """log the incoming call to the REST api"""
   442     try:
   443         call = 'REST ' +  web_environ['REQUEST_METHOD'] + ' ' + web_environ['REQUEST_URI'] + ' from ' + web_environ['REMOTE_ADDR'] + ':' + web_environ['REMOTE_PORT']
   444         logger.debug(call)
   445     except:
   446         pass
   447 
   448 
   449 def main():
   450     """main startup for the opensecuirityd"""
   451 
   452     global gvm_mgr
   453     global server
   454 
   455     logger.debug('Starting OpenSecurity REST server')
   456 
   457     # ensure a VMManger is yet loaded
   458     gvm_mgr = vmmanager.VMManager.getInstance()
   459     gvm_mgr.start()
   460     # tweak sys.argv to control wep.py server start behavior
   461     sys.argv = [__file__, "8080"]
   462     server = web.application(opensecurity_urls, globals(), autoreload = False)
   463     server.run()
   464     
   465     logger.debug('Stopped OpenSecurity REST server')
   466 
   467 
   468 def stop():
   469     """stop the opensecuirityd"""
   470 
   471     # calling sys.exit() raises a SystemExit exception
   472     # of the WSGI Server to let it wind down
   473     # gracefully
   474     sys.exit(0)
   475 
   476 # start
   477 if __name__ == "__main__":
   478     main()
   479     sys.exit(0)
   480