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

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/myproxy/__init__.py@6107
Revision 6107, 8.4 KB checked in by pjkersha, 10 years ago (diff)
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 myproxy.client import MyProxyClient, MyProxyClientError
19from ndg.security.server.wsgi import NDGSecurityMiddlewareBase, \
20    NDGSecurityMiddlewareConfigError
21   
22from ndg.security.server.wsgi.authn import HTTPBasicAuthMiddleware
23       
24       
25class MyProxyClientMiddlewareConfigError(NDGSecurityMiddlewareConfigError):
26    """Configuration error with MyProxyClientMiddleware"""
27
28
29class MyProxyClientMiddleware(NDGSecurityMiddlewareBase):
30    '''
31    Create a MyProxy client and make it available to other middleware in the
32    WSGI stack
33    '''
34    # Options for ini file
35    CLIENT_ENV_KEYNAME_OPTNAME = 'clientEnvKeyName'
36    LOGON_FUNC_ENV_KEYNAME_OPTNAME = 'logonFuncEnvKeyName'     
37   
38    # Default environ key names
39    CLIENT_ENV_KEYNAME = ('ndg.security.server.wsgi.authn.'
40                          'MyProxyClientMiddleware')
41    LOGON_FUNC_ENV_KEYNAME = ('ndg.security.server.wsgi.authn.'
42                              'MyProxyClientMiddleware.logon')
43   
44    # Option prefixes
45    PARAM_PREFIX = 'myproxy.'
46    MYPROXY_CLIENT_PARAM_PREFIX = 'client.'
47   
48    def __init__(self, app, global_conf, prefix=PARAM_PREFIX, 
49                 myProxyClientPrefix=MYPROXY_CLIENT_PARAM_PREFIX, **app_conf):
50        ''''''
51        super(MyProxyClientMiddleware, self).__init__(app, global_conf)
52        self.__myProxyClient = None
53
54        # Get MyProxyClient initialisation parameters
55        myProxyClientFullPrefix = prefix + myProxyClientPrefix
56                           
57        myProxyClientKw = dict([(k.replace(myProxyClientFullPrefix, ''), v) 
58                                 for k,v in app_conf.items() 
59                                 if k.startswith(myProxyClientFullPrefix)])
60       
61        self.myProxyClient = MyProxyClient(**myProxyClientKw)
62        clientEnvKeyOptName = prefix + \
63                            MyProxyClientMiddleware.CLIENT_ENV_KEYNAME_OPTNAME
64                   
65        self.clientEnvironKeyName = app_conf.get(clientEnvKeyOptName,
66                                MyProxyClientMiddleware.CLIENT_ENV_KEYNAME)
67                   
68        logonFuncEnvKeyOptName = prefix + \
69                    MyProxyClientMiddleware.LOGON_FUNC_ENV_KEYNAME_OPTNAME
70
71        self.logonFuncEnvironKeyName = app_conf.get(logonFuncEnvKeyOptName,
72                                MyProxyClientMiddleware.LOGON_FUNC_ENV_KEYNAME)
73
74    def _getClientEnvironKeyName(self):
75        return self.__clientEnvironKeyName
76
77    def _setClientEnvironKeyName(self, value):
78        if not isinstance(value, basestring):
79            raise TypeError('Expecting string type for "clientEnvironKeyName"; '
80                            'got %r type' % type(value))
81        self.__clientEnvironKeyName = value
82
83    clientEnvironKeyName = property(fget=_getClientEnvironKeyName, 
84                                    fset=_setClientEnvironKeyName, 
85                                    doc="key name in environ for the "
86                                        "MyProxyClient instance")   
87
88    def _getLogonFuncEnvironKeyName(self):
89        return self.__logonFuncEnvironKeyName
90
91    def _setLogonFuncEnvironKeyName(self, value):
92        if not isinstance(value, basestring):
93            raise TypeError('Expecting string type for '
94                            '"logonFuncEnvironKeyName"; got %r type' % 
95                            type(value))
96        self.__logonFuncEnvironKeyName = value
97
98    logonFuncEnvironKeyName = property(fget=_getLogonFuncEnvironKeyName, 
99                                       fset=_setLogonFuncEnvironKeyName, 
100                                       doc="key name in environ for the "
101                                           "MyProxy logon function")
102   
103    def _getMyProxyClient(self):
104        return self.__myProxyClient
105
106    def _setMyProxyClient(self, value):
107        if not isinstance(value, MyProxyClient):
108            raise TypeError('Expecting %r type for "myProxyClient" attribute '
109                            'got %r' % (MyProxyClient, type(value)))
110        self.__myProxyClient = value
111       
112    myProxyClient = property(fget=_getMyProxyClient,
113                             fset=_setMyProxyClient, 
114                             doc="MyProxyClient instance used to convert HTTPS"
115                                 " call into a call to a MyProxy server")
116
117    @NDGSecurityMiddlewareBase.initCall
118    def __call__(self, environ, start_response):
119        '''Set MyProxyClient instance and MyProxy logon method in environ
120       
121        @type environ: dict
122        @param environ: WSGI environment variables dictionary
123        @type start_response: function
124        @param start_response: standard WSGI start response function
125        '''
126        log.debug("MyProxyClientMiddleware.__call__ ...")
127        environ[self.clientEnvironKeyName] = self.myProxyClient
128        environ[self.logonFuncEnvironKeyName] = self.myProxyLogon
129       
130        return self._app(environ, start_response)
131   
132    @property
133    def myProxyLogon(self):
134        """Return the MyProxy logon method wrapped as a HTTP Basic Auth
135        authenticate interface function
136        """
137        def _myProxylogon(environ, start_response, username, password):
138            """Wrap MyProxy logon method as a WSGI app
139            """
140            try:
141                credentials = self.myProxyClient.logon(username, password)
142                status = self.getStatusMessage(httplib.OK)
143                response = '\n'.join(credentials)
144               
145            except MyProxyClientError, e:
146                status = self.getStatusMessage(httplib.UNAUTHORIZED)
147                response = str(e)
148           
149            except socket.error, e:
150                raise MyProxyClientMiddlewareConfigError("Socket error "
151                                        "with MyProxy server %r: %s" % 
152                                        (self.myProxyClient.hostname, e))
153            except Exception, e:
154                log.error("MyProxyClient.logon raised an unknown exception "
155                          "calling %r: %s", 
156                          self.myProxyClient.hostname,
157                          traceback.format_exc())
158                raise
159           
160            start_response(status,
161                           [('Content-length', str(len(response))),
162                            ('Content-type', 'text/plain')])
163            return [response]
164       
165        return _myProxylogon
166       
167       
168class MyProxyLogonMiddlewareConfigError(NDGSecurityMiddlewareConfigError):
169    """Configuration error with MyProxyLogonMiddleware"""
170   
171   
172class MyProxyLogonMiddleware(NDGSecurityMiddlewareBase):
173    """HTTP Basic Auth interface to MyProxy logon.  This interfaces creates a
174    MyProxy client instance and HTTP Basic Auth based web service interface
175    for MyProxy logon calls.  This WSGI must be run over HTTPS to ensure
176    confidentiality of username/passphrase credentials
177    """
178    PARAM_PREFIX = 'myproxy.logon.'
179   
180    def __init__(self, app, global_conf, prefix=PARAM_PREFIX, **app_conf):       
181       
182        authnFuncEnvKeyNameOptName = HTTPBasicAuthMiddleware.PARAM_PREFIX + \
183                        HTTPBasicAuthMiddleware.AUTHN_FUNC_ENV_KEYNAME_OPTNAME
184                       
185        if authnFuncEnvKeyNameOptName in app_conf:
186            raise MyProxyLogonMiddlewareConfigError("Found %r option name in "
187                "application configuration settings.  Use %r instead" %
188                (authnFuncEnvKeyNameOptName, 
189                 MyProxyClientMiddleware.PARAM_PREFIX + \
190                 MyProxyClientMiddleware.LOGON_FUNC_ENV_KEYNAME_OPTNAME))
191       
192        httpBasicAuthApp = HTTPBasicAuthMiddleware(app, app_conf, **app_conf)
193        app = MyProxyClientMiddleware(httpBasicAuthApp, app_conf, **app_conf)
194       
195        # Set HTTP Basic Auth to use the MyProxy client logon for its
196        # authentication method
197        httpBasicAuthApp.authnFuncEnvironKeyName = app.logonFuncEnvironKeyName
198       
199        super(MyProxyLogonMiddleware, self).__init__(app, global_conf, 
200                                                     prefix=prefix, **app_conf)
Note: See TracBrowser for help on using the repository browser.