1 """MyProxy WSGI middleware - places a MyProxy client instance in environ for
2 other downstream middleware or apps to access and use
3
4 NERC DataGrid Project
5 """
6 __author__ = "P J Kershaw"
7 __date__ = "23/03/11"
8 __copyright__ = "(C) 2010 Science and Technology Facilities Council"
9 __license__ = "BSD - see LICENSE file in top-level directory"
10 __contact__ = "Philip.Kershaw@stfc.ac.uk"
11 __revision__ = "$Id: $"
12 import logging
13 log = logging.getLogger(__name__)
14 import httplib
15
16 from myproxy.client import MyProxyClient
20 """Runtime error with MyProxyClientMiddleware"""
21
24 """Configuration error with MyProxyClientMiddleware"""
25
28 """Base class for common functionality
29
30 @cvar CLIENT_ENV_KEYNAME_OPTNAME: ini file option which sets the key name
31 in the WSGI environ for referring to the MyProxy client instance shared
32 between MyProxy* middleware/apps
33 @type CLIENT_ENV_KEYNAME_OPTNAME: string
34
35 @cvar DEFAULT_CLIENT_ENV_KEYNAME: default value for key name set in the
36 WSGI environ dict which refers to the MyProxy client instance shared
37 between MyProxy* middleware/apps
38 @type DEFAULT_CLIENT_ENV_KEYNAME: string
39
40 @ivar __app: WSGI callable for next middleware or app in the WSGI stack
41 @type __app: function
42
43 @ivar __clientEnvironKeyName: key name set in the WSGI environ dict which
44 refers to the MyProxy client instance shared between MyProxy* middleware/
45 apps
46 @type __clientEnvironKeyName: string
47 """
48 __slots__ = (
49 '__app',
50 '__clientEnvironKeyName',
51 )
52
53 CLIENT_ENV_KEYNAME_OPTNAME = 'clientEnvKeyName'
54 DEFAULT_CLIENT_ENV_KEYNAME = ('myproxy.server.wsgi.middleware.'
55 'MyProxyClientMiddleware.myProxyClient')
56
58 """Create WSGI app and MyProxy client attributes
59 @type app: function
60 @param app: WSGI callable for next middleware or app in the WSGI stack
61 """
62 self.__app = app
63 self.__clientEnvironKeyName = None
64
66 """Get MyProxyClient environ key name
67
68 @rtype: basestring
69 @return: MyProxyClient environ key name
70 """
71 return self.__clientEnvironKeyName
72
74 """Set MyProxyClient environ key name
75
76 @type value: basestring
77 @param value: MyProxyClient environ key name
78 """
79 if not isinstance(value, basestring):
80 raise TypeError('Expecting string type for "clientEnvironKeyName"; '
81 'got %r type' % type(value))
82 self.__clientEnvironKeyName = value
83
84 clientEnvironKeyName = property(fget=_getClientEnvironKeyName,
85 fset=_setClientEnvironKeyName,
86 doc="key name in environ for the "
87 "MyProxyClient instance")
88
89 @property
91 """Get Property method for reference to next WSGI application in call
92 stack
93 @rtype: function
94 @return: WSGI application
95 """
96 return self.__app
97
98 @staticmethod
100 '''Make a standard status message for use with start_response
101 @type statusCode: int
102 @param statusCode: HTTP status code
103 @rtype: string
104 @return: status code with standard message
105 @raise KeyError: for invalid status code
106 '''
107 return '%d %s' % (statusCode, httplib.responses[statusCode])
108
111 '''Create a MyProxy client and make it available to other middleware in the
112 WSGI stack
113
114 @cvar PARAM_PREFIX: prefix for ini file option names
115 @type PARAM_PREFIX: string
116
117 @cvar MYPROXY_CLIENT_PARAM_PREFIX: default value for ini file sub-prefix
118 used for MyProxyClient initialisation settings such as MyProxy server
119 hostname, CA cert directory etc. The prefix is such that option names
120 will look like this e.g.
121 <PARAM_PREFIX><MYPROXY_CLIENT_PARAM_PREFIX>hostname
122 ...
123 @type MYPROXY_CLIENT_PARAM_PREFIX: string
124
125 @ivar __myProxyClient: MyProxy client interface object to enable this
126 middleware to communicate with a backend MyProxy server using the MyProxy
127 protocol
128 @type __myProxyClient: myproxy.client.MyProxyClient
129 '''
130
131 PARAM_PREFIX = 'myproxy.'
132 MYPROXY_CLIENT_PARAM_PREFIX = 'client.'
133
134 __slots__ = (
135 '__myProxyClient',
136 )
137
139 '''Create attributes
140
141 @type app: function
142 @param app: WSGI callable for next application in stack
143 '''
144 super(MyProxyClientMiddleware, self).__init__(app)
145 self.__myProxyClient = None
146
147 @classmethod
152 """Function following Paste filter app factory signature
153
154 @type app: callable following WSGI interface
155 @param app: next middleware/application in the chain
156 @type global_conf: dict
157 @param global_conf: PasteDeploy global configuration dictionary
158 @type prefix: basestring
159 @param prefix: prefix for configuration items
160 @type myProxyClientPrefix: ini file sub-prefix used for MyProxyClient
161 initialisation settings such as MyProxy server hostname, CA cert.
162 directory etc.
163 @param myProxyClientPrefix: basestring
164 @type app_conf: dict
165 @param app_conf: PasteDeploy application specific configuration
166 dictionary
167
168 @rtype: myproxy.server.wsgi.middleware.MyProxyClientMiddleware
169 @return: an instance of this application
170 """
171 app = cls(app)
172 app.parseConfig(prefix=prefix, myProxyClientPrefix=myProxyClientPrefix,
173 **app_conf)
174 return app
175
180 """Parse dictionary of configuration items updating the relevant
181 attributes of this instance
182
183 @type prefix: basestring
184 @param prefix: prefix for configuration items
185 @type myProxyClientPrefix: basestring
186 @param myProxyClientPrefix: explicit prefix for MyProxyClient class
187 specific configuration items
188 @type app_conf: dict
189 @param app_conf: PasteDeploy application specific configuration
190 dictionary
191 """
192
193
194 myProxyClientFullPrefix = prefix + myProxyClientPrefix
195
196 myProxyClientKw = dict([(k.replace(myProxyClientFullPrefix, ''), v)
197 for k,v in app_conf.items()
198 if k.startswith(myProxyClientFullPrefix)])
199
200 self.myProxyClient = MyProxyClient(**myProxyClientKw)
201 clientEnvKeyOptName = prefix + \
202 MyProxyClientMiddleware.CLIENT_ENV_KEYNAME_OPTNAME
203
204 self.clientEnvironKeyName = app_conf.get(clientEnvKeyOptName,
205 MyProxyClientMiddleware.DEFAULT_CLIENT_ENV_KEYNAME)
206
208 """Get MyProxyClient instance
209
210 @rtype: myproxy.client.MyProxyClient
211 @return: MyProxyClient instance
212 """
213 return self.__myProxyClient
214
216 """Set MyProxyClient instance
217
218 @type value: myproxy.client.MyProxyClient
219 @param value: MyProxyClient instance
220 """
221 if not isinstance(value, MyProxyClient):
222 raise TypeError('Expecting %r type for "myProxyClient" attribute '
223 'got %r' % (MyProxyClient, type(value)))
224 self.__myProxyClient = value
225
226 myProxyClient = property(fget=_getMyProxyClient,
227 fset=_setMyProxyClient,
228 doc="MyProxyClient instance used to convert HTTPS"
229 " call into a call to a MyProxy server")
230
231 - def __call__(self, environ, start_response):
232 '''Set MyProxyClient instance and MyProxy logon method in environ
233
234 @type environ: dict
235 @param environ: WSGI environment variables dictionary
236 @type start_response: function
237 @param start_response: standard WSGI start response function
238 '''
239 log.debug("MyProxyClientMiddleware.__call__ ...")
240 environ[self.clientEnvironKeyName] = self.myProxyClient
241
242 return self.app(environ, start_response)
243