source: TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/myproxy/__init__.py @ 6202

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/myproxy/__init__.py@6202
Revision 6202, 9.5 KB checked in by pjkersha, 10 years ago (diff)

Adding information about requested attributes for the decide page interface of the OpenID Provider.

Line 
1"""Functionality for WSGI HTTPS proxy to MyProxy server.
2 
3NERC DataGrid Project
4"""
5__author__ = "P J Kershaw"
6__date__ = "13/01/09"
7__copyright__ = "(C) 2009 Science and Technology Facilities Council"
8__license__ = "BSD - see LICENSE file in top-level directory"
9__contact__ = "Philip.Kershaw@stfc.ac.uk"
10__revision__ = "$Id: $"
11import logging
12log = logging.getLogger(__name__)
13import traceback
14import re
15import httplib
16import socket
17
18from M2Crypto import X509
19
20from myproxy.client import MyProxyClient, MyProxyClientError
21from ndg.security.server.wsgi import (NDGSecurityMiddlewareBase, 
22                                      NDGSecurityMiddlewareConfigError)
23   
24from ndg.security.server.wsgi.authn import HTTPBasicAuthMiddleware
25       
26       
27class MyProxyClientMiddlewareConfigError(NDGSecurityMiddlewareConfigError):
28    """Configuration error with MyProxyClientMiddleware"""
29
30
31class MyProxyClientMiddleware(NDGSecurityMiddlewareBase):
32    '''
33    Create a MyProxy client and make it available to other middleware in the
34    WSGI stack
35    '''
36    # Options for ini file
37    CLIENT_ENV_KEYNAME_OPTNAME = 'clientEnvKeyName'
38    LOGON_FUNC_ENV_KEYNAME_OPTNAME = 'logonFuncEnvKeyName'     
39   
40    # Default environ key names
41    CLIENT_ENV_KEYNAME = ('ndg.security.server.wsgi.authn.'
42                          'MyProxyClientMiddleware')
43    LOGON_FUNC_ENV_KEYNAME = ('ndg.security.server.wsgi.authn.'
44                              'MyProxyClientMiddleware.logon')
45   
46    WSGI_INPUT_ENV_KEYNAME = 'wsgi.input'
47   
48    # Option prefixes
49    PARAM_PREFIX = 'myproxy.'
50    MYPROXY_CLIENT_PARAM_PREFIX = 'client.'
51   
52    def __init__(self, app, global_conf, prefix=PARAM_PREFIX, 
53                 myProxyClientPrefix=MYPROXY_CLIENT_PARAM_PREFIX, **app_conf):
54        ''''''
55        super(MyProxyClientMiddleware, self).__init__(app, global_conf)
56        self.__myProxyClient = None
57
58        # Get MyProxyClient initialisation parameters
59        myProxyClientFullPrefix = prefix + myProxyClientPrefix
60                           
61        myProxyClientKw = dict([(k.replace(myProxyClientFullPrefix, ''), v) 
62                                 for k,v in app_conf.items() 
63                                 if k.startswith(myProxyClientFullPrefix)])
64       
65        self.myProxyClient = MyProxyClient(**myProxyClientKw)
66        clientEnvKeyOptName = prefix + \
67                            MyProxyClientMiddleware.CLIENT_ENV_KEYNAME_OPTNAME
68                   
69        self.clientEnvironKeyName = app_conf.get(clientEnvKeyOptName,
70                                MyProxyClientMiddleware.CLIENT_ENV_KEYNAME)
71                   
72        logonFuncEnvKeyOptName = prefix + \
73                    MyProxyClientMiddleware.LOGON_FUNC_ENV_KEYNAME_OPTNAME
74
75        self.logonFuncEnvironKeyName = app_conf.get(logonFuncEnvKeyOptName,
76                                MyProxyClientMiddleware.LOGON_FUNC_ENV_KEYNAME)
77
78    def _getClientEnvironKeyName(self):
79        return self.__clientEnvironKeyName
80
81    def _setClientEnvironKeyName(self, value):
82        if not isinstance(value, basestring):
83            raise TypeError('Expecting string type for "clientEnvironKeyName"; '
84                            'got %r type' % type(value))
85        self.__clientEnvironKeyName = value
86
87    clientEnvironKeyName = property(fget=_getClientEnvironKeyName, 
88                                    fset=_setClientEnvironKeyName, 
89                                    doc="key name in environ for the "
90                                        "MyProxyClient instance")   
91
92    def _getLogonFuncEnvironKeyName(self):
93        return self.__logonFuncEnvironKeyName
94
95    def _setLogonFuncEnvironKeyName(self, value):
96        if not isinstance(value, basestring):
97            raise TypeError('Expecting string type for '
98                            '"logonFuncEnvironKeyName"; got %r type' % 
99                            type(value))
100        self.__logonFuncEnvironKeyName = value
101
102    logonFuncEnvironKeyName = property(fget=_getLogonFuncEnvironKeyName, 
103                                       fset=_setLogonFuncEnvironKeyName, 
104                                       doc="key name in environ for the "
105                                           "MyProxy logon function")
106   
107    def _getMyProxyClient(self):
108        return self.__myProxyClient
109
110    def _setMyProxyClient(self, value):
111        if not isinstance(value, MyProxyClient):
112            raise TypeError('Expecting %r type for "myProxyClient" attribute '
113                            'got %r' % (MyProxyClient, type(value)))
114        self.__myProxyClient = value
115       
116    myProxyClient = property(fget=_getMyProxyClient,
117                             fset=_setMyProxyClient, 
118                             doc="MyProxyClient instance used to convert HTTPS"
119                                 " call into a call to a MyProxy server")
120
121    @NDGSecurityMiddlewareBase.initCall
122    def __call__(self, environ, start_response):
123        '''Set MyProxyClient instance and MyProxy logon method in environ
124       
125        @type environ: dict
126        @param environ: WSGI environment variables dictionary
127        @type start_response: function
128        @param start_response: standard WSGI start response function
129        '''
130        log.debug("MyProxyClientMiddleware.__call__ ...")
131        environ[self.clientEnvironKeyName] = self.myProxyClient
132        environ[self.logonFuncEnvironKeyName] = self.myProxyLogon
133       
134        return self._app(environ, start_response)
135   
136    @property
137    def myProxyLogon(self):
138        """Return the MyProxy logon method wrapped as a HTTP Basic Auth
139        authenticate interface function
140        """
141        def _myProxylogon(environ, start_response, username, password):
142            """Wrap MyProxy logon method as a WSGI app
143            """
144            if environ['HTTP_METHOD'] == 'GET':
145                # No certificate request passed with GET call
146                # TODO: retire this method? - keys are generated here instead of
147                # the client
148                certReq = None
149                   
150            elif environ['HTTP_METHOD'] == 'POST':
151               
152                pemCertReq = environ[
153                        MyProxyClientMiddleware.WSGI_INPUT_ENV_KEYNAME].read()
154               
155                # TODO: restore WSGI file object
156               
157                # Expecting PEM encoded request
158                certReq = X509.load_request_string(pemCertReq) 
159            else:
160                status = self.getStatusMessage(httplib.UNAUTHORIZED)
161                response = ("HTTP request method %r not recognised for this "
162                            "request " % environ['HTTP_METHOD'])
163               
164            try:
165                credentials = self.myProxyClient.logon(username, 
166                                                       password,
167                                                       certReq=certReq)
168                status = self.getStatusMessage(httplib.OK)
169                response = '\n'.join(credentials)
170               
171            except MyProxyClientError, e:
172                status = self.getStatusMessage(httplib.UNAUTHORIZED)
173                response = str(e)
174           
175            except socket.error, e:
176                raise MyProxyClientMiddlewareConfigError("Socket error "
177                                        "with MyProxy server %r: %s" % 
178                                        (self.myProxyClient.hostname, e))
179            except Exception, e:
180                log.error("MyProxyClient.logon raised an unknown exception "
181                          "calling %r: %s", 
182                          self.myProxyClient.hostname,
183                          traceback.format_exc())
184                raise
185           
186            start_response(status,
187                           [('Content-length', str(len(response))),
188                            ('Content-type', 'text/plain')])
189            return [response]
190       
191        return _myProxylogon
192       
193       
194class MyProxyLogonMiddlewareConfigError(NDGSecurityMiddlewareConfigError):
195    """Configuration error with MyProxyLogonMiddleware"""
196   
197   
198class MyProxyLogonMiddleware(NDGSecurityMiddlewareBase):
199    """HTTP Basic Auth interface to MyProxy logon.  This interfaces creates a
200    MyProxy client instance and HTTP Basic Auth based web service interface
201    for MyProxy logon calls.  This WSGI must be run over HTTPS to ensure
202    confidentiality of username/passphrase credentials
203    """
204    PARAM_PREFIX = 'myproxy.logon.'
205   
206    def __init__(self, app, global_conf, prefix=PARAM_PREFIX, **app_conf):       
207       
208        authnFuncEnvKeyNameOptName = HTTPBasicAuthMiddleware.PARAM_PREFIX + \
209                        HTTPBasicAuthMiddleware.AUTHN_FUNC_ENV_KEYNAME_OPTNAME
210                       
211        if authnFuncEnvKeyNameOptName in app_conf:
212            raise MyProxyLogonMiddlewareConfigError("Found %r option name in "
213                "application configuration settings.  Use %r instead" %
214                (authnFuncEnvKeyNameOptName, 
215                 MyProxyClientMiddleware.PARAM_PREFIX + \
216                 MyProxyClientMiddleware.LOGON_FUNC_ENV_KEYNAME_OPTNAME))
217       
218        httpBasicAuthApp = HTTPBasicAuthMiddleware(app, app_conf, **app_conf)
219        app = MyProxyClientMiddleware(httpBasicAuthApp, app_conf, **app_conf)
220       
221        # Set HTTP Basic Auth to use the MyProxy client logon for its
222        # authentication method
223        httpBasicAuthApp.authnFuncEnvironKeyName = app.logonFuncEnvironKeyName
224       
225        super(MyProxyLogonMiddleware, self).__init__(app, global_conf, 
226                                                     prefix=prefix, **app_conf)
Note: See TracBrowser for help on using the repository browser.