source: TI12-security/trunk/python/ndg.security.test/ndg/security/test/integration/authz/securedapp.py @ 5454

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.test/ndg/security/test/integration/authz/securedapp.py@5454
Revision 5454, 9.1 KB checked in by pjkersha, 11 years ago (diff)

Important fix: remove credentialWallet key on logout

Line 
1#!/usr/bin/env python
2"""NDG Security test harness for authorisation middleware used to secure an
3application
4
5NERC DataGrid Project
6"""
7__author__ = "P J Kershaw"
8__date__ = "20/11/08"
9__copyright__ = "(C) 2009 Science and Technology Facilities Council"
10__license__ = "BSD - See top-level directory for LICENSE file"
11__contact__ = "Philip.Kershaw@stfc.ac.uk"
12__revision__ = "$Id$"
13
14   
15def app_factory(globalConfig, **localConfig):
16    '''AuthZTestMiddleware factory for Paste app pattern'''
17    return AuthZTestMiddleware(None, globalConfig, **localConfig)
18
19def filter_app_factory(app, globalConfig, **localConfig):
20    '''AuthZTestMiddleware factory for Paste filter app pattern'''
21    return AuthZTestMiddleware(app, globalConfig, **localConfig)
22
23class AuthZTestMiddleware(object):
24    """This class simulates the application to be secured by the NDG Security
25    authorization middleware
26    """
27    method = {
28"/": 'default',
29"/test_401": "test_401",
30"/test_403": "test_403",
31"/test_securedURI": "test_securedURI",
32"/test_accessDeniedToSecuredURI": "test_accessDeniedToSecuredURI"
33    }
34    header = """        <h1>Authorisation Integration Tests:</h1>
35        <p>Test Authorisation middleware with no Session Manager running.
36        See the authz/ integration test directory for a configuration including
37        a Session Manager</p>
38        <p>These tests use require the security services application to be
39        running.  See securityserviceapp.py and securityservices.ini in the
40        authz_lite/ integration test directory.</p>
41        <h2>To Run:</h2>
42        <p>Try any of the links below.  When prompt for username and password,
43        enter one of the sets of credentials from securityservices.ini
44        openid.provider.authN.userCreds section.  The defaults are:
45        </p>
46        <p>pjk/testpassword</p>
47        <p>another/testpassword</p>
48        <p>The attributeinterface.py AttributeAuthority plugin is configured to
49        grant access to 'pjk' for all URLs below apart from
50        'test_accessDeniedToSecuredURI'.  The 'another' account will be denied
51        access from all URLs apart from 'test_401'</p>
52"""
53
54    def __init__(self, app, globalConfig, **localConfig):
55        self.app = app
56           
57    def __call__(self, environ, start_response):
58       
59        methodName = self.method.get(environ['PATH_INFO'], '').rstrip()
60        if methodName:
61            action = getattr(self, methodName)
62            return action(environ, start_response)
63        elif environ['PATH_INFO'] == '/logout':
64            return self.default(environ, start_response)
65       
66        elif self.app is not None:
67            return self.app(environ, start_response)
68        else:
69            start_response('404 Not Found', [('Content-type', 'text/plain')])
70            return "Authorisation integration tests: invalid URI"
71           
72    def default(self, environ, start_response):
73        if 'REMOTE_USER' in environ:
74            response = """<html>
75    <head/>
76    <body>
77        %s
78        <ul>%s</ul>
79        <p>You are logged in with OpenID [%s].  <a href="/logout">Logout</a></p>
80    </body>
81</html>
82""" % (AuthZTestMiddleware.header,
83       '\n'.join(['<li><a href="%s">%s</a></li>' % (link, name) 
84                 for link,name in self.method.items() if name != 'default']),
85       environ['REMOTE_USER'])
86       
87            start_response('200 OK', 
88                           [('Content-type', 'text/html'),
89                            ('Content-length', str(len(response)))])
90        else:
91            response = """<html>
92    <head/>
93    <body>
94        <h1>Authorisation integration tests:</h1>
95        <ul>%s</ul>
96    </body>
97</html>
98""" % '\n'.join(['<li><a href="%s">%s</a></li>' % (link, name) 
99                 for link,name in self.method.items() if name != 'default'])
100
101            start_response('200 OK', 
102                           [('Content-type', 'text/html'),
103                            ('Content-length', str(len(response)))])
104        return response
105
106    def test_401(self, environ, start_response):
107        if 'REMOTE_USER' in environ:
108            response = """<html>
109    <head/>
110    <body>
111        <h1>Authenticated!</h1>
112        <ul>%s</ul>
113        <p>You are logged in.  <a href="/logout">Logout</a></p>
114    </body>
115</html>
116""" % '\n'.join(['<li><a href="%s">%s</a></li>' % (link, name) 
117                 for link,name in self.method.items() if name != 'default'])
118
119            start_response('200 OK', 
120                           [('Content-type', 'text/html'),
121                            ('Content-length', str(len(response)))])
122        else:
123            response = "Trigger OpenID Relying Party..."
124            start_response('401 Unauthorized', 
125                           [('Content-type', 'text/plain'),
126                            ('Content-length', str(len(response)))])
127        return response
128
129    def test_403(self, environ, start_response):
130        """Trigger the Authorization middleware by returning a 403 Forbidden
131        HTTP status code from this URI"""
132       
133        if 'REMOTE_USER' in environ:
134            response = """<html>
135    <head/>
136    <body>
137        <h1>Authorised!</h1>
138        <ul>%s</ul>
139        <p>You are logged in with OpenID [%s].  <a href="/logout">Logout</a></p>
140    </body>
141</html>
142""" % ('\n'.join(['<li><a href="%s">%s</a></li>' % (link, name) 
143                 for link,name in self.method.items() if name != 'default']),
144       environ['REMOTE_USER'])
145
146            start_response('200 OK', 
147                           [('Content-type', 'text/html'),
148                            ('Content-length', str(len(response)))])
149        else:
150            response = ("Authorization middleware is triggered because this "
151                        "page returns a 403 Forbidden status.")
152            start_response('403 Forbidden', 
153                           [('Content-type', 'text/plain'),
154                            ('Content-length', str(len(response)))])
155        return response
156
157    def test_securedURI(self, environ, start_response):
158        """To be secured, the Authorization middleware must have this URI in
159        its policy"""
160        if 'REMOTE_USER' in environ:
161            response = """<html>
162    <head/>
163    <body>
164        <h1>Authorised for path [%s]!</h1>
165        <ul>%s</ul>
166        <p>You are logged in with OpenID [%s].  <a href="/logout">Logout</a></p>
167    </body>
168</html>
169""" % (environ['PATH_INFO'],
170       '\n'.join(['<li><a href="%s">%s</a></li>' % (link, name) 
171                 for link,name in self.method.items() if name != 'default']),
172       environ['REMOTE_USER'])
173
174
175            start_response('200 OK', 
176                           [('Content-type', 'text/html'),
177                            ('Content-length', str(len(response)))])
178        else:
179            response = ("Authorization middleware must have this URI in its "
180                        "policy in order to secure it!")
181            start_response('200 OK', 
182                           [('Content-type', 'text/plain'),
183                            ('Content-length', str(len(response)))])
184        return response
185
186
187    def test_accessDeniedToSecuredURI(self, environ, start_response):
188        """To be secured, the Authorization middleware must have this URI in
189        its policy and the user must not have the required role as specified
190        in the policy.  See ndg.security.test.config.attributeauthority.sitea
191        for user role settings retrieved from the attribute authority"""
192        if 'REMOTE_USER' in environ:
193            response = """<html>
194    <head/>
195    <body>
196        <h1>Authorised for path [%s]!</h1>
197        <ul>%s</ul>
198        <p>You are logged in with OpenID [%s].  <a href="/logout">Logout</a></p>
199    </body>
200</html>
201""" % (environ['PATH_INFO'],
202       '\n'.join(['<li><a href="%s">%s</a></li>' % (link, name) 
203                 for link,name in self.method.items() if name != 'default']),
204       environ['REMOTE_USER'])
205
206
207            start_response('200 OK', 
208                           [('Content-type', 'text/html'),
209                            ('Content-length', str(len(response)))])
210        else:
211            response = ("Authorization middleware must have this URI in its "
212                        "policy in order to secure it!")
213            start_response('200 OK', 
214                           [('Content-type', 'text/plain'),
215                            ('Content-length', str(len(response)))])
216        return response
217   
218    @classmethod
219    def app_factory(cls, globalConfig, **localConfig):
220        return cls(None, globalConfig, **localConfig)
221   
222    @classmethod
223    def filter_app_factory(cls, app, globalConfig, **localConfig):
224        return cls(app, globalConfig, **localConfig)
225   
226# To start run
227# $ paster serve services.ini or run this file as a script
228# $ ./securedapp.py [port #]
229if __name__ == '__main__':
230    import sys
231    import os
232    from os.path import dirname, abspath
233    import logging
234    logging.basicConfig(level=logging.DEBUG)
235
236    if len(sys.argv) > 1:
237        port = int(sys.argv[1])
238    else:
239        port = 7080
240       
241    cfgFilePath = os.path.join(dirname(abspath(__file__)), 'securedapp.ini')
242       
243    from paste.httpserver import serve
244    from paste.deploy import loadapp
245   
246    app = loadapp('config:%s' % cfgFilePath)
247    serve(app, host='0.0.0.0', port=port)
Note: See TracBrowser for help on using the repository browser.