source: TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/renderinginterface/genshi/__init__.py @ 6115

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/renderinginterface/genshi/__init__.py@6115
Revision 6115, 13.6 KB checked in by pjkersha, 10 years ago (diff)
Line 
1"""NDG Security Pylons Buffet based Rendering Interface for
2OpenIDProviderMiddleware
3
4NERC Data Grid Project
5"""
6__author__ = "P J Kershaw"
7__date__ = "14/08/08"
8__copyright__ = "(C) 2009 Science and Technology Facilities Council"
9__contact__ = "Philip.Kershaw@stfc.ac.uk"
10__revision__ = "$Id: $"
11__license__ = "BSD - see LICENSE file in top-level directory"
12import logging
13log = logging.getLogger(__name__)
14
15import httplib
16from os import path
17
18from genshi.template import TemplateLoader
19from openid.consumer import discover
20from openid.server.server  import CheckIDRequest
21
22# Rendering classes for OpenID Provider must derive from generic render
23# interface
24from ndg.security.server.wsgi.openid.provider import (RenderingInterface, 
25    RenderingInterfaceConfigError)
26   
27from ndg.security.server.wsgi.openid.provider import OpenIDProviderMiddleware
28
29
30class GenshiRendering(RenderingInterface):
31    """Provide Templating for OpenID Provider Middleware using Genshi templating
32    """
33    PROPERTY_NAMES = (
34        'templateRootDir',
35        'baseURL',
36        'leftLogo',
37        'leftAlt',
38        'ndgLink',
39        'ndgImage',
40        'disclaimer',
41        'stfcLink',
42        'stfcImage',
43        'helpIcon'
44    )
45    ATTR_NAMES = (
46        'title', 
47        'xml', 
48        'headExtras', 
49        'loginStatus',
50        'loader',
51        'session',
52        'success_to',
53        'fail_to',
54        'trust_root',
55        'environ',
56        'identityURI',
57        'oidRequest'
58    )
59    __slots__ = tuple(["__%s" % name for name in ATTR_NAMES])
60    del name
61    __slots__ += PROPERTY_NAMES
62       
63    LOGIN_TMPL_NAME = 'login.html'
64    DECIDE_PAGE_TMPL_NAME = 'decide.html'
65    MAIN_PAGE_TMPL_NAME = 'main.html'
66    ERROR_PAGE_TMPL_NAME = 'error.html'
67   
68    DEFAULT_TEMPLATES_DIR = path.join(path.dirname(__file__), 'templates')
69   
70    def __init__(self, *arg, **opt):
71        '''Extend RenderingInterface to include config and set-up for Genshi
72        templating
73       
74        @type *arg: tuple
75        @param *arg: RenderingInterface parent class arguments
76        @type **opt: dict
77        @param **opt: additional keywords to set-up Buffet rendering'''
78        super(GenshiRendering, self).__init__(*arg, **opt)
79       
80        # Initialise attributes
81        for i in GenshiRendering.PROPERTY_NAMES:
82            setattr(self, i, '')
83         
84        # Update from keywords   
85        for i in opt:
86            setattr(self, i, opt[i])
87
88        if not self.templateRootDir:
89            self.templateRootDir = GenshiRendering.DEFAULT_TEMPLATES_DIR
90         
91        self.__loader = TemplateLoader(self.templateRootDir, auto_reload=True)
92       
93        self.title = ''
94        self.xml = ''
95        self.headExtras = ''
96        self.loginStatus = True
97        self.session = ''
98        self.success_to = ''
99        self.fail_to = ''
100       
101        self.__oidRequest = None
102        self.__identityURI = None
103        self.__environ = None
104        self.__trust_root = None
105
106    def getEnviron(self):
107        return self.__environ
108
109    def getIdentityURI(self):
110        return self.__identityURI
111
112    def setEnviron(self, value):
113        self.__environ = value
114
115    def setIdentityURI(self, value):
116        self.__identityURI = value
117
118    def getTrust_root(self):
119        return self.__trust_root
120
121    def getOidRequest(self):
122        return self.__oidRequest
123
124    def setTrust_root(self, value):
125        if not isinstance(value, basestring):
126            raise TypeError('Expecting string type for trust_root attribute; '
127                            'got %r' % type(value))
128        self.__trust_root = value
129
130    def setOidRequest(self, value):
131        if not isinstance(value, CheckIDRequest):
132            raise TypeError('Expecting %r type for oidRequest attribute; '
133                            'got %r' % (CheckIDRequest, type(value)))
134        self.__oidRequest = value
135
136    def getSuccess_to(self):
137        return self.__success_to
138
139    def getFail_to(self):
140        return self.__fail_to
141
142    def setSuccess_to(self, value):
143        if not isinstance(value, basestring):
144            raise TypeError('Expecting string type for success_to attribute; '
145                            'got %r' % type(value))
146        self.__success_to = value
147
148    def setFail_to(self, value):
149        if not isinstance(value, basestring):
150            raise TypeError('Expecting string type for fail_to attribute; '
151                            'got %r' % type(value))
152        self.__fail_to = value
153
154    def getTitle(self):
155        return self.__title
156
157    def getXml(self):
158        return self.__xml
159
160    def getHeadExtras(self):
161        return self.__headExtras
162
163    def getLoginStatus(self):
164        return self.__loginStatus
165
166    def getSession(self):
167        return self.__session
168   
169    def setTitle(self, value):
170        if not isinstance(value, basestring):
171            raise TypeError('Expecting string type for title attribute; '
172                            'got %r' % type(value))
173        self.__title = value
174
175    def setXml(self, value):
176        if not isinstance(value, basestring):
177            raise TypeError('Expecting string type for xml attribute; '
178                            'got %r' % type(value))
179        self.__xml = value
180
181    def setHeadExtras(self, value):
182        if not isinstance(value, basestring):
183            raise TypeError('Expecting string type for headExtras attribute; '
184                            'got %r' % type(value))
185        self.__headExtras = value
186
187    def setLoginStatus(self, value):
188        if not isinstance(value, bool):
189            raise TypeError('Expecting bool type for loginStatus attribute; '
190                            'got %r' % type(value))
191        self.__loginStatus = value
192
193    def setSession(self, value):
194        self.__session = value
195
196    title = property(getTitle, setTitle, None, "Template title")
197
198    xml = property(getXml, setXml, None, "Additional XML for template")
199
200    headExtras = property(getHeadExtras, setHeadExtras, None, 
201                          "additional head info for template")
202
203    loginStatus = property(getLoginStatus, setLoginStatus, None, 
204                           "Login Status boolean")
205
206    session = property(getSession, setSession, None, 
207                       "Beaker session")
208
209    success_to = property(getSuccess_to, setSuccess_to, None, 
210                          "URL following successful login")
211
212    fail_to = property(getFail_to, setFail_to, None, 
213                       "URL following an error with login")
214
215    def __setattr__(self, name, value):
216        """Apply some generic type checking"""
217        if name in GenshiRendering.PROPERTY_NAMES:
218            if not isinstance(value, basestring):
219                raise TypeError('Expecting string type for %r attribute; got '
220                                '%r' % (name, type(value)))
221                           
222        super(GenshiRendering, self).__setattr__(name, value)
223       
224    def _getLoader(self):
225        return self.__loader
226
227    def _setLoader(self, value):
228        if not isinstance(value, TemplateLoader):
229            raise TypeError('Expecting %r type for "loader"; got %r' % 
230                            (TemplateLoader, type(value)))
231        self.__loader = value
232
233    loader = property(_getLoader, _setLoader, 
234                      doc="Genshi TemplateLoader instance") 
235         
236    def _render(self, templateName, c=None, **kw):
237        '''Wrapper for Genshi template rendering
238        @type templateName: basestring
239        @param templateName: name of template file to load
240        @type c: None/object
241        @param c: reference to object to pass into template - defaults to self
242        @type kw: dict
243        @param kw: keywords to pass to template
244        @rtype: string
245        @return: rendered template
246        '''
247        if c is None:
248            c = self
249           
250        kw['c'] = c
251       
252        tmpl = self.loader.load(templateName)
253        rendering = tmpl.generate(**kw).render('html', doctype='html')
254       
255        return rendering
256
257    def yadis(self, environ, start_response):
258        """Render Yadis document containing user URL - override base
259        implementation to specify Yadis based discovery for user URL
260       
261        @type environ: dict
262        @param environ: dictionary of environment variables
263        @type start_response: callable
264        @param start_response: WSGI start response function.  Should be called
265        from this method to set the response code and HTTP header content
266        @rtype: basestring
267        @return: WSGI response
268        """
269        userIdentifier = OpenIDProviderMiddleware.parseIdentityURI(
270                                                    environ['PATH_INFO'])[-1]
271       
272        # This is where this implementation differs from the base class one
273        user_url = OpenIDProviderMiddleware.createIdentityURI(
274                                                        self.urls['url_yadis'],
275                                                        userIdentifier)
276       
277        yadisDict = dict(openid20type=discover.OPENID_2_0_TYPE, 
278                         openid10type=discover.OPENID_1_0_TYPE,
279                         endpoint_url=self.urls['url_openidserver'], 
280                         user_url=user_url)
281       
282        response = RenderingInterface.tmplYadis % yadisDict
283     
284        start_response('200 OK',
285                       [('Content-type', 'application/xrds+xml'+self.charset),
286                        ('Content-length', str(len(response)))])
287        return response
288 
289    def login(self, environ, start_response, success_to=None, fail_to=None, 
290              msg=''):
291        """Set-up template for OpenID Provider Login"""
292        self.title = "OpenID Login"
293        self.success_to = success_to or self.urls['url_mainpage']
294        self.fail_to = fail_to or self.urls['url_mainpage'] 
295        self.xml = msg
296       
297        response = self._render(GenshiRendering.LOGIN_TMPL_NAME)
298        start_response('200 OK', 
299                       [('Content-type', 'text/html'+self.charset),
300                        ('Content-length', str(len(response)))])
301        self.xml = ''
302        return response
303               
304    def mainPage(self, environ, start_response):
305        """Set-up template for OpenID Provider Login"""
306        self.title = "OpenID Provider"
307        self.headExtras = '<meta http-equiv="x-xrds-location" content="%s"/>'%\
308                        self.urls['url_serveryadis']
309   
310        response = self._render(GenshiRendering.MAIN_PAGE_TMPL_NAME)
311        start_response('200 OK', 
312                       [('Content-type', 'text/html'+self.charset),
313                        ('Content-length', str(len(response)))])
314        return response
315
316    def identityPage(self, environ, start_response):
317        """This page would normally render the user's Identity page but it's
318        not needed for Yadis only based discovery"""
319
320        self.xml = 'Invalid page requested for OpenID Provider'
321        response = self._render(GenshiRendering.ERROR_PAGE_TMPL_NAME) 
322        self.xml = ''   
323        start_response("404 Not Found", 
324                       [('Content-type', 'text/html'+self.charset),
325                        ('Content-length', str(len(response)))])
326        return response
327 
328    def decidePage(self, environ, start_response, oidRequest):
329        """Handle user interaction required before final submit back to Relying
330        Party"""
331        self.title = 'Approve OpenID Request?'
332        self.trust_root = oidRequest.trust_root
333        self.oidRequest = oidRequest
334        self.environ = environ
335       
336        if oidRequest.idSelect():
337            if 'username' not in self.session:
338                log.error("No 'username' key set in session object for "
339                          "idselect mode do decide page")
340                msg = ('An internal error has occurred.  Please contact '
341                       'your system administrator')
342                response = self.errorPage(environ, start_response, msg)
343                return response
344               
345            userIdentifier = self._authN.username2UserIdentifiers(
346                                            environ,
347                                            self.session['username'])[0]
348                                           
349            # Use the Yadis path because we want to use Yadis only
350            # based discovery
351            self.identityURI = OpenIDProviderMiddleware.createIdentityURI(
352                                                        self.urls['url_yadis'],
353                                                        userIdentifier)
354        else:
355            self.identityURI = oidRequest.identity
356       
357        response = self._render(GenshiRendering.DECIDE_PAGE_TMPL_NAME)
358        self.identityURI = ''
359       
360        start_response("200 OK", 
361                       [('Content-type', 'text/html'+self.charset),
362                        ('Content-length', str(len(response)))])
363        return response
364       
365    def errorPage(self, environ, start_response, msg, code=500):
366        '''Display error information'''
367        self.title = 'Error with OpenID Provider'
368        self.xml = msg
369        response = self._render(GenshiRendering.ERROR_PAGE_TMPL_NAME)
370        start_response('%d %s' % (code, httplib.responses[code]), 
371                       [('Content-type', 'text/html'+self.charset),
372                        ('Content-length', str(len(response)))])
373        self.xml = ''
374        return response
375
376    trust_root = property(getTrust_root, setTrust_root, None, "Trust_root's Docstring")
377
378    oidRequest = property(getOidRequest, setOidRequest, None, "OidRequest's Docstring")
379
380    environ = property(getEnviron, setEnviron, None, "Environ's Docstring")
381
382    identityURI = property(getIdentityURI, setIdentityURI, None, "IdentityURI's Docstring")
Note: See TracBrowser for help on using the repository browser.