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

root/trunk/cherrypy/test/test_httpauth.py

Revision 1891 (checked in by lawouach, 3 months ago)

Fix for #787 only for digest though as basic responses don't provide the realm

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

Hosted by WebFaction

Log in as guest/cpguest to create tickets