Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

root/trunk/cherrypy/test/test_httpauth.py

Revision 2637 (checked in by jtate, 2 weeks ago)

Convert the tests to use nose instead of our own runner. This strips out much coverage and profiling (handled by nose) and lets you focus on writing tests.

The biggest changes that have to be done in the tests classes is you have to put the "setup_server" method on the class(es) that need them when running. If you need it for multiple classes, you can use staticmethod() to attach it to multiple classes without using inheritance.

  • Property svn:eol-style set to native
Line 
1 from cherrypy.test import test
2
3
4 try:
5     # Python 2.5+
6     from hashlib import md5, sha1 as sha
7 except ImportError:
8     from md5 import new as md5
9     from sha import new as sha
10
11 import cherrypy
12 from cherrypy.lib import httpauth
13
14 from cherrypy.test import helper
15
16 class HTTPAuthTest(helper.CPWebCase):
17     @staticmethod
18     def setup_server():
19         class Root:
20             def index(self):
21                 return "This is public."
22             index.exposed = True
23
24         class DigestProtected:
25             def index(self):
26                 return "Hello %s, you've been authorized." % cherrypy.request.login
27             index.exposed = True
28
29         class BasicProtected:
30             def index(self):
31                 return "Hello %s, you've been authorized." % cherrypy.request.login
32             index.exposed = True
33
34         class BasicProtected2:
35             def index(self):
36                 return "Hello %s, you've been authorized." % cherrypy.request.login
37             index.exposed = True
38
39         def fetch_users():
40             return {'test': 'test'}
41
42         def sha_password_encrypter(password):
43             return sha(password).hexdigest()
44        
45         def fetch_password(username):
46             return sha('test').hexdigest()
47
48         conf = {'/digest': {'tools.digest_auth.on': True,
49                             'tools.digest_auth.realm': 'localhost',
50                             'tools.digest_auth.users': fetch_users},
51                 '/basic': {'tools.basic_auth.on': True,
52                            'tools.basic_auth.realm': 'localhost',
53                            'tools.basic_auth.users': {'test': md5('test').hexdigest()}},
54                 '/basic2': {'tools.basic_auth.on': True,
55                             'tools.basic_auth.realm': 'localhost',
56                             'tools.basic_auth.users': fetch_password,
57                             'tools.basic_auth.encrypt': sha_password_encrypter}}
58                
59         root = Root()
60         root.digest = DigestProtected()
61         root.basic = BasicProtected()
62         root.basic2 = BasicProtected2()
63         cherrypy.tree.mount(root, config=conf)
64
65
66     def testPublic(self):
67         self.getPage("/")
68         self.assertStatus('200 OK')
69         self.assertHeader('Content-Type', 'text/html;charset=utf-8')
70         self.assertBody('This is public.')
71
72     def testBasic(self):
73         self.getPage("/basic/")
74         self.assertStatus(401)
75         self.assertHeader('WWW-Authenticate', 'Basic realm="localhost"')
76
77         self.getPage('/basic/', [('Authorization', 'Basic dGVzdDp0ZX60')])
78         self.assertStatus(401)
79        
80         self.getPage('/basic/', [('Authorization', 'Basic dGVzdDp0ZXN0')])
81         self.assertStatus('200 OK')
82         self.assertBody("Hello test, you've been authorized.")
83
84     def testBasic2(self):
85         self.getPage("/basic2/")
86         self.assertStatus(401)
87         self.assertHeader('WWW-Authenticate', 'Basic realm="localhost"')
88
89         self.getPage('/basic2/', [('Authorization', 'Basic dGVzdDp0ZX60')])
90         self.assertStatus(401)
91        
92         self.getPage('/basic2/', [('Authorization', 'Basic dGVzdDp0ZXN0')])
93         self.assertStatus('200 OK')
94         self.assertBody("Hello test, you've been authorized.")
95
96     def testDigest(self):
97         self.getPage("/digest/")
98         self.assertStatus(401)
99        
100         value = None
101         for k, v in self.headers:
102             if k.lower() == "www-authenticate":
103                 if v.startswith("Digest"):
104                     value = v
105                     break
106
107         if value is None:
108             self._handlewebError("Digest authentification scheme was not found")
109
110         value = value[7:]
111         items = value.split(', ')
112         tokens = {}
113         for item in items:
114             key, value = item.split('=')
115             tokens[key.lower()] = value
116            
117         missing_msg = "%s is missing"
118         bad_value_msg = "'%s' was expecting '%s' but found '%s'"
119         nonce = None
120         if 'realm' not in tokens:
121             self._handlewebError(missing_msg % 'realm')
122         elif tokens['realm'] != '"localhost"':
123             self._handlewebError(bad_value_msg % ('realm', '"localhost"', tokens['realm']))
124         if 'nonce' not in tokens:
125             self._handlewebError(missing_msg % 'nonce')
126         else:
127             nonce = tokens['nonce'].strip('"')
128         if 'algorithm' not in tokens:
129             self._handlewebError(missing_msg % 'algorithm')
130         elif tokens['algorithm'] != '"MD5"':
131             self._handlewebError(bad_value_msg % ('algorithm', '"MD5"', tokens['algorithm']))
132         if 'qop' not in tokens:
133             self._handlewebError(missing_msg % 'qop')
134         elif tokens['qop'] != '"auth"':
135             self._handlewebError(bad_value_msg % ('qop', '"auth"', tokens['qop']))
136
137         # Test a wrong 'realm' value
138         base_auth = 'Digest username="test", realm="wrong realm", nonce="%s", uri="/digest/", algorithm=MD5, response="%s", qop=auth, nc=%s, cnonce="1522e61005789929"'
139
140         auth = base_auth % (nonce, '', '00000001')
141         params = httpauth.parseAuthorization(auth)
142         response = httpauth._computeDigestResponse(params, 'test')
143        
144         auth = base_auth % (nonce, response, '00000001')
145         self.getPage('/digest/', [('Authorization', auth)])
146         self.assertStatus(401)
147
148         # Test that must pass
149         base_auth = 'Digest username="test", realm="localhost", nonce="%s", uri="/digest/", algorithm=MD5, response="%s", qop=auth, nc=%s, cnonce="1522e61005789929"'
150
151         auth = base_auth % (nonce, '', '00000001')
152         params = httpauth.parseAuthorization(auth)
153         response = httpauth._computeDigestResponse(params, 'test')
154        
155         auth = base_auth % (nonce, response, '00000001')
156         self.getPage('/digest/', [('Authorization', auth)])
157         self.assertStatus('200 OK')
158         self.assertBody("Hello test, you've been authorized.")
159            
160 if __name__ == "__main__":
161     helper.testmain()
Note: See TracBrowser for help on using the browser.

Hosted by WebFaction

Log in as guest/cpguest to create tickets