OpenSecurity/bin/opensecurity_client_restful_server.py
author om
Mon, 09 Dec 2013 14:44:41 +0100
changeset 29 3f564e1673bb
parent 16 e16d64b5e008
child 31 d95fe93d7a83
permissions -rwxr-xr-x
added notifcation and password callback url
om@13
     1
#!/bin/env python
om@13
     2
# -*- coding: utf-8 -*-
om@13
     3
om@13
     4
# ------------------------------------------------------------
om@13
     5
# opensecurity_client_restful_server
om@13
     6
# 
om@13
     7
# the OpenSecurity client RESTful server
om@13
     8
#
om@13
     9
# Autor: Oliver Maurhart, <oliver.maurhart@ait.ac.at>
om@13
    10
#
om@13
    11
# Copyright (C) 2013 AIT Austrian Institute of Technology
om@13
    12
# AIT Austrian Institute of Technology GmbH
om@13
    13
# Donau-City-Strasse 1 | 1220 Vienna | Austria
om@13
    14
# http://www.ait.ac.at
om@13
    15
#
om@13
    16
# This program is free software; you can redistribute it and/or
om@13
    17
# modify it under the terms of the GNU General Public License
om@13
    18
# as published by the Free Software Foundation version 2.
om@13
    19
# 
om@13
    20
# This program is distributed in the hope that it will be useful,
om@13
    21
# but WITHOUT ANY WARRANTY; without even the implied warranty of
om@13
    22
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
om@13
    23
# GNU General Public License for more details.
om@13
    24
# 
om@13
    25
# You should have received a copy of the GNU General Public License
om@13
    26
# along with this program; if not, write to the Free Software
om@13
    27
# Foundation, Inc., 51 Franklin Street, Fifth Floor, 
om@13
    28
# Boston, MA  02110-1301, USA.
om@13
    29
# ------------------------------------------------------------
om@13
    30
om@13
    31
om@13
    32
# ------------------------------------------------------------
om@13
    33
# imports
om@13
    34
om@13
    35
import os
om@13
    36
import os.path
om@13
    37
import subprocess
om@13
    38
import sys
om@29
    39
import urllib
om@29
    40
import urllib2
om@13
    41
import web
om@13
    42
om@13
    43
# local
om@13
    44
from environment import Environment
om@29
    45
from notification import Notification
om@13
    46
import opensecurity_server
om@13
    47
om@13
    48
om@13
    49
# ------------------------------------------------------------
om@13
    50
# const
om@13
    51
om@13
    52
om@13
    53
__version__ = "0.1"
om@13
    54
om@13
    55
om@13
    56
"""All the URLs we know mapping to class handler"""
om@13
    57
opensecurity_urls = (
om@13
    58
    '/application',             'os_application',
om@13
    59
    '/credentials',             'os_credentials',
om@29
    60
    '/notification',            'os_notification',
om@13
    61
    '/password',                'os_password',
om@13
    62
    '/',                        'os_root'
om@13
    63
)
om@13
    64
om@13
    65
om@13
    66
# ------------------------------------------------------------
om@13
    67
# code
om@13
    68
om@13
    69
om@13
    70
class os_application:
om@13
    71
    """OpenSecurity '/application' handler.
om@13
    72
    
om@13
    73
    This is called on GET /application?vm=VM-ID&app=APP-ID
om@13
    74
    This tries to access the vm identified with the label VM-ID
om@13
    75
    and launched the application identified APP-ID
om@13
    76
    """
om@13
    77
    
om@13
    78
    def GET(self):
om@13
    79
        
om@13
    80
        # pick the arguments
om@13
    81
        args = web.input()
om@13
    82
        
om@13
    83
        # we _need_ a vm
om@13
    84
        if not "vm" in args:
om@29
    85
            raise web.badrequest('no vm given')
om@13
    86
        
om@13
    87
        # we _need_ a app
om@13
    88
        if not "app" in args:
om@29
    89
            raise web.badrequest('no app given')
om@13
    90
        
om@13
    91
        apps = opensecurity_server.query_apps()
om@13
    92
        vms = opensecurity_server.query_vms()
om@13
    93
        
om@13
    94
        # check if we do have valid vm
