1 | """WSGI Policy Enforcement Point basic result handler - returns a HTML access |
---|
2 | denied message to the client if the client is not authorized. |
---|
3 | |
---|
4 | Functionality in this module moved from original authz package location |
---|
5 | |
---|
6 | NERC DataGrid Project |
---|
7 | """ |
---|
8 | __author__ = "P J Kershaw" |
---|
9 | __date__ = "05/01/10" |
---|
10 | __copyright__ = "(C) 2010 Science and Technology Facilities Council" |
---|
11 | __contact__ = "Philip.Kershaw@stfc.ac.uk" |
---|
12 | __revision__ = "$Id$" |
---|
13 | __license__ = "BSD - see LICENSE file in top-level directory" |
---|
14 | import logging |
---|
15 | log = logging.getLogger(__name__) |
---|
16 | |
---|
17 | from httplib import UNAUTHORIZED, FORBIDDEN |
---|
18 | |
---|
19 | from ndg.security.server.wsgi import NDGSecurityMiddlewareBase |
---|
20 | from ndg.security.server.wsgi.authz.result_handler import ( |
---|
21 | PEPResultHandlerMiddlewareBase, PEPResultHandlerMiddlewareConfigError) |
---|
22 | |
---|
23 | |
---|
24 | class HTTPRedirectPEPResultHandlerMiddleware(PEPResultHandlerMiddlewareBase): |
---|
25 | """This middleware is invoked if access is denied to a given resource. It |
---|
26 | sets a redirect response to redirect the user's browser to a configured |
---|
27 | URL. This could be to provide a custom access denied message or interface. |
---|
28 | |
---|
29 | This middleware is incorporated into the call stack by passing it in to a |
---|
30 | MultiHandler instance. The MultiHandler is configured in the |
---|
31 | AuthorizationMiddlewareBase class - see ndg.security.server.wsgi.authz. The |
---|
32 | MultiHandler is passed a checker method which determines whether to allow |
---|
33 | access, or call this interface. The checker is implemented in the |
---|
34 | PEPFilter. See ndg.security.server.wsgi.authz |
---|
35 | """ |
---|
36 | REDIRECT_URI_PARAMNAME = 'redirectURI' |
---|
37 | |
---|
38 | def __init__(self, app, global_conf, prefix='', **app_conf): |
---|
39 | ''' |
---|
40 | @type app: callable following WSGI interface |
---|
41 | @param app: next middleware application in the chain |
---|
42 | @type global_conf: dict |
---|
43 | @param global_conf: PasteDeploy global configuration dictionary |
---|
44 | @type prefix: basestring |
---|
45 | @param prefix: prefix for configuration items |
---|
46 | @type app_conf: dict |
---|
47 | @param app_conf: PasteDeploy application specific configuration |
---|
48 | dictionary |
---|
49 | ''' |
---|
50 | super(PEPResultHandlerMiddlewareBase, self).__init__(app, {}) |
---|
51 | |
---|
52 | redirectURI = app_conf.get(prefix + \ |
---|
53 | HTTPRedirectPEPResultHandlerMiddleware.REDIRECT_URI_PARAMNAME) |
---|
54 | if redirectURI is None: |
---|
55 | raise PEPResultHandlerMiddlewareConfigError("Missing required " |
---|
56 | "parameter %r" % prefix + \ |
---|
57 | HTTPRedirectPEPResultHandlerMiddleware.REDIRECT_URI_PARAMNAME) |
---|
58 | |
---|
59 | self.redirectURI = redirectURI |
---|
60 | |
---|
61 | @PEPResultHandlerMiddlewareBase.initCall |
---|
62 | def __call__(self, environ, start_response): |
---|
63 | |
---|
64 | log.debug("PEPResultHandlerMiddleware.__call__ ...") |
---|
65 | cls = HTTPRedirectPEPResultHandlerMiddleware |
---|
66 | |
---|
67 | session = self.environ.get(self.sessionKey) |
---|
68 | if not self.isAuthenticated: |
---|
69 | # This check is included as a precaution: this condition should be |
---|
70 | # caught be the AuthNRedirectHandlerMiddleware or PEPFilter |
---|
71 | log.warning("PEPResultHandlerMiddleware: user is not " |
---|
72 | "authenticated - setting HTTP 401 response") |
---|
73 | return self._setErrorResponse(code=UNAUTHORIZED) |
---|
74 | else: |
---|
75 | # Get response message from PDP recorded by PEP |
---|
76 | pepCtx = session.get(cls.PEPCTX_SESSION_KEYNAME, {}) |
---|
77 | pdpResponse = pepCtx.get(cls.PEPCTX_RESPONSE_SESSION_KEYNAME) |
---|
78 | msg = getattr(pdpResponse, 'message', '') or '' |
---|
79 | log.info("PEP returned access denied message: %r; redirecting to " |
---|
80 | "configured redirectURI=%r", msg, self.redirectURI) |
---|
81 | |
---|
82 | return self.redirect() |
---|
83 | |
---|
84 | def redirect(self): |
---|
85 | """Override NDGSecurityMiddlewareBase.redirect to pass uri attribute |
---|
86 | explicitly |
---|
87 | |
---|
88 | @param uri: custom access denied response URI to redirect to |
---|
89 | @type uri: basestring |
---|
90 | @return: empty response - redirect is set in header |
---|
91 | @rtype: list |
---|
92 | """ |
---|
93 | return super(HTTPRedirectPEPResultHandlerMiddleware, self).redirect( |
---|
94 | self.redirectURI) |
---|
95 | |
---|
96 | def _setRedirectURI(self, uri): |
---|
97 | if not isinstance(uri, basestring): |
---|
98 | raise TypeError("Redirect URI must be set to string type") |
---|
99 | |
---|
100 | self.__redirectURI = uri |
---|
101 | |
---|
102 | def _getRedirectURI(self): |
---|
103 | return self.__redirectURI |
---|
104 | |
---|
105 | redirectURI = property(fget=_getRedirectURI, |
---|
106 | fset=_setRedirectURI, |
---|
107 | doc="URI to redirect to if access is denied") |
---|