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