om@13
    95
        v = [v for v in vms if v['name'] == args.vm]
om@13
    96
        if len(v) == 0:
om@13
    97
            raise web.notfound('vm not found')
om@13
    98
        v = v[0]
om@13
    99
        
om@13
   100
        # check if we do have a valid app
om@13
   101
        a = [a for a in apps if a['name'] == args.app]
om@13
   102
        if len(a) == 0:
om@13
   103
            raise web.notfound('app not found')
om@13
   104
        a = a[0]
om@13
   105
        
om@13
   106
        # invoke launch with 
om@13
   107
        res = "starting: launch " + v['user'] + " " + v['ip'] + " " + a['command']
om@13
   108
om@13
   109
        launch_image = os.path.join(sys.path[0], 'launch.py')
om@13
   110
        process_command = [sys.executable, launch_image, v['user'], v['ip'], a['command']]
om@13
   111
        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)
om@13
   112
        result = process.communicate()[0]
om@13
   113
        if process.returncode != 0:
om@13
   114
            return 'Launch of application aborted.'
om@13
   115
        
om@13
   116
        return result
om@13
   117
        
om@13
   118
om@13
   119
class os_credentials:
om@13
   120
    """OpenSecurity '/credentials' handler.
om@13
   121
    
om@13
   122
    This is called on GET /credentials?text=TEXT.
om@13
   123
    Ideally this should pop up a user dialog to insert his
om@13
   124
    credentials based the given TEXT.
om@13
   125
    """
om@13
   126
    
om@13
   127
    def GET(self):
om@13
   128
        
om@13
   129
        # pick the arguments
om@13
   130
        args = web.input()
om@13
   131
        
om@29
   132
        # we _need_ a text
om@13
   133
        if not "text" in args:
om@29
   134
            raise web.badrequest('no text given')
om@13
   135
        
om@13
   136
        # invoke the user dialog as a subprocess
om@29
   137
        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.py')
om@29
   138
        process_command = [sys.executable, dlg_image, 'credentials', args.text]
om@13
   139
        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)
om@13
   140
        result = process.communicate()[0]
om@13
   141
        if process.returncode != 0:
om@13
   142
            return 'Credentials request has been aborted.'
om@13
   143
        
om@13
   144
        return result
om@13
   145
om@13
   146
om@29
   147
class os_notification:
om@29
   148
    """OpenSecurity '/notification' handler.
om@29
   149
    
om@29
   150
    This is called on GET /notification?msgtype=TYPE&text=TEXT.
om@29
   151
    This will pop up an OpenSecurity notifcation window
om@29
   152
    """
om@29
   153
    
om@29
   154
    def GET(self):
om@29
   155
        
om@29
   156
        # pick the arguments
om@29
   157
        args = web.input()
om@29
   158
        
om@29
   159
        # we _need_ a type
om@29
   160
        if not "msgtype" in args:
om@29
   161
            raise web.badrequest('no msgtype given')
om@29
   162
            
om@29
   163
        if not args.msgtype in Notification.TYPES:
om@29
   164
            raise web.badrequest('Unknown value for msgtype')
om@29
   165
            
om@29
   166
        # we _need_ a text
om@29
   167
        if not "text" in args:
om@29
   168
            raise web.badrequest('no text given')
om@29
   169
            
om@29
   170
        # invoke the user dialog as a subprocess
om@29
   171
        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.py')
om@29
   172
        process_command = [sys.executable, dlg_image, 'notification-' + args.msgtype, args.text]
om@29
   173
        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)
om@29
   174
        return "Ok"
om@29
   175
om@29
   176
om@13
   177
class os_password:
om@13
   178
    """OpenSecurity '/password' handler.
om@13
   179
    
om@13
   180
    This is called on GET /password?text=TEXT.
om@13
   181
    Ideally this should pop up a user dialog to insert his
om@13
   182
    password based device name.
om@13
   183
    """
om@13
   184
    
om@13
   185
    def GET(self):
om@13
   186
        
om@13
   187
        # pick the arguments
om@13
   188
        args = web.input()
om@13
   189
        
om@29
   190
        # we _need_ a text
om@13
   191
        if not "text" in args:
om@29
   192
            raise web.badrequest('no text given')
