source: TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/authz/__init__.py @ 7361

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

Incomplete - task 2: XACML-Security Integration

  • working caching with ndg.security.test.integration.full_system integration test. Caching works at the app, caching authz decisions but also at the PIP inside the authorisation service, caching Attribute Authority query results.
  • TODO: make PEP use two stage PDP, first lightweight PDP filters out CSS and graphics requests to avoid overhead of network call to the authorisation service, second stage is callout to authorisation service as already in place.
  • Property svn:keywords set to Id
Line 
1"""WSGI Policy Enforcement Point Package
2
3NERC DataGrid Project
4"""
5__author__ = "P J Kershaw"
6__date__ = "16/01/2009"
7__copyright__ = "(C) 2009 Science and Technology Facilities Council"
8__contact__ = "Philip.Kershaw@stfc.ac.uk"
9__revision__ = "$Id$"
10__license__ = "BSD - see LICENSE file in top-level directory"
11import logging
12log = logging.getLogger(__name__)
13
14import warnings
15from time import time
16from urlparse import urlunsplit
17import httplib
18
19from paste.cascade import Cascade
20from paste.urlparser import StaticURLParser
21from authkit.authenticate.multi import MultiHandler
22
23from ndg.security.common.utils.classfactory import importClass
24from ndg.security.server.wsgi import NDGSecurityMiddlewareBase
25from ndg.security.server.wsgi.authz.pep import SamlPepFilter
26from ndg.security.server.wsgi.authz.result_handler import \
27    PEPResultHandlerMiddlewareBase
28from ndg.security.server.wsgi.authz.result_handler.basic import \
29    PEPResultHandlerMiddleware
30
31
32class Http403ForbiddenStatusHandler(object):
33    """Handler to catch HTTP 403 Forbidden responses.  It integrates with
34    AuthKit's MultiHandler.  This enables the given middleware to be substituted
35    into the WSGI stack should a 403 status be detected set from upstream
36    middleware.
37       
38    @cvar TRIGGER_HTTP_STATUS_CODE: status code to catch - HTTP 403 Forbidden
39    @type TRIGGER_HTTP_STATUS_CODE: basestring
40    """
41    TRIGGER_HTTP_STATUS_CODE = str(httplib.FORBIDDEN)
42   
43    @classmethod
44    def intercept(cls, environ, status, headers):
45        """Checker function for AuthKit Multihandler
46       
47        @type environ: dict
48        @param environ: WSGI environment dictionary
49        @type status: basestring
50        @param status: HTTP response code set by application middleware
51        that this intercept function is to protect
52        @type headers: list
53        @param headers: HTTP response header content"""
54       
55        if status.startswith(cls.TRIGGER_HTTP_STATUS_CODE):
56            log.debug("Found [%s] status for URI path [%s]: invoking access "
57                      "denied response",
58                      cls.TRIGGER_HTTP_STATUS_CODE,
59                      environ['PATH_INFO'])
60            return True
61        else:
62            # No match - it's publicly accessible
63            log.debug("The return status [%s] for this URI path [%s] didn't "
64                      "match the trigger status [%s]",
65                      status,
66                      environ['PATH_INFO'],
67                      cls.TRIGGER_HTTP_STATUS_CODE)
68            return False
69
70   
71class AuthorisationFilterConfigError(Exception):
72    """AuthorisationFilterBase configuration related exceptions"""
73 
74   
75class AuthorisationFilter(object):
76    '''NDG Security Authorisation filter wraps the Policy Enforcement Point
77    (PEP) filter to intercept requests and enforce access control decisions and
78    result handler middleware which enables a customised response given an
79    authorisation denied decision from the PEP filter.
80    '''
81    PEP_PARAM_PREFIX = 'pep.'
82    RESULT_HANDLER_PARAMNAME = "resultHandler"
83    RESULT_HANDLER_PARAM_PREFIX = RESULT_HANDLER_PARAMNAME + '.'
84    RESULT_HANDLER_STATIC_CONTENT_DIR_PARAMNAME = 'staticContentDir'
85   
86    @classmethod
87    def filter_app_factory(cls, app, global_conf, prefix='', **app_conf):
88        """Set-up Policy Enforcement Point to enforce access control decisions
89        based on the URI path requested and/or the HTTP response code set by
90        application(s) to be protected.  An AuthKit MultiHandler is setup to
91        handle the latter.  PEPResultHandlerMiddleware handles the output
92        set following an access denied decision
93        @type app: callable following WSGI interface
94        @param app: next middleware application in the chain     
95        @type global_conf: dict       
96        @param global_conf: PasteDeploy global configuration dictionary
97        @type prefix: basestring
98        @param prefix: prefix for configuration items
99        @type app_conf: dict       
100        @param app_conf: PasteDeploy application specific configuration
101        dictionary
102        """
103        # Allow for static content for use with PEP result handler middleware
104        resultHandlerParamPrefix = prefix + cls.RESULT_HANDLER_PARAM_PREFIX
105        resultHandlerStaticContentDirParamName = \
106                                resultHandlerParamPrefix + \
107                                cls.RESULT_HANDLER_STATIC_CONTENT_DIR_PARAMNAME
108       
109        resultHandlerStaticContentDir = app_conf.get(
110                                    resultHandlerStaticContentDirParamName)
111        if resultHandlerStaticContentDir is not None:   
112            staticApp = StaticURLParser(resultHandlerStaticContentDir)
113            app = Cascade([app, staticApp], catch=(httplib.NOT_FOUND,))
114
115        pepPrefix = prefix + cls.PEP_PARAM_PREFIX
116        pepFilter = SamlPepFilter.filter_app_factory(app, 
117                                                     global_conf, 
118                                                     prefix=pepPrefix, 
119                                                     **app_conf)
120       
121        # Now add the multi-handler to enable result handler to be invoked on
122        # 403 forbidden status from upstream middleware
123        app = MultiHandler(pepFilter)
124
125        resultHandlerClassName = app_conf.pop(
126                                            prefix+cls.RESULT_HANDLER_PARAMNAME, 
127                                            None)
128        if resultHandlerClassName is None:
129            resultHandler = PEPResultHandlerMiddleware
130        else:
131            resultHandler = importClass(resultHandlerClassName,
132                                    objectType=PEPResultHandlerMiddlewareBase)
133                               
134        app.add_method(resultHandler.__class__.__name__,
135                       resultHandler.filter_app_factory,
136                       global_conf,
137                       prefix=resultHandlerParamPrefix,
138                       **app_conf)
139       
140        app.add_checker(resultHandler.__class__.__name__, 
141                        Http403ForbiddenStatusHandler.intercept)
142       
143        return app
Note: See TracBrowser for help on using the repository browser.