1 import cherrypy
2 from cherrypy._cpcompat import md5, sha, ntob
3 from cherrypy.lib import httpauth
4
5 from cherrypy.test import helper
6
8
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(ntob(password)).hexdigest()
35
36 def fetch_password(username):
37 return sha(ntob('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(ntob('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 setup_server = staticmethod(setup_server)
56
57
63
75
87
89 self.getPage("/digest/")
90 self.assertStatus(401)
91
92 value = None
93 for k, v in self.headers:
94 if k.lower() == "www-authenticate":
95 if v.startswith("Digest"):
96 value = v
97 break
98
99 if value is None:
100 self._handlewebError("Digest authentification scheme was not found")
101
102 value = value[7:]
103 items = value.split(', ')
104 tokens = {}
105 for item in items:
106 key, value = item.split('=')
107 tokens[key.lower()] = value
108
109 missing_msg = "%s is missing"
110 bad_value_msg = "'%s' was expecting '%s' but found '%s'"
111 nonce = None
112 if 'realm' not in tokens:
113 self._handlewebError(missing_msg % 'realm')
114 elif tokens['realm'] != '"localhost"':
115 self._handlewebError(bad_value_msg % ('realm', '"localhost"', tokens['realm']))
116 if 'nonce' not in tokens:
117 self._handlewebError(missing_msg % 'nonce')
118 else:
119 nonce = tokens['nonce'].strip('"')
120 if 'algorithm' not in tokens:
121 self._handlewebError(missing_msg % 'algorithm')
122 elif tokens['algorithm'] != '"MD5"':
123 self._handlewebError(bad_value_msg % ('algorithm', '"MD5"', tokens['algorithm']))
124 if 'qop' not in tokens:
125 self._handlewebError(missing_msg % 'qop')
126 elif tokens['qop'] != '"auth"':
127 self._handlewebError(bad_value_msg % ('qop', '"auth"', tokens['qop']))
128
129
130 base_auth = 'Digest username="test", realm="wrong realm", nonce="%s", uri="/digest/", algorithm=MD5, response="%s", qop=auth, nc=%s, cnonce="1522e61005789929"'
131
132 auth = base_auth % (nonce, '', '00000001')
133 params = httpauth.parseAuthorization(auth)
134 response = httpauth._computeDigestResponse(params, 'test')
135
136 auth = base_auth % (nonce, response, '00000001')
137 self.getPage('/digest/', [('Authorization', auth)])
138 self.assertStatus(401)
139
140
141 base_auth = 'Digest username="test", realm="localhost", nonce="%s", uri="/digest/", algorithm=MD5, response="%s", qop=auth, nc=%s, cnonce="1522e61005789929"'
142
143 auth = base_auth % (nonce, '', '00000001')
144 params = httpauth.parseAuthorization(auth)
145 response = httpauth._computeDigestResponse(params, 'test')
146
147 auth = base_auth % (nonce, response, '00000001')
148 self.getPage('/digest/', [('Authorization', auth)])
149 self.assertStatus('200 OK')
150 self.assertBody("Hello test, you've been authorized.")
151