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

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

Added additional debug logging and improved error handling

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    return AuthZTestMiddleware(None, globalConfig, **localConfig)
17
18def filter_app_factory(app, globalConfig, **localConfig):
19    return AuthZTestMiddleware(app, globalConfig, **localConfig)
20
21class AuthZTestMiddleware(object):
22    """This class simulates the application to be secured by the NDG Security
23    authorization middleware
24    """
25    method = {
26"/": 'default',
27"/test_401": "test_401",
28"/test_403": "test_403",
29"/test_securedURI": "test_securedURI",
30"/test_accessDeniedToSecuredURI": "test_accessDeniedToSecuredURI"
31    }
32
33    def __init__(self, app, globalConfig, **localConfig):
34        self.app = app
35           
36    def __call__(self, environ, start_response):
37       
38        methodName = self.method.get(environ['PATH_INFO'], '').rstrip()
39        if methodName:
40            action = getattr(self, methodName)
41            return action(environ, start_response)
42        elif environ['PATH_INFO'] == '/logout':
43            return self.default(environ, start_response)
44       
45        elif self.app is not None:
46            return self.app(environ, start_response)
47        else:
48            start_response('404 Not Found', [('Content-type', 'text/plain')])
49            return "Authorisation integration tests: invalid URI"
50           
51    def default(self, environ, start_response):
52        if 'REMOTE_USER' in environ:
53            response = """<html>
54    <head/>
55    <body>
56        <h1>Authorisation integration tests:</h1>
57        <ul>%s</ul>
58        <p>You are logged in with OpenID [%s].  <a href="/logout">Logout</a></p>
59    </body>
60</html>
61""" % ('\n'.join(['<li><a href="%s">%s</a></li>' % (link, name) 
62                 for link,name in self.method.items() if name != 'default']),
63       environ['REMOTE_USER'])
64       
65            start_response('200 OK', 
66                           [('Content-type', 'text/html'),
67                            ('Content-length', str(len(response)))])
68        else:
69            response = """<html>
70    <head/>
71    <body>
72        <h1>Authorisation integration tests:</h1>
73        <ul>%s</ul>
74    </body>
75</html>
76""" % '\n'.join(['<li><a href="%s">%s</a></li>' % (link, name) 
77                 for link,name in self.method.items() if name != 'default'])
78
79            start_response('200 OK', 
80                           [('Content-type', 'text/html'),
81                            ('Content-length', str(len(response)))])
82        return response
83
84    def test_401(self, environ, start_response):
85        if 'REMOTE_USER' in environ:
86            response = """<html>
87    <head/>
88    <body>
89        <h1>Authenticated!</h1>
90        <ul>%s</ul>
91        <p>You are logged in.  <a href="/logout">Logout</a></p>
92    </body>
93</html>
94""" % '\n'.join(['<li><a href="%s">%s</a></li>' % (link, name) 
95                 for link,name in self.method.items() if name != 'default'])
96
97            start_response('200 OK', 
98                           [('Content-type', 'text/html'),
99                            ('Content-length', str(len(response)))])
100        else:
101            response = "Trigger OpenID Relying Party..."
102            start_response('401 Unauthorized', 
103                           [('Content-type', 'text/plain'),
104                            ('Content-length', str(len(response)))])
105        return response
106
107    def test_403(self, environ, start_response):
108        """Trigger the Authorization middleware by returning a 403 Forbidden
109        HTTP status code from this URI"""
110       
111        if 'REMOTE_USER' in environ:
112            response = """<html>
113    <head/>
114    <body>
115        <h1>Authorised!</h1>
116        <ul>%s</ul>
117        <p>You are logged in with OpenID [%s].  <a href="/logout">Logout</a></p>
118    </body>
119</html>
120""" % ('\n'.join(['<li><a href="%s">%s</a></li>' % (link, name) 
121                 for link,name in self.method.items() if name != 'default']),
122       environ['REMOTE_USER'])
123
124            start_response('200 OK', 
125                           [('Content-type', 'text/html'),
126                            ('Content-length', str(len(response)))])
127        else:
128            response = ("Authorization middleware is triggered becuase this "
129                        "page returns a 403 Forbidden status.")
130            start_response('403 Forbidden', 
131                           [('Content-type', 'text/plain'),
132                            ('Content-length', str(len(response)))])
133        return response
134
135    def test_securedURI(self, environ, start_response):
136        """To be secured, the Authorization middleware must have this URI in
137        its policy"""
138        if 'REMOTE_USER' in environ:
139            response = """<html>
140    <head/>
141    <body>
142        <h1>Authorised for path [%s]!</h1>
143        <ul>%s</ul>
144        <p>You are logged in with OpenID [%s].  <a href="/logout">Logout</a></p>
145    </body>
146</html>
147""" % (environ['PATH_INFO'],
148       '\n'.join(['<li><a href="%s">%s</a></li>' % (link, name) 
149                 for link,name in self.method.items() if name != 'default']),
150       environ['REMOTE_USER'])
151
152
153            start_response('200 OK', 
154                           [('Content-type', 'text/html'),
155                            ('Content-length', str(len(response)))])
156        else:
157            response = ("Authorization middleware must have this URI in its "
158                        "policy in order to secure it!")
159            start_response('200 OK', 
160                           [('Content-type', 'text/plain'),
161                            ('Content-length', str(len(response)))])
162        return response
163
164
165    def test_accessDeniedToSecuredURI(self, environ, start_response):
166        """To be secured, the Authorization middleware must have this URI in
167        its policy and the user must not have the required role as specified
168        in the policy.  See ndg.security.test.config.attributeauthority.sitea
169        for user role settings retrieved from the attribute authority"""
170        if 'REMOTE_USER' in environ:
171            response = """<html>
172    <head/>
173    <body>
174        <h1>Authorised for path [%s]!</h1>
175        <ul>%s</ul>
176        <p>You are logged in with OpenID [%s].  <a href="/logout">Logout</a></p>
177    </body>
178</html>
179""" % (environ['PATH_INFO'],
180       '\n'.join(['<li><a href="%s">%s</a></li>' % (link, name) 
181                 for link,name in self.method.items() if name != 'default']),
182       environ['REMOTE_USER'])
183
184
185            start_response('200 OK', 
186                           [('Content-type', 'text/html'),
187                            ('Content-length', str(len(response)))])
188        else:
189            response = ("Authorization middleware must have this URI in its "
190                        "policy in order to secure it!")
191            start_response('200 OK', 
192                           [('Content-type', 'text/plain'),
193                            ('Content-length', str(len(response)))])
194        return response
195   
196    @classmethod
197    def app_factory(cls, globalConfig, **localConfig):
198        return cls(None, globalConfig, **localConfig)
199   
200    @classmethod
201    def filter_app_factory(cls, app, globalConfig, **localConfig):
202        return cls(app, globalConfig, **localConfig)
203   
204# To start run
205# $ paster serve services.ini or run this file as a script
206# $ ./securedapp.py [port #]
207if __name__ == '__main__':
208    import sys
209    import os
210    from os.path import dirname, abspath
211    import logging
212    logging.basicConfig(level=logging.DEBUG)
213
214    if len(sys.argv) > 1:
215        port = int(sys.argv[1])
216    else:
217        port = 7080
218       
219    cfgFilePath = os.path.join(dirname(abspath(__file__)), 'securedapp.ini')
220       
221    from paste.httpserver import serve
222    from paste.deploy import loadapp
223   
224    app = loadapp('config:%s' % cfgFilePath)
225    serve(app, host='0.0.0.0', port=port)
Note: See TracBrowser for help on using the repository browser.