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

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@6127
Revision 6127, 14.4 KB checked in by pjkersha, 10 years ago (diff)

Fixed updated templates and stylesheet for OpenID Provider

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        'leftLink',
39        'leftImage',
40        'rightLink',
41        'rightImage',
42        'rightAlt',
43        'footerText',
44        'helpIcon'
45    )
46    ATTR_NAMES = (
47        'title', 
48        'heading',
49        'xml', 
50        'headExtras', 
51        'loginStatus',
52        'loader',
53        'session',
54        'success_to',
55        'fail_to',
56        'trust_root',
57        'environ',
58        'identityURI',
59        'oidRequest'
60    )
61    __slots__ = tuple(["__%s" % name for name in ATTR_NAMES])
62    del name
63    __slots__ += PROPERTY_NAMES
64       
65    LOGIN_TMPL_NAME = 'login.html'
66    DECIDE_PAGE_TMPL_NAME = 'decide.html'
67    MAIN_PAGE_TMPL_NAME = 'main.html'
68    ERROR_PAGE_TMPL_NAME = 'error.html'
69   
70    DEFAULT_TEMPLATES_DIR = path.join(path.dirname(__file__), 'templates')
71   
72    def __init__(self, *arg, **opt):
73        '''Extend RenderingInterface to include config and set-up for Genshi
74        templating
75       
76        @type *arg: tuple
77        @param *arg: RenderingInterface parent class arguments
78        @type **opt: dict
79        @param **opt: additional keywords to set-up Buffet rendering'''
80        super(GenshiRendering, self).__init__(*arg, **opt)
81       
82        # Initialise attributes
83        for i in GenshiRendering.PROPERTY_NAMES:
84            setattr(self, i, '')
85         
86        # Update from keywords   
87        for i in opt:
88            setattr(self, i, opt[i])
89
90        if not self.templateRootDir:
91            self.templateRootDir = GenshiRendering.DEFAULT_TEMPLATES_DIR
92         
93        self.__loader = TemplateLoader(self.templateRootDir, auto_reload=True)
94       
95        self.title = ''
96        self.heading = ''
97        self.xml = ''
98        self.headExtras = ''
99        self.loginStatus = True
100        self.session = ''
101        self.success_to = ''
102        self.fail_to = ''
103       
104        self.__oidRequest = None
105        self.__identityURI = None
106        self.__environ = None
107        self.__trust_root = None
108
109    def getEnviron(self):
110        return self.__environ
111
112    def getIdentityURI(self):
113        return self.__identityURI
114
115    def setEnviron(self, value):
116        self.__environ = value
117
118    def setIdentityURI(self, value):
119        self.__identityURI = value
120
121    def getTrust_root(self):
122        return self.__trust_root
123
124    def getOidRequest(self):
125        return self.__oidRequest
126
127    def setTrust_root(self, value):
128        if not isinstance(value, basestring):
129            raise TypeError('Expecting string type for trust_root attribute; '
130                            'got %r' % type(value))
131        self.__trust_root = value
132
133    def setOidRequest(self, value):
134        if not isinstance(value, CheckIDRequest):
135            raise TypeError('Expecting %r type for oidRequest attribute; '
136                            'got %r' % (CheckIDRequest, type(value)))
137        self.__oidRequest = value
138
139    def getSuccess_to(self):
140        return self.__success_to
141
142    def getFail_to(self):
143        return self.__fail_to
144
145    def setSuccess_to(self, value):
146        if not isinstance(value, basestring):
147            raise TypeError('Expecting string type for success_to attribute; '
148                            'got %r' % type(value))
149        self.__success_to = value
150
151    def setFail_to(self, value):
152        if not isinstance(value, basestring):
153            raise TypeError('Expecting string type for fail_to attribute; '
154                            'got %r' % type(value))
155        self.__fail_to = value
156
157    def getTitle(self):
158        return self.__title
159
160    def getHeading(self):
161        return self.__heading
162
163    def getXml(self):
164        return self.__xml
165
166    def getHeadExtras(self):
167        return self.__headExtras
168
169    def getLoginStatus(self):
170        return self.__loginStatus
171
172    def getSession(self):
173        return self.__session
174   
175    def setTitle(self, value):
176        if not isinstance(value, basestring):
177            raise TypeError('Expecting string type for title attribute; '
178                            'got %r' % type(value))
179        self.__title = value
180   
181    def setHeading(self, value):
182        if not isinstance(value, basestring):
183            raise TypeError('Expecting string type for heading attribute; '
184                            'got %r' % type(value))
185        self.__heading = value
186
187    def setXml(self, value):
188        if not isinstance(value, basestring):
189            raise TypeError('Expecting string type for xml attribute; '
190                            'got %r' % type(value))
191        self.__xml = value
192
193    def setHeadExtras(self, value):
194        if not isinstance(value, basestring):
195            raise TypeError('Expecting string type for headExtras attribute; '
196                            'got %r' % type(value))
197        self.__headExtras = value
198
199    def setLoginStatus(self, value):
200        if not isinstance(value, bool):
201            raise TypeError('Expecting bool type for loginStatus attribute; '
202                            'got %r' % type(value))
203        self.__loginStatus = value
204
205    def setSession(self, value):
206        self.__session = value
207
208    title = property(getTitle, setTitle, None, "Template title")
209
210    heading = property(getHeading, setHeading, None, "Template heading")
211
212    xml = property(getXml, setXml, None, "Additional XML for template")
213
214    headExtras = property(getHeadExtras, setHeadExtras, None, 
215                          "additional head info for template")
216
217    loginStatus = property(getLoginStatus, setLoginStatus, None, 
218                           "Login Status boolean")
219
220    session = property(getSession, setSession, None, 
221                       "Beaker session")
222
223    success_to = property(getSuccess_to, setSuccess_to, None, 
224                          "URL following successful login")
225
226    fail_to = property(getFail_to, setFail_to, None, 
227                       "URL following an error with login")
228
229    def __setattr__(self, name, value):
230        """Apply some generic type checking"""
231        if name in GenshiRendering.PROPERTY_NAMES:
232            if not isinstance(value, basestring):
233                raise TypeError('Expecting string type for %r attribute; got '
234                                '%r' % (name, type(value)))
235           
236        super(GenshiRendering, self).__setattr__(name, value)
237       
238    def _getLoader(self):
239        return self.__loader
240
241    def _setLoader(self, value):
242        if not isinstance(value, TemplateLoader):
243            raise TypeError('Expecting %r type for "loader"; got %r' % 
244                            (TemplateLoader, type(value)))
245        self.__loader = value
246
247    loader = property(_getLoader, _setLoader, 
248                      doc="Genshi TemplateLoader instance") 
249         
250    def _render(self, templateName, c=None, **kw):
251        '''Wrapper for Genshi template rendering
252        @type templateName: basestring
253        @param templateName: name of template file to load
254        @type c: None/object
255        @param c: reference to object to pass into template - defaults to self
256        @type kw: dict
257        @param kw: keywords to pass to template
258        @rtype: string
259        @return: rendered template
260        '''
261        if c is None:
262            c = self
263           
264        kw['c'] = c
265       
266        tmpl = self.loader.load(templateName)
267        rendering = tmpl.generate(**kw).render('html', doctype='html')
268       
269        return rendering
270
271    def yadis(self, environ, start_response):
272        """Render Yadis document containing user URL - override base
273        implementation to specify Yadis based discovery for user URL
274       
275        @type environ: dict
276        @param environ: dictionary of environment variables
277        @type start_response: callable
278        @param start_response: WSGI start response function.  Should be called
279        from this method to set the response code and HTTP header content
280        @rtype: basestring
281        @return: WSGI response
282        """
283        userIdentifier = OpenIDProviderMiddleware.parseIdentityURI(
284                                                    environ['PATH_INFO'])[-1]
285       
286        # This is where this implementation differs from the base class one
287        user_url = OpenIDProviderMiddleware.createIdentityURI(
288                                                        self.urls['url_yadis'],
289                                                        userIdentifier)
290       
291        yadisDict = dict(openid20type=discover.OPENID_2_0_TYPE, 
292                         openid10type=discover.OPENID_1_0_TYPE,
293                         endpoint_url=self.urls['url_openidserver'], 
294                         user_url=user_url)
295       
296        response = RenderingInterface.tmplYadis % yadisDict
297     
298        start_response('200 OK',
299                       [('Content-type', 'application/xrds+xml'+self.charset),
300                        ('Content-length', str(len(response)))])
301        return response
302 
303    def login(self, environ, start_response, success_to=None, fail_to=None, 
304              msg=''):
305        """Set-up template for OpenID Provider Login"""
306        self.title = "OpenID Login"
307        self.heading = "Login"
308        self.success_to = success_to or self.urls['url_mainpage']
309        self.fail_to = fail_to or self.urls['url_mainpage'] 
310        self.xml = msg
311       
312        response = self._render(GenshiRendering.LOGIN_TMPL_NAME)
313        start_response('200 OK', 
314                       [('Content-type', 'text/html'+self.charset),
315                        ('Content-length', str(len(response)))])
316        self.xml = ''
317        return response
318               
319    def mainPage(self, environ, start_response):
320        """Set-up template for OpenID Provider Login"""
321        self.title = "OpenID Provider"
322        self.heading = "OpenID Provider"
323        self.headExtras = '<meta http-equiv="x-xrds-location" content="%s"/>'%\
324                        self.urls['url_serveryadis']
325   
326        response = self._render(GenshiRendering.MAIN_PAGE_TMPL_NAME)
327        start_response('200 OK', 
328                       [('Content-type', 'text/html'+self.charset),
329                        ('Content-length', str(len(response)))])
330        return response
331
332    def identityPage(self, environ, start_response):
333        """This page would normally render the user's Identity page but it's
334        not needed for Yadis only based discovery"""
335        self.title = 'OpenID Provider - Error'
336        self.heading = 'OpenID Provider - Invalid Page Requested'
337        self.xml = 'Invalid page requested for OpenID Provider'
338        response = self._render(GenshiRendering.ERROR_PAGE_TMPL_NAME) 
339        self.xml = ''   
340        start_response("404 Not Found", 
341                       [('Content-type', 'text/html'+self.charset),
342                        ('Content-length', str(len(response)))])
343        return response
344 
345    def decidePage(self, environ, start_response, oidRequest):
346        """Handle user interaction required before final submit back to Relying
347        Party"""
348        self.title = 'Approve OpenID Request?'
349        self.heading = 'Approve OpenID Request?'
350        self.trust_root = oidRequest.trust_root
351        self.oidRequest = oidRequest
352        self.environ = environ
353       
354        if oidRequest.idSelect():
355            if 'username' not in self.session:
356                log.error("No 'username' key set in session object for "
357                          "idselect mode do decide page")
358                msg = ('An internal error has occurred.  Please contact '
359                       'your system administrator')
360                response = self.errorPage(environ, start_response, msg)
361                return response
362               
363            userIdentifier = self._authN.username2UserIdentifiers(
364                                            environ,
365                                            self.session['username'])[0]
366                                           
367            # Use the Yadis path because we want to use Yadis only
368            # based discovery
369            self.identityURI = OpenIDProviderMiddleware.createIdentityURI(
370                                                        self.urls['url_yadis'],
371                                                        userIdentifier)
372        else:
373            self.identityURI = oidRequest.identity
374       
375        response = self._render(GenshiRendering.DECIDE_PAGE_TMPL_NAME)
376        self.identityURI = ''
377       
378        start_response("200 OK", 
379                       [('Content-type', 'text/html'+self.charset),
380                        ('Content-length', str(len(response)))])
381        return response
382       
383    def errorPage(self, environ, start_response, msg, code=500):
384        '''Display error information'''
385        self.title = 'Error with OpenID Provider'
386        self.heading = 'Error'
387        self.xml = msg
388        response = self._render(GenshiRendering.ERROR_PAGE_TMPL_NAME)
389        start_response('%d %s' % (code, httplib.responses[code]), 
390                       [('Content-type', 'text/html'+self.charset),
391                        ('Content-length', str(len(response)))])
392        self.xml = ''
393        return response
394
395    trust_root = property(getTrust_root, setTrust_root, 
396                          doc="trust_root - dict of user trusted RPs")
397
398    oidRequest = property(getOidRequest, setOidRequest, 
399                          doc="oidRequest - OpenID Request object")
400
401    environ = property(getEnviron, setEnviron, None, 
402                       "WSGI environ dict")
403
404    identityURI = property(getIdentityURI, setIdentityURI, 
405                           doc="User OpenID URI")
Note: See TracBrowser for help on using the repository browser.