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

root/branches/cherrypy-3.0.x/cherrypy/test/test_httpauth.py

Revision 1892 (checked in by lawouach, 10 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     root = Root()
50     root.digest = DigestProtected()
51     root.basic = BasicProtected()
52     root.basic2 = BasicProtected2()
53     cherrypy.tree.mount(root, config=conf)
54     cherrypy.config.update({'environment': 'test_suite'})
55
56 from cherrypy.test import helper
57
58 class HTTPAuthTest(helper.CPWebCase):
59
60     def testPublic(self):
61         self.getPage("/")
62         self.assertStatus('200 OK')
63         self.assertHeader('Content-Type', 'text/html')
64         self.assertBody('This is public.')
65
66     def testBasic(self):
67         self.getPage("/basic/")
68         self.assertStatus('401 Unauthorized')
69         self.assertHeader('WWW-Authenticate', 'Basic realm="localhost"')
70
71         self.getPage('/basic/', [('Authorization', 'Basic dGVzdDp0ZX60')])
72         self.assertStatus('401 Unauthorized')
73        
74         self.getPage('/basic/', [('Authorization', 'Basic dGVzdDp0ZXN0')])
75         self.assertStatus('200 OK')
76         self.assertBody("Hello test, you've been authorized.")
77
78     def testBasic2(self):
79         self.getPage("/basic2/")
80         self.assertStatus('401 Unauthorized')
81         self.assertHeader('WWW-Authenticate', 'Basic realm="localhost"')
82
83         self.getPage('/basic2/', [('Authorization', 'Basic dGVzdDp0ZX60')])
84         self.assertStatus('401 Unauthorized')
85        
86         self.getPage('/basic2/', [('Authorization', 'Basic dGVzdDp0ZXN0')])
87         self.assertStatus('200 OK')
88         self.assertBody("Hello test, you've been authorized.")
89
90     def testDigest(self):
91         self.getPage("/digest/")
92         self.assertStatus('401 Unauthorized')
93        
94         value = None
95         for k, v in self.headers:
96             if k.lower() == "www-authenticate":
97                 if v.startswith("Digest"):
98                     value = v
99                     break
100
101         if value is None:
102             self._handlewebError("Digest authentification scheme was not found")
103
104         value = value[7:]
105         items = value.split(', ')
106         tokens = {}
107         for item in items:
108             key, value = item.split('=')
109             tokens[key.lower()] = value
110            
111         missing_msg = "%s is missing"
112         bad_value_msg = "'%s' was expecting '%s' but found '%s'"
113         nonce = None
114         if 'realm' not in tokens:
115             self._handlewebError(missing_msg % 'realm')
116         elif tokens['realm'] != '"localhost"':
117             self._handlewebError(bad_value_msg % ('realm', '"localhost"', tokens['realm']))
118         if 'nonce' not in tokens:
119             self._handlewebError(missing_msg % 'nonce')
120         else:
121             nonce = tokens['nonce'].strip('"')
122         if 'algorithm' not in tokens:
123             self._handlewebError(missing_msg % 'algorithm')
124         elif tokens['algorithm'] != '"MD5"':
125             self._handlewebError(bad_value_msg % ('algorithm', '"MD5"', tokens['algorithm']))
126         if 'qop' not in tokens:
127             self._handlewebError(missing_msg % 'qop')
128         elif tokens['qop'] != '"auth"':
129             self._handlewebError(bad_value_msg % ('qop', '"auth"', tokens['qop']))
130
131         # Test a wrong 'realm' value
132         base_auth = 'Digest username="test", realm="wrong realm", nonce="%s", uri="/digest/", algorithm=MD5, response="%s", qop=auth, nc=%s, cnonce="1522e61005789929"'
133
134         auth = base_auth % (nonce, '', '00000001')
135         params = httpauth.parseAuthorization(auth)
136         response = httpauth._computeDigestResponse(params, 'test')
137        
138         auth = base_auth % (nonce, response, '00000001')
139         self.getPage('/digest/', [('Authorization', auth)])
140         self.assertStatus('401 Unauthorized')
141        
142         # Test that must pass
143         base_auth = 'Digest username="test", realm="localhost", nonce="%s", uri="/digest/", algorithm=MD5, response="%s", qop=auth, nc=%s, cnonce="1522e61005789929"'
144
145         auth = base_auth % (nonce, '', '00000001')
146                
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