source: TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/authz/result_handler/genshi.py @ 6265

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/authz/result_handler/genshi.py@6265
Revision 6265, 5.2 KB checked in by pjkersha, 10 years ago (diff)

Adding Genshi template interface for access denied result handler.

Line 
1"""WSGI Policy Enforcement Point basic result handler module for a Genshi
2based implementation.  Access denied HTML response is rendered using the
3Genshi templating language.
4
5NERC DataGrid Project
6"""
7__author__ = "P J Kershaw"
8__date__ = "05/01/10"
9__copyright__ = "(C) 2010 Science and Technology Facilities Council"
10__contact__ = "Philip.Kershaw@stfc.ac.uk"
11__revision__ = "$Id: $"
12__license__ = "BSD - see LICENSE file in top-level directory"
13from string import Template
14from genshi.template import TemplateLoader
15
16from httplib import UNAUTHORIZED, FORBIDDEN
17
18from ndg.security.server.wsgi import NDGSecurityMiddlewareBase
19from ndg.security.server.wsgi.session import SessionMiddlewareBase
20
21
22class GenshiPEPResultHandlerMiddleware(SessionMiddlewareBase):
23    """Genshi based PEP result handler
24    """
25    PROPERTY_NAMES = (
26        'messageTemplate',
27        'templateName',
28        'templateRootDir'
29    )
30    __slots__ = PROPERTY_NAMES
31       
32    DEFAULT_TMPL_NAME = 'accessdenied.html'
33    DEFAULT_TMPL_DIR = path.join(path.dirname(__file__), 'templates')
34   
35    MSG_TMPL = (
36        "Access is forbidden for this resource:<br/><br/>"
37        "$pdpResponseMsg<br/><br/>"
38        "Please check with your site administrator that you have the required "
39        "access privileges."
40    )
41   
42    def __init__(self, app, global_conf, prefix='', **app_conf):
43        '''
44        @type app: callable following WSGI interface
45        @param app: next middleware application in the chain     
46        @type global_conf: dict       
47        @param global_conf: PasteDeploy global configuration dictionary
48        @type prefix: basestring
49        @param prefix: prefix for configuration items
50        @type app_conf: dict       
51        @param app_conf: PasteDeploy application specific configuration
52        dictionary
53        '''
54        super(GenshiPEPResultHandlerMiddleware, self).__init__(app,
55                                                               global_conf,
56                                                               prefix=prefix,
57                                                               **app_conf) 
58               
59        # Initialise attributes
60        for i in GenshiRendering.PROPERTY_NAMES:
61            setattr(self, i, '')
62         
63        # Update from keywords   
64        for i in app_conf:
65            setattr(self, i, app_conf[i])
66
67        if not self.templateRootDir:
68            self.templateRootDir = \
69                            GenshiPEPResultHandlerMiddleware.DEFAULT_TMPL_DIR
70         
71        if not self.messageTemplate:
72            self.messageTemplate = GenshiPEPResultHandlerMiddleware.MSG_TMPL
73           
74        if not self.templateName:
75            self.templateName = \
76                GenshiPEPResultHandlerMiddleware.DEFAULT_TMPL_NAME
77           
78        self.__loader = TemplateLoader(self.templateRootDir, auto_reload=True)
79       
80    @NDGSecurityMiddlewareBase.initCall
81    def __call__(self, environ, start_response):
82       
83        if not self.isAuthenticated:
84            # sets 401 response to be trapped by authentication handler
85            log.warning("PEPResultHandlerMiddleware: user is not "
86                        "authenticated - setting HTTP 401 response")
87            return self._setErrorResponse(code=UNAUTHORIZED)
88        else:
89            # Get response message from PDP recorded by PEP
90            pepCtx = self.session.get(PEPFilter.PEPCTX_SESSION_KEYNAME, {})
91            pdpResponse = pepCtx.get(PEPFilter.PEPCTX_RESPONSE_SESSION_KEYNAME)
92            pdpResponseMsg = getattr(pdpResponse, 'message', '') or ''
93               
94            msg = Template(self.messageTemplate).substitute(
95                                                pdpResponseMsg=pdpResponseMsg)
96
97            response = self._render(xml=msg)
98            start_response(
99                GenshiPEPResultHandlerMiddleware.getStatusMessage(FORBIDDEN),
100                [('Content-type', 'text/html'),
101                 ('Content-Length', str(len(response)))])
102           
103            return response
104       
105    def __setattr__(self, name, value):
106        """Apply some generic type checking"""
107        if name in GenshiRendering.PROPERTY_NAMES:
108            if not isinstance(value, basestring):
109                raise TypeError('Expecting string type for %r attribute; got '
110                                '%r' % (name, type(value)))
111           
112        super(GenshiPEPResultHandlerMiddleware, self).__setattr__(name, value)
113                       
114    def _getLoader(self):
115        return self.__loader
116
117    def _setLoader(self, value):
118        if not isinstance(value, TemplateLoader):
119            raise TypeError('Expecting %r type for "loader"; got %r' % 
120                            (TemplateLoader, type(value)))
121        self.__loader = value
122
123    loader = property(_getLoader, _setLoader, 
124                      doc="Genshi TemplateLoader instance") 
125         
126    def _render(self, **kw):
127        '''Wrapper for Genshi template rendering
128        @type kw: dict
129        @param kw: keywords to pass to template
130        @rtype: string
131        @return: rendered template
132        '''       
133        tmpl = self.loader.load(self.templateName)
134        rendering = tmpl.generate(**kw).render('html', doctype='html')
135       
136        return rendering
Note: See TracBrowser for help on using the repository browser.