om@13
   193
            
om@29
   194
        # remember remote ip
om@29
   195
        remote_ip = web.ctx.environ['REMOTE_ADDR']
om@29
   196
        
om@13
   197
        # invoke the user dialog as a subprocess
om@29
   198
        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.py')
om@29
   199
        process_command = [sys.executable, dlg_image, 'password', args.text]
om@13
   200
        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)
om@13
   201
        result = process.communicate()[0]
om@13
   202
        if process.returncode != 0:
om@13
   203
            return 'password request has been aborted.'
om@13
   204
        
om@29
   205
        # all ok, tell send request back appropriate destination
om@29
   206
        
om@29
   207
        # the returned value of the dialog is a jason object like
om@29
   208
        # "{ 'password': 'THE_PASSWORD' }"
om@29
   209
        # so we _could_ call eval(...) on this.
om@29
   210
        #
om@29
   211
        # However, anyone malicious enough _could_ encode a certain
om@29
   212
        # "password" making some nasty things within that eval code. :(
om@29
   213
        #
om@29
   214
        # So this is plain old-school string hacking then ...
om@29
   215
        try:
om@29
   216
            password = result.split(':')[1].split("'")[1]
om@29
   217
        except:
om@29
   218
            raise web.internalerror('error in password parsing')
om@29
   219
        
om@29
   220
        url_addr = 'http://' + remote_ip + ':58080/password'
om@29
   221
        url_data = urllib.urlencode({ 'password': password})
om@29
   222
        req = urllib2.Request(url = url_addr + '?' + url_data)
om@29
   223
        try:
om@29
   224
            res = urllib2.urlopen(req)
om@29
   225
        except:
om@29
   226
            raise web.internalerror('failed to contact: ' + url_addr)
om@29
   227
        
om@29
   228
        return 'password told'
om@13
   229
om@13
   230
om@13
   231
class os_root:
om@13
   232
    """OpenSecurity '/' handler"""
om@13
   233
    
om@13
   234
    def GET(self):
om@13
   235
    
om@13
   236
        res = "OpenSecurity-Client RESTFul Server { \"version\": \"%s\" }" % __version__
om@13
   237
        
om@13
   238
        # add some sample links
om@13
   239
        res = res + """
om@13
   240
        
om@13
   241
USAGE EXAMPLES:
om@13
   242
        
om@13
   243
Request a password: 
om@13
   244
    (copy paste this into your browser's address field after the host:port)
om@13
   245
    
om@13
   246
    /password?text=Give+me+a+password+for+device+%22My+USB+Drive%22+(ID%3A+32090-AAA-X0)
om@13
   247
    
om@13
   248
    (eg.: http://127.0.0.1:8090/password?text=Give+me+a+password+for+device+%22My+USB+Drive%22+(ID%3A+32090-AAA-X0))
om@13
   249
    NOTE: check yout taskbar, the dialog window may not pop up in front of your browser window.
om@13
   250
    
om@13
   251
    
om@13
   252
Request a combination of user and password:
om@13
   253
    (copy paste this into your browser's address field after the host:port)
om@13
   254
    
om@13
   255
    /credentials?text=Tell+the+NSA+which+credentials+to+use+in+order+to+avoid+hacking+noise+on+wire.
om@13
   256
    
om@13
   257
    (eg.: http://127.0.0.1:8090/credentials?text=Tell+the+NSA+which+credentials+to+use+in+order+to+avoid+hacking+noise+on+wire.)
om@13
   258
    NOTE: check yout taskbar, the dialog window may not pop up in front of your browser window.
om@13
   259
    
om@13
   260
om@13
   261
Start a Browser:
om@13
   262
    (copy paste this into your browser's address field after the host:port)
om@13
   263
om@13
   264
    /application?vm=Debian+7&app=Browser
om@13
   265
om@13
   266
    (e.g. http://127.0.0.1:8090/application?vm=Debian+7&app=Browser)
om@13
   267
        """
om@13
   268
    
om@13
   269
        return res
om@13
   270
om@13
   271
om@13
   272
# start
om@13
   273
if __name__ == "__main__":
om@13
   274
    server = web.application(opensecurity_urls, globals())
om@13
   275
    server.run()