source: TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/wsgi/authz/test_authz.py @ 6069

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/wsgi/authz/test_authz.py@6069
Revision 6069, 14.9 KB checked in by pjkersha, 11 years ago (diff)

Re-release as rc1

Line 
1#!/usr/bin/env python
2"""Unit tests for WSGI Authorization handler
3
4NERC DataGrid Project
5"""
6__author__ = "P J Kershaw"
7__date__ = "21/05/09"
8__copyright__ = "(C) 2009 Science and Technology Facilities Council"
9__license__ = "BSD - see LICENSE file in top-level directory"
10__contact__ = "Philip.Kershaw@stfc.ac.uk"
11__revision__ = '$Id: $'
12import logging
13
14
15import unittest
16import os
17from urlparse import urlunsplit
18
19from os.path import expandvars as xpdVars
20from os.path import join as jnPath
21mkPath = lambda file: jnPath(os.environ['NDGSEC_COMBINED_SRVS_UNITTEST_DIR'], 
22                             file)
23
24import paste.fixture
25from paste.deploy import loadapp
26
27from ndg.security.test.unit import BaseTestCase
28from ndg.security.server.wsgi import NDGSecurityMiddlewareBase
29from ndg.security.server.wsgi.authz import (NdgPIPMiddlewareConfigError,
30                                            SamlPIPMiddlewareConfigError, 
31                                            PEPResultHandlerMiddleware)
32from ndg.security.common.authz.msi import Response
33
34
35class RedirectFollowingAccessDenied(PEPResultHandlerMiddleware):
36   
37    @NDGSecurityMiddlewareBase.initCall
38    def __call__(self, environ, start_response):
39       
40        queryString = environ.get('QUERY_STRING', '')
41        if 'admin=1' in queryString:
42            # User has been rejected access to a URI requiring admin rights,
43            # try redirect to the same URI minus the admin query arg, this
44            # request will pass because admin rights aren't needed
45            queryArgs = queryString.split('&')
46            queryList = [arg for arg in queryArgs if arg != 'admin=1']
47            editedQuery = '&'.join(queryList)
48            redirectURI = urlunsplit(('', '', self.pathInfo, editedQuery, ''))
49            return self.redirect(redirectURI)
50        else:
51            return super(RedirectFollowingAccessDenied, self).__call__(
52                                                            environ,
53                                                            start_response)
54
55       
56class TestAuthZMiddleware(object):
57    '''Test Application for the Authentication handler to protect'''
58    response = "Test Authorization application"
59       
60    def __init__(self, app_conf, **local_conf):
61        pass
62   
63    def __call__(self, environ, start_response):
64       
65        if environ['PATH_INFO'] == '/test_401':
66            status = "401 Unauthorized"
67           
68        elif environ['PATH_INFO'] == '/test_403':
69            status = "403 Forbidden"
70           
71        elif environ['PATH_INFO'] == '/test_200':
72            status = "200 OK"
73           
74        elif environ['PATH_INFO'] == '/test_accessDeniedToSecuredURI':
75            # Nb. AuthZ middleware should intercept the request and bypass this
76            # response
77            status = "200 OK"
78           
79        elif environ['PATH_INFO'] == '/test_accessGrantedToSecuredURI':
80            status = "200 OK"
81        else:
82            status = "404 Not found"
83               
84        start_response(status,
85                       [('Content-length', 
86                         str(len(TestAuthZMiddleware.response))),
87                        ('Content-type', 'text/plain')])
88        return [TestAuthZMiddleware.response]
89
90
91class BeakerSessionStub(dict):
92    """Emulate beaker.session session object for purposes of the unit tests
93    """
94    def save(self):
95        pass
96 
97   
98class NdgWSGIAuthZTestCase(BaseTestCase):
99
100    def __init__(self, *args, **kwargs):
101        BaseTestCase.__init__(self, *args, **kwargs)
102       
103        here_dir = os.path.dirname(os.path.abspath(__file__))
104        wsgiapp = loadapp('config:ndg-test.ini', relative_to=here_dir)
105        self.app = paste.fixture.TestApp(wsgiapp)
106       
107        self.startSiteAAttributeAuthority()
108       
109       
110
111    def test01CatchNoBeakerSessionFound(self):
112       
113        # PEPFilterConfigError is raised if no beaker.session is set in
114        # environ
115        try:
116            response = self.app.get('/test_200')
117        except NdgPIPMiddlewareConfigError, e:
118            print("ok - expected: %s exception: %s" % (e.__class__, e))
119       
120    def test02Ensure200WithNotLoggedInAndUnsecuredURI(self):
121       
122        # Check the authZ middleware leaves the response alone if the URI
123        # is not matched in the policy
124       
125        # Simulate a beaker.session in the environ
126        extra_environ={'beaker.session.ndg.security':BeakerSessionStub()}
127        response = self.app.get('/test_200',
128                                extra_environ=extra_environ)
129
130    def test03Catch401WithLoggedIn(self):
131       
132        # Check that the application being secured can raise a HTTP 401
133        # response and that this respected by the Authorization middleware
134        # even though a user is set in the session
135       
136        extra_environ={'beaker.session.ndg.security':
137                       BeakerSessionStub(username='testuser')}
138        response = self.app.get('/test_401', 
139                                extra_environ=extra_environ,
140                                status=401)
141
142    def test04Catch403WithLoggedIn(self):
143       
144        # Check that the application being secured can raise a HTTP 403
145        # response and that this respected by the Authorization middleware
146        # even though a user is set in the session
147       
148        extra_environ={'beaker.session.ndg.security':
149                       BeakerSessionStub(username='testuser')}
150        response = self.app.get('/test_403', 
151                                extra_environ=extra_environ,
152                                status=403)
153
154    def test05Catch401WithNotLoggedInAndSecuredURI(self):
155       
156        # AuthZ middleware grants access because the URI requested is not
157        # targeted in the policy
158       
159        # AuthZ middleware checks for username key in session set by AuthN
160        # handler
161        extra_environ={'beaker.session.ndg.security':BeakerSessionStub()}       
162        response = self.app.get('/test_accessDeniedToSecuredURI',
163                                extra_environ=extra_environ,
164                                status=401)
165       
166    def test06AccessDeniedForSecuredURI(self):
167       
168        # User is logged in but doesn't have the required credentials for
169        # access
170        extra_environ={'beaker.session.ndg.security':
171                       BeakerSessionStub(username='testuser')}
172       
173        response = self.app.get('/test_accessDeniedToSecuredURI',
174                                extra_environ=extra_environ,
175                                status=403)
176        self.assert_("Insufficient privileges to access the "
177                     "resource" in response)
178        print response
179
180    def test07AccessGrantedForSecuredURI(self):
181       
182        # User is logged in and has credentials for access to a URI secured
183        # by the policy file
184        extra_environ={'beaker.session.ndg.security':
185                       BeakerSessionStub(username='testuser')}
186       
187        response = self.app.get('/test_accessGrantedToSecuredURI',
188                                extra_environ=extra_environ,
189                                status=200)
190        self.assert_(TestAuthZMiddleware.response in response)
191        print response
192
193    def test08AccessDeniedForAdminQueryArg(self):
194       
195        # User is logged in but doesn't have the required credentials for
196        # access
197        extra_environ={'beaker.session.ndg.security':
198                       BeakerSessionStub(username='testuser')}
199       
200        # Try this URI with the query arg admin=1.  This will be picked up
201        # by the policy as a request requiring admin rights.  The request is
202        # denied as the user doesn't have these rights but this then calls
203        # into play the PEP result handler defined in this module,
204        # RedirectFollowingAccessDenied.  This class reinvokes the request
205        # but without the admin query argument.  Access is then granted for
206        # the redirected request
207        response = self.app.get('/test_accessGrantedToSecuredURI',
208                                params={'admin': 1},
209                                extra_environ=extra_environ,
210                                status=302)
211        try:
212            redirectResponse = response.follow(extra_environ=extra_environ)
213        except paste.fixture.AppError, e:
214            self.failIf(TestAuthZMiddleware.response not in response)
215        print response
216
217
218
219       
220class TestAuthZMiddleware(object):
221    '''Test Application for the Authentication handler to protect'''
222    response = "Test Authorization application"
223       
224    def __init__(self, app_conf, **local_conf):
225        pass
226   
227    def __call__(self, environ, start_response):
228       
229        if environ['PATH_INFO'] == '/test_401':
230            status = "401 Unauthorized"
231           
232        elif environ['PATH_INFO'] == '/test_403':
233            status = "403 Forbidden"
234           
235        elif environ['PATH_INFO'] == '/test_200':
236            status = "200 OK"
237           
238        elif environ['PATH_INFO'] == '/test_accessDeniedToSecuredURI':
239            # Nb. AuthZ middleware should intercept the request and bypass this
240            # response
241            status = "200 OK"
242           
243        elif environ['PATH_INFO'] == '/test_accessGrantedToSecuredURI':
244            status = "200 OK"
245        else:
246            status = "404 Not found"
247               
248        start_response(status,
249                       [('Content-length', 
250                         str(len(TestAuthZMiddleware.response))),
251                        ('Content-type', 'text/plain')])
252        return [TestAuthZMiddleware.response]
253
254
255class BeakerSessionStub(dict):
256    """Emulate beaker.session session object for purposes of the unit tests
257    """
258    def save(self):
259        pass
260 
261   
262class SamlWSGIAuthZTestCase(BaseTestCase):
263
264    def __init__(self, *args, **kwargs):       
265        BaseTestCase.__init__(self, *args, **kwargs)
266
267        here_dir = os.path.dirname(os.path.abspath(__file__))
268        wsgiapp = loadapp('config:saml-test.ini', relative_to=here_dir)
269        self.app = paste.fixture.TestApp(wsgiapp)
270       
271        self.startSiteAAttributeAuthority(withSSL=True,
272            port=SamlWSGIAuthZTestCase.SITEA_SSL_ATTRIBUTEAUTHORITY_PORTNUM)
273       
274
275    def test01CatchNoBeakerSessionFound(self):
276       
277        # PEPFilterConfigError is raised if no beaker.session is set in
278        # environ
279        try:
280            response = self.app.get('/test_200')
281        except SamlPIPMiddlewareConfigError, e:
282            print("ok - expected: %s exception: %s" % (e.__class__, e))
283       
284    def test02Ensure200WithNotLoggedInAndUnsecuredURI(self):
285       
286        # Check the authZ middleware leaves the response alone if the URI
287        # is not matched in the policy
288       
289        # Simulate a beaker.session in the environ
290        extra_environ={'beaker.session.ndg.security':BeakerSessionStub()}
291        response = self.app.get('/test_200',
292                                extra_environ=extra_environ)
293
294    def test03Catch401WithLoggedIn(self):
295       
296        # Check that the application being secured can raise a HTTP 401
297        # response and that this respected by the Authorization middleware
298        # even though a user is set in the session
299       
300        extra_environ = {
301            'beaker.session.ndg.security':
302                BeakerSessionStub(username=SamlWSGIAuthZTestCase.OPENID_URI)
303        }
304        response = self.app.get('/test_401', 
305                                extra_environ=extra_environ,
306                                status=401)
307
308    def test04Catch403WithLoggedIn(self):
309       
310        # Check that the application being secured can raise a HTTP 403
311        # response and that this respected by the Authorization middleware
312        # even though a user is set in the session
313       
314        extra_environ = {
315            'beaker.session.ndg.security':
316                BeakerSessionStub(username=SamlWSGIAuthZTestCase.OPENID_URI)
317        }
318        response = self.app.get('/test_403', 
319                                extra_environ=extra_environ,
320                                status=403)
321
322    def test05Catch401WithNotLoggedInAndSecuredURI(self):
323       
324        # AuthZ middleware grants access because the URI requested is not
325        # targeted in the policy
326       
327        # AuthZ middleware checks for username key in session set by AuthN
328        # handler
329        extra_environ={'beaker.session.ndg.security':BeakerSessionStub()}       
330        response = self.app.get('/test_accessDeniedToSecuredURI',
331                                extra_environ=extra_environ,
332                                status=401)
333       
334    def test06AccessDeniedForSecuredURI(self):
335       
336        # User is logged in but doesn't have the required credentials for
337        # access
338        extra_environ = {
339            'beaker.session.ndg.security':
340                BeakerSessionStub(username=SamlWSGIAuthZTestCase.OPENID_URI)
341        }
342       
343        response = self.app.get('/test_accessDeniedToSecuredURI',
344                                extra_environ=extra_environ,
345                                status=403)
346        self.assert_("Insufficient privileges to access the "
347                     "resource" in response)
348        print response
349
350    def test07AccessGrantedForSecuredURI(self):
351       
352        # User is logged in and has credentials for access to a URI secured
353        # by the policy file
354        extra_environ = {
355            'beaker.session.ndg.security':
356                BeakerSessionStub(username=SamlWSGIAuthZTestCase.OPENID_URI)
357        }
358       
359        response = self.app.get('/test_accessGrantedToSecuredURI',
360                                extra_environ=extra_environ,
361                                status=200)
362        self.assert_(TestAuthZMiddleware.response in response)
363        print response
364
365    def test08AccessDeniedForAdminQueryArg(self):
366       
367        # User is logged in but doesn't have the required credentials for
368        # access
369        extra_environ = {
370            'beaker.session.ndg.security':
371                BeakerSessionStub(username=SamlWSGIAuthZTestCase.OPENID_URI)
372        }
373       
374        # Try this URI with the query arg admin=1.  This will be picked up
375        # by the policy as a request requiring admin rights.  The request is
376        # denied as the user doesn't have these rights but this then calls
377        # into play the PEP result handler defined in this module,
378        # RedirectFollowingAccessDenied.  This class reinvokes the request
379        # but without the admin query argument.  Access is then granted for
380        # the redirected request
381        response = self.app.get('/test_accessGrantedToSecuredURI',
382                                params={'admin': 1},
383                                extra_environ=extra_environ,
384                                status=302)
385        try:
386            redirectResponse = response.follow(extra_environ=extra_environ)
387        except paste.fixture.AppError, e:
388            self.failIf(TestAuthZMiddleware.response not in response)
389        print response
390
391
392if __name__ == "__main__":
393    unittest.main()       
Note: See TracBrowser for help on using the repository browser.