source: TI12-security/trunk/MyProxyServerUtils/myproxy/server/test/test_httpbasicauth.py @ 6897

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/MyProxyServerUtils/myproxy/server/test/test_httpbasicauth.py@6897
Revision 6897, 6.4 KB checked in by pjkersha, 10 years ago (diff)

Fixed setting of authentication realm for HTTP Basic Auth middleware and improved interface to callback function by providing a exception type for the callback function to use to pass back message and HTTP status code.

Line 
1#!/usr/bin/env python
2"""Unit tests for MyProxy WSGI Middleware classes and Application
3"""
4__author__ = "P J Kershaw"
5__date__ = "21/05/10"
6__copyright__ = "(C) 2010 Science and Technology Facilities Council"
7__license__ = "BSD - see LICENSE file in top-level directory"
8__contact__ = "Philip.Kershaw@stfc.ac.uk"
9__revision__ = '$Id: $'
10import logging
11
12import unittest
13import os
14import base64
15
16import paste.fixture
17from paste.deploy import loadapp
18
19from myproxy.server.wsgi.httpbasicauth import (HttpBasicAuthMiddleware,
20                                               HttpBasicAuthResponseException)
21
22
23class TestApp(object):
24    def __init__(self, global_conf, **app_conf):
25        pass
26   
27    def __call__(self, environ, start_response):
28        contentType = 'text/plain'
29        response = 'Authenticated!'
30        status = 200
31        start_response(status,
32                       [('Content-type', contentType),
33                        ('Content-Length', str(len(response)))])
34        return [response]
35   
36           
37class TestHttpBasicAuthCallBackAppMiddleware(object):
38    """Add an authentication function to the environ for HttpBasicAuthMiddleware
39    to pick up and use.  It behaves as an application returning a response
40    """   
41    USERNAME = 'myusername'
42    PASSWORD = 'mypassword'
43    SUCCESS_RESPONSE = 'AUTHENTICATED'
44    FAILURE_RESPONSE = 'FAILED'
45   
46    def __init__(self, app, global_conf, **app_conf):
47        self.app = app
48       
49    def __call__(self, environ, start_response):
50        def authenticationApp(environ, start_response, username, password):
51            """Authentication callback application - its responsible for the
52            response message and response code
53            """
54            if (username == self.__class__.USERNAME and
55                password == self.__class__.PASSWORD):
56                response = self.__class__.SUCCESS_RESPONSE
57                status = '200 OK'
58            else:
59                response = self.__class__.FAILURE_RESPONSE
60                status = '401 Unauthorized'
61               
62            start_response(status,
63                           [('Content-type', 'text/plain'),
64                            ('Content-Length', str(len(response)))])
65            return [response]
66           
67        environ['HTTPBASICAUTH_FUNC'] = authenticationApp
68       
69        return self.app(environ, start_response)
70
71
72class TestHttpBasicAuthCallBackMiddleware(object):
73    """Add an authentication function to the environ for HttpBasicAuthMiddleware
74    to pick up and use.  The callback does not return a response leaving control
75    with the HttpBasicAuthMiddleware
76    """   
77    USERNAME = 'myusername'
78    PASSWORD = 'mypassword'
79   
80    def __init__(self, app, global_conf, **app_conf):
81        self.app = app
82       
83    def __call__(self, environ, start_response):
84        def authenticate(environ, start_response, username, password):
85            if (username != self.__class__.USERNAME or
86                password != self.__class__.PASSWORD):
87                raise HttpBasicAuthResponseException("Invalid credentials")
88           
89        environ['HTTPBASICAUTH_FUNC'] = authenticate
90       
91        return self.app(environ, start_response)
92   
93
94class HttpBasicAuthMiddlewareTestCase(unittest.TestCase):
95    CONFIG_FILE = 'httpbasicauth.ini'
96   
97    def __init__(self, *args, **kwargs):
98        here_dir = os.path.dirname(os.path.abspath(__file__))
99        configFilePath = ('config:%s' % 
100                          HttpBasicAuthMiddlewareTestCase.CONFIG_FILE)
101        wsgiapp = loadapp(configFilePath, relative_to=here_dir)
102        self.app = paste.fixture.TestApp(wsgiapp)
103         
104        unittest.TestCase.__init__(self, *args, **kwargs)
105       
106    def test01NoHttpBasicAuthHeader(self):
107        # Try with no HTTP Basic Auth HTTP header
108        response = self.app.get('/auth', status=401)
109           
110    def test02ValidCredentials(self):
111        # Try with no HTTP Basic Auth HTTP header
112        username = TestHttpBasicAuthCallBackAppMiddleware.USERNAME
113        password = TestHttpBasicAuthCallBackAppMiddleware.PASSWORD
114       
115        base64String = base64.encodestring('%s:%s' % (username, password))[:-1]
116        authHeader =  "Basic %s" % base64String
117        headers = {'Authorization': authHeader}
118       
119        response = self.app.get('/auth', headers=headers, status=200)
120        self.assert_((TestHttpBasicAuthCallBackAppMiddleware.SUCCESS_RESPONSE in
121                      response))
122                     
123    def test03InvalidCredentials(self):
124        # Try with no HTTP Basic Auth HTTP header
125        username = 'x'
126        password = 'y'
127       
128        base64String = base64.encodestring('%s:%s' % (username, password))[:-1]
129        authHeader =  "Basic %s" % base64String
130        headers = {'Authorization': authHeader}
131       
132        response = self.app.get('/auth', headers=headers, status=401)
133        self.assert_((TestHttpBasicAuthCallBackAppMiddleware.FAILURE_RESPONSE in
134                      response))
135       
136    def _createCallbackMiddleware(self):
137        # Test creating app independently of PasteScript and using an
138        # alternate middleware which doesn't return a response but simply
139        # raises a 401 exception type if input credentials don't match
140        app = TestApp({})
141        app = HttpBasicAuthMiddleware.filter_app_factory(app, {},
142                                prefix='',
143                                authnFuncEnvironKeyName='HTTPBASICAUTH_FUNC')
144        app = TestHttpBasicAuthCallBackMiddleware(app, {})
145
146        self.app2 = paste.fixture.TestApp(app)
147       
148    def test04SimpleCBMiddlewareWithValidCredentials(self):
149        self._createCallbackMiddleware()
150        username = TestHttpBasicAuthCallBackAppMiddleware.USERNAME
151        password = TestHttpBasicAuthCallBackAppMiddleware.PASSWORD
152       
153        base64String = base64.encodestring('%s:%s' % (username, password))[:-1]
154        authHeader =  "Basic %s" % base64String
155        headers = {'Authorization': authHeader}
156       
157        response = self.app.get('/auth', headers=headers, status=200)
158       
159    def test05SimpleCBMiddlewareWithInvalidCredentials(self):
160        self._createCallbackMiddleware()
161        username = 'a'
162        password = 'b'
163       
164        base64String = base64.encodestring('%s:%s' % (username, password))[:-1]
165        authHeader =  "Basic %s" % base64String
166        headers = {'Authorization': authHeader}
167       
168        response = self.app.get('/auth', headers=headers, status=401)       
169
170   
Note: See TracBrowser for help on using the repository browser.