1
2
3
4
5
6 import cherrypy
7 from cherrypy.lib import auth_digest
8
9 from cherrypy.test import helper
10
11
13
15 class Root:
16
17 def index(self):
18 return "This is public."
19 index.exposed = True
20
21 class DigestProtected:
22
23 def index(self):
24 return "Hello %s, you've been authorized." % (
25 cherrypy.request.login)
26 index.exposed = True
27
28 def fetch_users():
29 return {'test': 'test'}
30
31 get_ha1 = cherrypy.lib.auth_digest.get_ha1_dict_plain(fetch_users())
32 conf = {'/digest': {'tools.auth_digest.on': True,
33 'tools.auth_digest.realm': 'localhost',
34 'tools.auth_digest.get_ha1': get_ha1,
35 'tools.auth_digest.key': 'a565c27146791cfb',
36 'tools.auth_digest.debug': 'True'}}
37
38 root = Root()
39 root.digest = DigestProtected()
40 cherrypy.tree.mount(root, config=conf)
41 setup_server = staticmethod(setup_server)
42
48
50 self.getPage("/digest/")
51 self.assertStatus(401)
52
53 value = None
54 for k, v in self.headers:
55 if k.lower() == "www-authenticate":
56 if v.startswith("Digest"):
57 value = v
58 break
59
60 if value is None:
61 self._handlewebError(
62 "Digest authentification scheme was not found")
63
64 value = value[7:]
65 items = value.split(', ')
66 tokens = {}
67 for item in items:
68 key, value = item.split('=')
69 tokens[key.lower()] = value
70
71 missing_msg = "%s is missing"
72 bad_value_msg = "'%s' was expecting '%s' but found '%s'"
73 nonce = None
74 if 'realm' not in tokens:
75 self._handlewebError(missing_msg % 'realm')
76 elif tokens['realm'] != '"localhost"':
77 self._handlewebError(bad_value_msg %
78 ('realm', '"localhost"', tokens['realm']))
79 if 'nonce' not in tokens:
80 self._handlewebError(missing_msg % 'nonce')
81 else:
82 nonce = tokens['nonce'].strip('"')
83 if 'algorithm' not in tokens:
84 self._handlewebError(missing_msg % 'algorithm')
85 elif tokens['algorithm'] != '"MD5"':
86 self._handlewebError(bad_value_msg %
87 ('algorithm', '"MD5"', tokens['algorithm']))
88 if 'qop' not in tokens:
89 self._handlewebError(missing_msg % 'qop')
90 elif tokens['qop'] != '"auth"':
91 self._handlewebError(bad_value_msg %
92 ('qop', '"auth"', tokens['qop']))
93
94 get_ha1 = auth_digest.get_ha1_dict_plain({'test': 'test'})
95
96
97 base_auth = ('Digest username="test", '
98 'realm="wrong realm", '
99 'nonce="%s", '
100 'uri="/digest/", '
101 'algorithm=MD5, '
102 'response="%s", '
103 'qop=auth, '
104 'nc=%s, '
105 'cnonce="1522e61005789929"')
106
107 auth_header = base_auth % (
108 nonce, '11111111111111111111111111111111', '00000001')
109 auth = auth_digest.HttpDigestAuthorization(auth_header, 'GET')
110
111 ha1 = get_ha1(auth.realm, 'test')
112 response = auth.request_digest(ha1)
113
114 auth_header = base_auth % (nonce, response, '00000001')
115 self.getPage('/digest/', [('Authorization', auth_header)])
116 self.assertStatus(401)
117
118
119 base_auth = ('Digest username="test", '
120 'realm="localhost", '
121 'nonce="%s", '
122 'uri="/digest/", '
123 'algorithm=MD5, '
124 'response="%s", '
125 'qop=auth, '
126 'nc=%s, '
127 'cnonce="1522e61005789929"')
128
129 auth_header = base_auth % (
130 nonce, '11111111111111111111111111111111', '00000001')
131 auth = auth_digest.HttpDigestAuthorization(auth_header, 'GET')
132
133 ha1 = get_ha1('localhost', 'test')
134 response = auth.request_digest(ha1)
135
136 auth_header = base_auth % (nonce, response, '00000001')
137 self.getPage('/digest/', [('Authorization', auth_header)])
138 self.assertStatus('200 OK')
139 self.assertBody("Hello test, you've been authorized.")
140