source: TI12-security/trunk/MyProxyWebService/myproxy/server/test/test_myproxywsgi_with_paster.py @ 6957

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/MyProxyWebService/myproxy/server/test/test_myproxywsgi_with_paster.py@6957
Revision 6957, 7.1 KB checked in by pjkersha, 10 years ago (diff)

Incomplete - task 5: MyProxy? Logon HTTPS Interface

  • fixed paths to be absolute for PasteDeploy? loadapp ini file in unit tests.
Line 
1#!/usr/bin/env python
2"""Unit tests for MyProxy WSGI Middleware classes and Application testing them
3with Paster web application server.  The server is started from __init__ method
4of the Test Case class and then called by the unit test methods.  The unit
5test methods themselves using a bash script myproxy-ws-logon.sh to query the
6MyProxy web application.
7"""
8__author__ = "P J Kershaw"
9__date__ = "25/05/10"
10__copyright__ = "(C) 2010 Science and Technology Facilities Council"
11__license__ = "BSD - see LICENSE file in top-level directory"
12__contact__ = "Philip.Kershaw@stfc.ac.uk"
13__revision__ = '$Id$'
14from os import path
15from getpass import getpass
16from ConfigParser import SafeConfigParser, NoOptionError
17import subprocess
18import unittest
19import socket
20import logging
21logging.basicConfig(level=logging.DEBUG)
22
23from OpenSSL import SSL, crypto
24
25from myproxy.server.test import PasteDeployAppServer
26       
27
28class MyProxyLogonAppWithPasterTestCase(unittest.TestCase):
29    """Test MyProxy Logon App WSGI in Paster web application server container
30    with bash shell script clients.  For POSIX-like systems ONLY
31    """
32    THIS_DIR = path.abspath(path.dirname(__file__))
33    CA_DIRNAME = 'ca'
34    CA_DIR = path.join(THIS_DIR, CA_DIRNAME)
35    CA_ENV_VARNAME = 'X509_CERT_DIR'
36    INI_FILENAME = 'myproxywsgi.ini'
37    INI_FILEPATH = path.join(THIS_DIR, INI_FILENAME) 
38    CONFIG_FILENAME = 'test_myproxywsgi.cfg'
39    CONFIG_FILEPATH = path.join(THIS_DIR, CONFIG_FILENAME) 
40    SSLCERT_FILEPATH = 'localhost.crt'
41    SSLKEY_FILEPATH = 'localhost.key'
42
43    SERVICE_PORTNUM = 10443
44    LOGON_SCRIPT_CMD = 'myproxy-ws-logon.sh'
45    LOGON_SCRIPT_USER_OPTNAME = '--username'
46    LOGON_SCRIPT_STDIN_PASS_OPTNAME = '--stdin_pass'
47   
48    SCRIPT_URI_OPTNAME = '--uri'
49   
50    GET_TRUSTROOTS_SCRIPT_CMD = 'myproxy-ws-get-trustroots.sh'
51    GET_TRUSTROOTS_SCRIPT_BOOTSTRAP_OPTNAME = '--bootstrap'
52   
53    def __init__(self, *arg, **kw):
54        """Read settings from a config file and create thread for paster
55        based MyProxy Web Service app running over HTTPS
56        """
57        super(MyProxyLogonAppWithPasterTestCase, self).__init__(*arg, **kw)
58        self.services = []
59        self.disableServiceStartup = False
60       
61        self.cfg = SafeConfigParser({'here': self.__class__.THIS_DIR})
62        self.cfg.optionxform = str
63        self.cfg.read(self.__class__.CONFIG_FILEPATH)
64       
65        # Start the MyProxy web service
66        self.addService(cfgFilePath=self.__class__.INI_FILEPATH, 
67                        port=self.__class__.SERVICE_PORTNUM,
68                        withSSL=True,
69                        withLoggingConfig=False)
70   
71    def test01GetTrustRootsScriptWithBootstrap(self):
72        # Test curl/base64 based client script
73        optName = 'MyProxyLogonAppWithPasterTestCase.test02GetTrustRootsScript'
74        uri = self.cfg.get(optName, 'uri')
75       
76        cmd = (
77            self.__class__.GET_TRUSTROOTS_SCRIPT_CMD, 
78            "%s=%s" % (self.__class__.SCRIPT_URI_OPTNAME, uri),
79            "%s" % self.__class__.GET_TRUSTROOTS_SCRIPT_BOOTSTRAP_OPTNAME
80        )
81               
82        try:
83            proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
84                                    stderr=subprocess.PIPE,
85                                    env={self.__class__.CA_ENV_VARNAME:
86                                         self.__class__.CA_DIR})
87        except OSError, e:
88            self.failIf(e.errno == 13, 'Check that the %r script is set with '
89                        'execute permissions' % 
90                        self.__class__.GET_TRUSTROOTS_SCRIPT_CMD)
91            raise
92
93        stdoutdata, stderrdata = proc.communicate()
94        self.failIf(len(stderrdata) > 0, "An error message was returned: %s" % 
95                    stderrdata)
96        print("stdout = %s" % stdoutdata)
97   
98    def test02LogonScript(self):
99        # Test curl/openssl based client script access
100        optName = 'MyProxyLogonAppWithPasterTestCase.test02LogonScript'
101        username = self.cfg.get(optName, 'username')
102        try: 
103            password = self.cfg.get(optName, 'password')
104        except NoOptionError:
105            password = getpass(optName + ' password: ')
106
107        uri = self.cfg.get(optName, 'uri')
108       
109        cmd = (
110            self.__class__.LOGON_SCRIPT_CMD, 
111            "%s=%s"%(self.__class__.SCRIPT_URI_OPTNAME, uri),
112            "%s=%s"%(self.__class__.LOGON_SCRIPT_USER_OPTNAME, username),
113            self.__class__.LOGON_SCRIPT_STDIN_PASS_OPTNAME
114        )
115               
116        p1 = subprocess.Popen(["echo", password], stdout=subprocess.PIPE)
117        try:
118            p2 = subprocess.Popen(cmd, stdin=p1.stdout, stdout=subprocess.PIPE,
119                                  stderr=subprocess.PIPE,
120                                  env={self.__class__.CA_ENV_VARNAME:
121                                       self.__class__.CA_DIR})
122        except OSError, e:
123            self.failIf(e.errno == 13, 'Check that the %r script is set with '
124                        'execute permissions' % self.__class__.LOGON_SCRIPT_CMD)
125            raise
126       
127        stdoutdata, stderrdata = p2.communicate()
128        self.failIf(len(stderrdata) > 0, "An error message was returned: %s" % 
129                    stderrdata)
130        print("stdout = %s" % stdoutdata)
131       
132        cert = crypto.load_certificate(crypto.FILETYPE_PEM, stdoutdata)
133        subj = cert.get_subject()
134        self.assert_(subj)
135        self.assert_(subj.CN)
136        print("Returned certificate subject CN=%r" % subj.CN)
137       
138    def addService(self, *arg, **kw):
139        """Utility for setting up threads to run Paste HTTP based services with
140        unit tests
141       
142        @param arg: tuple contains ini file path setting for the service
143        @type arg: tuple
144        @param kw: keywords including "port" - port number to run the service
145        from
146        @type kw: dict
147        """
148        if self.disableServiceStartup:
149            return
150       
151        withSSL = kw.pop('withSSL', False)
152        if withSSL:
153            certFilePath = path.join(self.__class__.THIS_DIR, 
154                                     self.__class__.SSLCERT_FILEPATH)
155            priKeyFilePath = path.join(self.__class__.THIS_DIR, 
156                                       self.__class__.SSLKEY_FILEPATH)
157           
158            kw['ssl_context'] = SSL.Context(SSL.SSLv23_METHOD)
159            kw['ssl_context'].set_options(SSL.OP_NO_SSLv2)
160       
161            kw['ssl_context'].use_privatekey_file(priKeyFilePath)
162            kw['ssl_context'].use_certificate_file(certFilePath)
163           
164        try:
165            self.services.append(PasteDeployAppServer(*arg, **kw))
166            self.services[-1].startThread()
167           
168        except socket.error:
169            pass
170
171    def __del__(self):
172        """Stop any services started with the addService method"""
173        if hasattr(self, 'services'):
174            for service in self.services:
175                service.terminateThread()
176               
177        parentObj = super(MyProxyLogonAppWithPasterTestCase, self)
178        if hasattr(parentObj, '__del__'):
179            parentObj.__del__()
180
181if __name__ == "__main__":
182    unittest.main()       
183       
Note: See TracBrowser for help on using the repository browser.