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