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