Merge lp:~facundo/canonical-identity-provider/new-era-discharge into lp:canonical-identity-provider/release
- new-era-discharge
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 1440 |
Proposed branch: | lp:~facundo/canonical-identity-provider/new-era-discharge |
Merge into: | lp:canonical-identity-provider/release |
Diff against target: |
952 lines (+461/-107) 9 files modified
src/api/v20/handlers.py (+41/-16) src/api/v20/tests/test_handlers.py (+103/-18) src/identityprovider/auth.py (+84/-21) src/identityprovider/tests/test_auth.py (+219/-38) src/identityprovider/tests/test_forms.py (+6/-6) src/identityprovider/tests/test_macaroon.py (+1/-1) src/identityprovider/tests/test_views_server.py (+4/-4) src/identityprovider/tests/utils.py (+1/-1) src/identityprovider/views/server.py (+2/-2) |
To merge this branch: | bzr merge lp:~facundo/canonical-identity-provider/new-era-discharge |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant | Needs Fixing | ||
Facundo Batista (community) | Approve | ||
Ricardo Kirkner (community) | Approve | ||
Review via email: mp+293879@code.launchpad.net |
Commit message
Accept the caveat_id (instead of macaroon) and return the unbound discharge (instead of binding it) for both create and refresh discharges.
Description of the change
Accept the caveat_id (instead of macaroon) and return the unbound discharge (instead of binding it) for both create and refresh discharges.
Facundo Batista (facundo) : | # |
Ubuntu One Auto Pilot (otto-pilot) wrote : | # |
The attempt to merge lp:~facundo/canonical-identity-provider/new-era-discharge into lp:canonical-identity-provider failed. Below is the output from the failed tests.
Bootstrapping...
rm -rf /mnt/tarmac/
rm -rf branches/wheels
rm -rf branches/*
rm -rf staticfiles
rm -f lib/versioninfo.py
find -name '*.pyc' -delete
find -name '*.~*' -delete
Not deleting /mnt/tarmac/
New python executable in /mnt/tarmac/
Installing setuptools, pip...done.
/usr/lib/
touch branches/last_build
[ -d branches/wheels ] && (cd branches/wheels && bzr pull) || (bzr branch lp:~ubuntuone-pqm-team/canonical-identity-provider/dependencies branches/wheels)
bzr version-info --format=python > lib/versioninfo.py
/mnt/tarmac/
Ignoring indexes: https:/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Requirement already satisfied (use --upgrade to upgrade): oops==0.0.13 in /usr/lib/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Downloading/
Requirement already s...
William Grant (wgrant) : | # |
Facundo Batista (facundo) : | # |
William Grant (wgrant) : | # |
Facundo Batista (facundo) wrote : | # |
Addressed the "no caveat id in refreshing" issue
Preview Diff
1 | === modified file 'src/api/v20/handlers.py' |
2 | --- src/api/v20/handlers.py 2016-04-18 15:53:18 +0000 |
3 | +++ src/api/v20/handlers.py 2016-05-05 12:45:29 +0000 |
4 | @@ -58,6 +58,7 @@ |
5 | TokenScope, |
6 | ) |
7 | from identityprovider.signals import login_failed, login_succeeded |
8 | +from identityprovider.stats import stats |
9 | from identityprovider.timeline_helpers import get_request_timing_function |
10 | from identityprovider.utils import redirection_url_for_token |
11 | |
12 | @@ -446,11 +447,19 @@ |
13 | if 'macaroon' in data: |
14 | simple_macaroon = True |
15 | root_macaroons_info = [(None, data['macaroon'])] |
16 | + stats.increment('macaroon.discharge', key='single_macaroon') |
17 | elif 'macaroons' in data: |
18 | simple_macaroon = False |
19 | root_macaroons_info = data['macaroons'] |
20 | + stats.increment('macaroon.discharge', key='multi_macaroons') |
21 | + elif 'caveat_id' in data: |
22 | + simple_macaroon = True |
23 | + root_macaroons_info = None |
24 | + caveat_id = data['caveat_id'] |
25 | + stats.increment('macaroon.discharge', key='caveat_id') |
26 | else: |
27 | - missing = {'macaroon or macaroons': [FIELD_REQUIRED]} |
28 | + # let's flag the new one only, not the deprecated ones |
29 | + missing = {'caveat_id': [FIELD_REQUIRED]} |
30 | return errors.INVALID_DATA(**missing) |
31 | |
32 | account = None |
33 | @@ -490,16 +499,22 @@ |
34 | if response is not None: |
35 | return response |
36 | |
37 | - all_discharges = [] |
38 | - for mac_id, root_macaroon_raw in root_macaroons_info: |
39 | - try: |
40 | - discharge = auth.build_discharge_macaroon( |
41 | - account, root_macaroon_raw) |
42 | - except ValidationError: |
43 | - return errors.INVALID_DATA() |
44 | - except AuthenticationError: |
45 | - return errors.INVALID_CREDENTIALS() |
46 | - all_discharges.append((mac_id, discharge.serialize())) |
47 | + try: |
48 | + if root_macaroons_info is None: |
49 | + discharge = auth.build_discharge_macaroon(account, caveat_id) |
50 | + all_discharges = [(None, discharge.serialize())] |
51 | + else: |
52 | + # 2016-05-03: this is deprecated, just supporting it until |
53 | + # no more clients send root macaroon(s) |
54 | + all_discharges = [] |
55 | + for mac_id, root_macaroon_raw in root_macaroons_info: |
56 | + discharge = auth.build_discharge_macaroon_from_root( |
57 | + account, root_macaroon_raw) |
58 | + all_discharges.append((mac_id, discharge.serialize())) |
59 | + except ValidationError: |
60 | + return errors.INVALID_DATA() |
61 | + except AuthenticationError: |
62 | + return errors.INVALID_CREDENTIALS() |
63 | |
64 | response = rc.ALL_OK |
65 | if simple_macaroon: |
66 | @@ -523,16 +538,26 @@ |
67 | |
68 | data = request.data |
69 | try: |
70 | - root_macaroon_raw = data['root_macaroon'] |
71 | discharge_macaroon_raw = data['discharge_macaroon'] |
72 | except KeyError: |
73 | - expected = {'root_macaroon', 'discharge_macaroon'} |
74 | - missing = dict((k, [FIELD_REQUIRED]) for k in expected - set(data)) |
75 | + missing = {'discharge_macaroon': [FIELD_REQUIRED]} |
76 | + return errors.INVALID_DATA(**missing) |
77 | + |
78 | + if 'caveat_id' in data: |
79 | + method = auth.refresh_discharge |
80 | + params = (data['caveat_id'], discharge_macaroon_raw) |
81 | + stats.increment('macaroon.refresh', key='caveat_id') |
82 | + elif 'root_macaroon' in data: |
83 | + method = auth.refresh_macaroons |
84 | + params = (data['root_macaroon'], discharge_macaroon_raw) |
85 | + stats.increment('macaroon.refresh', key='macaroon') |
86 | + else: |
87 | + # let's flag the new one only, not the deprecated one |
88 | + missing = {'caveat_id': [FIELD_REQUIRED]} |
89 | return errors.INVALID_DATA(**missing) |
90 | |
91 | try: |
92 | - new_discharge = auth.refresh_macaroons(root_macaroon_raw, |
93 | - discharge_macaroon_raw) |
94 | + new_discharge = method(*params) |
95 | except ValidationError: |
96 | return errors.INVALID_DATA() |
97 | except AccountDeactivated: |
98 | |
99 | === modified file 'src/api/v20/tests/test_handlers.py' |
100 | --- src/api/v20/tests/test_handlers.py 2016-04-18 15:53:18 +0000 |
101 | +++ src/api/v20/tests/test_handlers.py 2016-05-05 12:45:29 +0000 |
102 | @@ -2169,13 +2169,25 @@ |
103 | self.login_failed_calls = [] |
104 | login_failed.connect(self.track_failed_logins, dispatch_uid=self.id()) |
105 | |
106 | - self.root_macaroon, self.macaroon_random_key = self.build_macaroon() |
107 | + self.root_macaroon, self.macaroon_random_key, _ = self.build_macaroon() |
108 | self.data = dict( |
109 | email='foo@bar.com', password='foobar123', |
110 | macaroon=self.root_macaroon.serialize()) |
111 | self.account = self.factory.make_account( |
112 | email=self.data['email'], password=self.data['password']) |
113 | |
114 | + self._stats_increment = self.patch('api.v20.handlers.stats.increment') |
115 | + |
116 | + def check_stats_increment(self, *args, **kwargs): |
117 | + """Check stats increment was properly called.""" |
118 | + calls = self._stats_increment.call_args_list |
119 | + self.assertEqual(len(calls), 1) |
120 | + call_args, call_kwargs = calls[0] |
121 | + self.assertEqual(call_args, args, |
122 | + "Bad args in stats increment call {}".format(calls)) |
123 | + self.assertEqual(call_kwargs, kwargs, |
124 | + "Bad kwargs in stats increment call {}".format(calls)) |
125 | + |
126 | |
127 | class MacaroonDischargeHandlerTestCase(MacaroonHandlerBaseTestCase, |
128 | AuthLogTestCaseMixin): |
129 | @@ -2199,7 +2211,7 @@ |
130 | response) |
131 | return json.loads(response.content) |
132 | |
133 | - def assert_response_correct(self, json_body, account): |
134 | + def assert_response_correct(self, json_body, account, bind=False): |
135 | """Check we received a good discharge macaroon for the root sent. |
136 | |
137 | Proper verification of the received macaroon internals happens in |
138 | @@ -2207,6 +2219,9 @@ |
139 | """ |
140 | discharge_macaroon_raw = json_body['discharge_macaroon'] |
141 | discharge_macaroon = Macaroon.deserialize(discharge_macaroon_raw) |
142 | + if bind: |
143 | + discharge_macaroon = self.root_macaroon.prepare_for_request( |
144 | + discharge_macaroon) |
145 | v = Verifier() |
146 | v.satisfy_general(lambda c: True) |
147 | v.verify( |
148 | @@ -2327,6 +2342,7 @@ |
149 | def test_macaroon_created(self): |
150 | json_body = self.do_post() |
151 | self.assert_response_correct(json_body, self.account) |
152 | + self.check_stats_increment('macaroon.discharge', key='single_macaroon') |
153 | |
154 | def test_root_macaroon_corrupt(self): |
155 | data = dict( |
156 | @@ -2337,23 +2353,23 @@ |
157 | check_login_failed=False) |
158 | |
159 | def test_root_macaroon_not_for_sso(self): |
160 | - macaroon, _ = self.build_macaroon(service_location="other service") |
161 | + macaroon, _, _ = self.build_macaroon(service_location="other service") |
162 | data = dict(email='foo@bar.com', password='foobar123', |
163 | macaroon=macaroon.serialize()) |
164 | self.assert_failed_login('INVALID_CREDENTIALS', data, |
165 | expected_status_code=401, |
166 | check_login_failed=False) |
167 | |
168 | - def test_missing_macaroons(self): |
169 | + def test_missing_macaroon_info(self): |
170 | data = dict(email='foo@bar.com', password='foobar123') |
171 | - extra = {'macaroon or macaroons': [handlers.FIELD_REQUIRED]} |
172 | + extra = {'caveat_id': [handlers.FIELD_REQUIRED]} |
173 | self.assert_failed_login('INVALID_DATA', data, extra=extra, |
174 | expected_status_code=400, |
175 | check_login_failed=False) |
176 | |
177 | def test_multiple_macaroons(self): |
178 | # build *several* macaroons and send them all at once |
179 | - roots, rkeys = zip(*[self.build_macaroon() for _ in range(3)]) |
180 | + roots, rkeys, _ = zip(*[self.build_macaroon() for _ in range(3)]) |
181 | ids = range(3) |
182 | roots = dict(zip(ids, roots)) |
183 | rkeys = dict(zip(ids, rkeys)) |
184 | @@ -2372,8 +2388,11 @@ |
185 | v.satisfy_general(verifying_function) |
186 | v.verify(root_macaroon, key, [discharge_macaroon]) |
187 | |
188 | + self.check_stats_increment('macaroon.discharge', key='multi_macaroons') |
189 | + |
190 | def test_multiple_mixed(self): |
191 | - bad_macaroon, _ = self.build_macaroon(service_location="other service") |
192 | + bad_macaroon, _, _ = self.build_macaroon( |
193 | + service_location="other service") |
194 | data = dict(email='foo@bar.com', password='foobar123', macaroons=[ |
195 | ('good', self.root_macaroon.serialize()), |
196 | ('bad', bad_macaroon.serialize()), |
197 | @@ -2382,6 +2401,24 @@ |
198 | expected_status_code=401, |
199 | check_login_failed=False) |
200 | |
201 | + def test_caveat_id_discharge_created(self): |
202 | + # discharge the test macaroon |
203 | + (caveat,) = [c for c in self.root_macaroon.third_party_caveats() |
204 | + if c.location == settings.MACAROON_SERVICE_LOCATION] |
205 | + data = dict(email='foo@bar.com', password='foobar123', |
206 | + caveat_id=caveat.caveat_id) |
207 | + |
208 | + json_body = self.do_post(data=data) |
209 | + self.assert_response_correct(json_body, self.account, bind=True) |
210 | + self.check_stats_increment('macaroon.discharge', key='caveat_id') |
211 | + |
212 | + def test_caveat_id_corrupt(self): |
213 | + data = dict(email='foo@bar.com', password='foobar123', |
214 | + caveat_id="I'm a seriously corrupted caveat") |
215 | + self.assert_failed_login('INVALID_DATA', data, |
216 | + expected_status_code=400, |
217 | + check_login_failed=False) |
218 | + |
219 | |
220 | class MacaroonHandlerTimelineTestCase(MacaroonHandlerBaseTestCase, |
221 | TimelineActionMixin): |
222 | @@ -2428,12 +2465,16 @@ |
223 | super(MacaroonRefreshHandlerTestCase, self).setUp() |
224 | |
225 | # discharge the test macaroon |
226 | - root_macaroon_raw = self.root_macaroon.serialize() |
227 | - self.discharge_macaroon = build_discharge_macaroon( |
228 | - self.account, root_macaroon_raw) |
229 | - |
230 | - self.data = {'root_macaroon': root_macaroon_raw, |
231 | - 'discharge_macaroon': self.discharge_macaroon.serialize()} |
232 | + (caveat,) = [c for c in self.root_macaroon.third_party_caveats() |
233 | + if c.location == settings.MACAROON_SERVICE_LOCATION] |
234 | + |
235 | + unbound_discharge = build_discharge_macaroon( |
236 | + self.account, caveat.caveat_id) |
237 | + self.discharge_macaroon = self.root_macaroon.prepare_for_request( |
238 | + unbound_discharge) |
239 | + |
240 | + self.data = {'caveat_id': caveat.caveat_id, |
241 | + 'discharge_macaroon': unbound_discharge.serialize()} |
242 | |
243 | def do_post(self, data=None, expected_status_code=200, |
244 | content_type='application/json', **kwargs): |
245 | @@ -2463,13 +2504,23 @@ |
246 | self.assertEqual(json_body['extra'], extra) |
247 | return json_body |
248 | |
249 | - def test_required_parameters(self): |
250 | + def test_required_parameters_discharge(self): |
251 | json_body = self.do_post(expected_status_code=400, data={}) |
252 | |
253 | self.assertEqual(json_body, { |
254 | 'code': 'INVALID_DATA', |
255 | - 'extra': {'root_macaroon': [handlers.FIELD_REQUIRED], |
256 | - 'discharge_macaroon': [handlers.FIELD_REQUIRED]}, |
257 | + 'extra': {'discharge_macaroon': [handlers.FIELD_REQUIRED]}, |
258 | + 'message': 'Invalid request data'}, |
259 | + ) |
260 | + self.assertEqual(self.login_failed_calls, []) |
261 | + |
262 | + def test_required_parameters_caveat_id(self): |
263 | + json_body = self.do_post(expected_status_code=400, |
264 | + data={'discharge_macaroon': 'whatever'}) |
265 | + |
266 | + self.assertEqual(json_body, { |
267 | + 'code': 'INVALID_DATA', |
268 | + 'extra': {'caveat_id': [handlers.FIELD_REQUIRED]}, |
269 | 'message': 'Invalid request data'}, |
270 | ) |
271 | self.assertEqual(self.login_failed_calls, []) |
272 | @@ -2486,7 +2537,7 @@ |
273 | check_login_failed=False) |
274 | |
275 | def test_macaroon_bad_authinfo(self): |
276 | - macaroon, _ = self.build_macaroon(service_location="other service") |
277 | + macaroon, _, _ = self.build_macaroon(service_location="other service") |
278 | data = dict(root_macaroon=macaroon.serialize(), |
279 | discharge_macaroon=self.discharge_macaroon.serialize()) |
280 | self.assert_failed_login('INVALID_CREDENTIALS', data, |
281 | @@ -2494,7 +2545,9 @@ |
282 | check_login_failed=False) |
283 | |
284 | def test_macaroon_refreshed(self): |
285 | - json_body = self.do_post() |
286 | + data = {'root_macaroon': self.root_macaroon.serialize(), |
287 | + 'discharge_macaroon': self.discharge_macaroon.serialize()} |
288 | + json_body = self.do_post(data=data) |
289 | |
290 | # get new discharge macaroon and verify with old root (its internals |
291 | # are verified by the tests of the 'refresh_macaroons' function itself) |
292 | @@ -2504,3 +2557,35 @@ |
293 | v.satisfy_general(lambda c: True) |
294 | v.verify( |
295 | self.root_macaroon, self.macaroon_random_key, [discharge_macaroon]) |
296 | + self.check_stats_increment('macaroon.refresh', key='macaroon') |
297 | + |
298 | + def test_caveat_id_corrupt(self): |
299 | + data = dict(caveat_id="I'm a seriously corrupted caveat", |
300 | + discharge_macaroon="Also broken") |
301 | + self.assert_failed_login('INVALID_DATA', data, |
302 | + expected_status_code=400, |
303 | + check_login_failed=False) |
304 | + |
305 | + def test_caveat_id_bad_authinfo(self): |
306 | + macaroon, _, _ = self.build_macaroon(service_location="other service") |
307 | + (caveat,) = [c for c in macaroon.third_party_caveats() |
308 | + if c.location == "other service"] |
309 | + data = dict(caveat_id=caveat.caveat_id, |
310 | + discharge_macaroon=self.discharge_macaroon.serialize()) |
311 | + self.assert_failed_login('INVALID_CREDENTIALS', data, |
312 | + expected_status_code=401, |
313 | + check_login_failed=False) |
314 | + |
315 | + def test_caveat_id_refreshed(self): |
316 | + json_body = self.do_post() |
317 | + |
318 | + # get new discharge macaroon, apply it and verify with old root (its |
319 | + # internals are verified by the tests of the 'refresh_macaroons' |
320 | + # function itself) |
321 | + unbound_discharge_raw = json_body['discharge_macaroon'] |
322 | + unbound_discharge = Macaroon.deserialize(unbound_discharge_raw) |
323 | + discharge = self.root_macaroon.prepare_for_request(unbound_discharge) |
324 | + v = Verifier() |
325 | + v.satisfy_general(lambda c: True) |
326 | + v.verify(self.root_macaroon, self.macaroon_random_key, [discharge]) |
327 | + self.check_stats_increment('macaroon.refresh', key='caveat_id') |
328 | |
329 | === modified file 'src/identityprovider/auth.py' |
330 | --- src/identityprovider/auth.py 2016-03-23 16:20:24 +0000 |
331 | +++ src/identityprovider/auth.py 2016-05-05 12:45:29 +0000 |
332 | @@ -507,16 +507,21 @@ |
333 | # the macaroon doesn't have a location for this service |
334 | raise AuthenticationError("The received macaroon is not for ours") |
335 | |
336 | - # get the only-for-this-project random key |
337 | + caveat_info = _decrypt_caveat(sso_caveat.caveat_id) |
338 | + return sso_caveat.caveat_id, caveat_info |
339 | + |
340 | + |
341 | +def _decrypt_caveat(raw_caveat_id): |
342 | + """Decrypt and decode the caveat id info.""" |
343 | try: |
344 | caveat_info_raw = settings.CRYPTO_SSO_PRIVKEY.decrypt( |
345 | - base64.b64decode(sso_caveat.caveat_id)) |
346 | + base64.b64decode(raw_caveat_id)) |
347 | caveat_info = json.loads(caveat_info_raw) |
348 | except: |
349 | # not properly encrypted information inside |
350 | - raise AuthenticationError("Bad info in the caveat_id") |
351 | + raise ValidationError("Bad info in the caveat_id") |
352 | |
353 | - return sso_caveat.caveat_id, caveat_info |
354 | + return caveat_info |
355 | |
356 | |
357 | def _build_discharge(macaroon_key, caveat_id, account, |
358 | @@ -556,8 +561,12 @@ |
359 | return d |
360 | |
361 | |
362 | -def build_discharge_macaroon(account, root_macaroon_raw): |
363 | - """Build a discharge macaroon from a root one.""" |
364 | +def build_discharge_macaroon_from_root(account, root_macaroon_raw): |
365 | + """Build a discharge macaroon from a root one. |
366 | + |
367 | + This function is deprecated; will be removed when clients stop hitting |
368 | + the handler passing the root macaroon. |
369 | + """ |
370 | try: |
371 | root_macaroon = Macaroon.deserialize(root_macaroon_raw) |
372 | except: |
373 | @@ -576,18 +585,24 @@ |
374 | return discharge |
375 | |
376 | |
377 | -def refresh_macaroons(root_macaroon_raw, discharge_macaroon_raw): |
378 | - """Refresh a root/discharge pair with a new discharge macaroon.""" |
379 | +def build_discharge_macaroon(account, raw_caveat_id): |
380 | + """Build a discharge macaroon from the caveat id.""" |
381 | + # get the decrypted deserialized info |
382 | + caveat_info = _decrypt_caveat(raw_caveat_id) |
383 | + |
384 | + # create a discharge macaroon with same location, key and |
385 | + # identifier than it's original 3rd-party caveat (so they can |
386 | + # be matched and verified) |
387 | + discharge = _build_discharge( |
388 | + caveat_info['3rdparty'], raw_caveat_id, account) |
389 | + |
390 | + # return the unbound discharge macaroon |
391 | + return discharge |
392 | + |
393 | + |
394 | +def _account_from_macaroon(macaroon, key, discharge=None): |
395 | + """Get the new discharge macaroon.""" |
396 | service_location = settings.MACAROON_SERVICE_LOCATION |
397 | - |
398 | - try: |
399 | - root_macaroon = Macaroon.deserialize(root_macaroon_raw) |
400 | - discharge_macaroon = Macaroon.deserialize(discharge_macaroon_raw) |
401 | - except: |
402 | - raise ValidationError("The received Macaroons are corrupt") |
403 | - |
404 | - # get the raw caveat id and the decrypted deserialized info |
405 | - raw_caveat_id, caveat_info = _get_own_caveat(root_macaroon) |
406 | info_holder = {} |
407 | |
408 | def checker(caveat): |
409 | @@ -606,7 +621,10 @@ |
410 | v = Verifier() |
411 | v.satisfy_general(checker) |
412 | try: |
413 | - v.verify(root_macaroon, caveat_info['roothash'], [discharge_macaroon]) |
414 | + if discharge is None: |
415 | + v.verify(macaroon, key) |
416 | + else: |
417 | + v.verify(macaroon, key, [discharge]) |
418 | except: |
419 | raise AuthenticationError("Not verifying macaroons") |
420 | |
421 | @@ -620,14 +638,59 @@ |
422 | if account.accountpassword.date_changed > last_auth_ts: |
423 | raise AuthenticationError("Password changed") |
424 | |
425 | + return account, info_holder |
426 | + |
427 | + |
428 | +def refresh_macaroons(root_macaroon_raw, discharge_macaroon_raw): |
429 | + """Refresh a root/discharge pair with a new discharge macaroon. |
430 | + |
431 | + This function is deprecated; will be removed when clients stop hitting |
432 | + the handler passing the root macaroon. |
433 | + """ |
434 | + try: |
435 | + root_macaroon = Macaroon.deserialize(root_macaroon_raw) |
436 | + discharge_macaroon = Macaroon.deserialize(discharge_macaroon_raw) |
437 | + except: |
438 | + raise ValidationError("The received Macaroons are corrupt") |
439 | + |
440 | + # get the raw caveat id and the decrypted deserialized info |
441 | + raw_caveat_id, caveat_info = _get_own_caveat(root_macaroon) |
442 | + |
443 | + account, macaroon_info = _account_from_macaroon( |
444 | + root_macaroon, caveat_info['roothash'], discharge_macaroon) |
445 | + |
446 | # create the new discharge macaroon with same location, key and |
447 | # identifier than it's original 3rd-party caveat (so they can |
448 | # be matched and verified), and keeping the last_auth and expires from |
449 | # the original discharge macaroon |
450 | - d = _build_discharge(caveat_info['3rdparty'], raw_caveat_id, account, |
451 | - last_auth=info_holder['last_auth'], |
452 | - expires=info_holder['expires']) |
453 | + d = _build_discharge( |
454 | + caveat_info['3rdparty'], raw_caveat_id, account, |
455 | + last_auth=macaroon_info['last_auth'], expires=macaroon_info['expires']) |
456 | |
457 | # return the properly prepared discharge macaroon |
458 | discharge = root_macaroon.prepare_for_request(d) |
459 | return discharge |
460 | + |
461 | + |
462 | +def refresh_discharge(raw_caveat_id, discharge_macaroon_raw): |
463 | + """Refresh a discharge with a new discharge macaroon.""" |
464 | + try: |
465 | + discharge_macaroon = Macaroon.deserialize(discharge_macaroon_raw) |
466 | + except: |
467 | + raise ValidationError("The received Macaroons are corrupt") |
468 | + |
469 | + # get the decrypted deserialized info |
470 | + caveat_info = _decrypt_caveat(raw_caveat_id) |
471 | + account, macaroon_info = _account_from_macaroon( |
472 | + discharge_macaroon, caveat_info['3rdparty']) |
473 | + |
474 | + # create the new discharge macaroon with same location, key and |
475 | + # identifier than it's original 3rd-party caveat (so they can |
476 | + # be matched and verified), and keeping the last_auth and expires from |
477 | + # the original discharge macaroon |
478 | + discharge = _build_discharge( |
479 | + caveat_info['3rdparty'], raw_caveat_id, account, |
480 | + last_auth=macaroon_info['last_auth'], expires=macaroon_info['expires']) |
481 | + |
482 | + # return the unbound discharge macaroon |
483 | + return discharge |
484 | |
485 | === modified file 'src/identityprovider/tests/test_auth.py' |
486 | --- src/identityprovider/tests/test_auth.py 2016-04-01 19:35:14 +0000 |
487 | +++ src/identityprovider/tests/test_auth.py 2016-05-05 12:45:29 +0000 |
488 | @@ -29,9 +29,11 @@ |
489 | LaunchpadBackend, |
490 | SSOOAuthAuthentication, |
491 | SSORequestValidator, |
492 | - _get_own_caveat, |
493 | + _decrypt_caveat, |
494 | basic_authenticate, |
495 | build_discharge_macaroon, |
496 | + build_discharge_macaroon_from_root, |
497 | + refresh_discharge, |
498 | refresh_macaroons, |
499 | validate_oauth_signature, |
500 | ) |
501 | @@ -958,26 +960,31 @@ |
502 | timer=self.dummy_timer) |
503 | |
504 | |
505 | -class BuildMacaroonDischargeTestCase(SSOBaseTestCase): |
506 | +class BuildMacaroonFromRootDischargeTestCase(SSOBaseTestCase): |
507 | + """Test the deprecated build_discharge_macaroon_from_root. |
508 | + |
509 | + These tests are kept separated as that function won't evolve no more. |
510 | + """ |
511 | |
512 | def setUp(self): |
513 | - super(BuildMacaroonDischargeTestCase, self).setUp() |
514 | - self.root_macaroon, self.macaroon_random_key = self.build_macaroon() |
515 | + super(BuildMacaroonFromRootDischargeTestCase, self).setUp() |
516 | + self.root_macaroon, self.macaroon_random_key, _ = self.build_macaroon() |
517 | |
518 | def test_root_macaroon_corrupt(self): |
519 | - self.assertRaises(ValidationError, build_discharge_macaroon, |
520 | + self.assertRaises(ValidationError, build_discharge_macaroon_from_root, |
521 | "fake account", "I'm a seriously corrupted macaroon") |
522 | |
523 | def test_root_macaroon_not_for_sso(self): |
524 | - macaroon, _ = self.build_macaroon(service_location="other service") |
525 | - self.assertRaises(AuthenticationError, build_discharge_macaroon, |
526 | + macaroon, _, _ = self.build_macaroon(service_location="other service") |
527 | + self.assertRaises(AuthenticationError, |
528 | + build_discharge_macaroon_from_root, |
529 | "fake account", macaroon.serialize()) |
530 | |
531 | def test_proper_discharging(self): |
532 | # build the input and call |
533 | real_account = self.factory.make_account() |
534 | before = now() |
535 | - discharge_macaroon = build_discharge_macaroon( |
536 | + discharge_macaroon = build_discharge_macaroon_from_root( |
537 | real_account, self.root_macaroon.serialize()) |
538 | after = now() |
539 | |
540 | @@ -1029,6 +1036,76 @@ |
541 | [discharge_macaroon]) |
542 | |
543 | |
544 | +class BuildMacaroonDischargeTestCase(SSOBaseTestCase): |
545 | + |
546 | + def test_caveat_id_corrupt(self): |
547 | + self.assertRaises(ValidationError, build_discharge_macaroon, |
548 | + "fake account", "I'm a seriously corrupted caveatid") |
549 | + |
550 | + def test_caveat_id_not_for_sso(self): |
551 | + macaroon, _, _ = self.build_macaroon(service_location="other service") |
552 | + (sso_caveat,) = [c for c in macaroon.third_party_caveats() |
553 | + if c.location == "other service"] |
554 | + |
555 | + self.assertRaises(ValidationError, build_discharge_macaroon, |
556 | + "fake account", sso_caveat) |
557 | + |
558 | + def test_proper_discharging(self): |
559 | + # build the input and call |
560 | + root_macaroon, _, random_key = self.build_macaroon() |
561 | + (sso_caveat,) = [c for c in root_macaroon.third_party_caveats() |
562 | + if c.location == settings.MACAROON_SERVICE_LOCATION] |
563 | + |
564 | + real_account = self.factory.make_account() |
565 | + before = now() |
566 | + discharge_macaroon = build_discharge_macaroon( |
567 | + real_account, sso_caveat.caveat_id) |
568 | + after = now() |
569 | + |
570 | + # test |
571 | + def checker(caveat): |
572 | + """Assure all caveats inside the discharged macaroon are ok.""" |
573 | + source, key, value = caveat.split("|", 2) |
574 | + |
575 | + if key == 'valid_since': |
576 | + valid_since = datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%f') |
577 | + self.assertGreater(valid_since, before) |
578 | + self.assertGreater(after, valid_since) |
579 | + return True |
580 | + |
581 | + if key == 'last_auth': |
582 | + last_auth = datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%f') |
583 | + self.assertGreater(last_auth, before) |
584 | + self.assertGreater(after, last_auth) |
585 | + return True |
586 | + |
587 | + if key == 'account': |
588 | + acc = json.loads(base64.b64decode(value).decode("utf8")) |
589 | + self.assertEqual(acc['openid'], real_account.openid_identifier) |
590 | + self.assertEqual(acc['email'], |
591 | + real_account.preferredemail.email) |
592 | + self.assertEqual(acc['displayname'], real_account.displayname) |
593 | + self.assertEqual(acc['is_verified'], real_account.is_verified) |
594 | + return True |
595 | + |
596 | + if key == 'expires': |
597 | + expires = datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%f') |
598 | + before_plus_ttl = before + timedelta( |
599 | + seconds=settings.MACAROON_TTL) |
600 | + after_plus_ttl = after + timedelta( |
601 | + seconds=settings.MACAROON_TTL) |
602 | + self.assertGreater(expires, before_plus_ttl) |
603 | + self.assertGreater(after_plus_ttl, expires) |
604 | + return True |
605 | + |
606 | + # we're not validating an SSO from the discharged macaroon, fail! |
607 | + return False |
608 | + |
609 | + v = Verifier() |
610 | + v.satisfy_general(checker) |
611 | + v.verify(discharge_macaroon, random_key, []) |
612 | + |
613 | + |
614 | class MacaroonHelpersTestCase(SSOBaseTestCase): |
615 | |
616 | def test_get_caveat_ok(self): |
617 | @@ -1052,42 +1129,29 @@ |
618 | settings.MACAROON_SERVICE_LOCATION, random_key, info_encrypted) |
619 | |
620 | # check |
621 | - raw_caveat_id, caveat_info = _get_own_caveat(root_macaroon) |
622 | - self.assertEqual(raw_caveat_id, info_encrypted) |
623 | + (sso_caveat,) = [c for c in root_macaroon.third_party_caveats() |
624 | + if c.location == settings.MACAROON_SERVICE_LOCATION] |
625 | + caveat_info = _decrypt_caveat(sso_caveat.caveat_id) |
626 | self.assertEqual(caveat_info, info) |
627 | |
628 | - def test_get_caveat_not_for_sso(self): |
629 | - macaroon, _ = self.build_macaroon(service_location="other service") |
630 | - self.assertRaises(AuthenticationError, _get_own_caveat, macaroon) |
631 | - |
632 | def test_get_caveat_badly_encrypted(self): |
633 | - test_rsa_priv_key, test_rsa_pub_key = self.setup_key_pair() |
634 | - |
635 | - # create a Macaron with the proper third party caveat |
636 | - macaroon_random_key = binascii.hexlify(os.urandom(32)) |
637 | - root_macaroon = Macaroon( |
638 | - location='The store ;)', |
639 | - key=macaroon_random_key, |
640 | - identifier='A test macaroon', |
641 | - ) |
642 | - random_key = binascii.hexlify(os.urandom(32)) |
643 | - root_macaroon.add_third_party_caveat( |
644 | - settings.MACAROON_SERVICE_LOCATION, random_key, |
645 | - b"not really well encrypted stuff") |
646 | - |
647 | - # check |
648 | - self.assertRaises(AuthenticationError, _get_own_caveat, root_macaroon) |
649 | - |
650 | - |
651 | -class MacaroonRefreshTestCase(SSOBaseTestCase): |
652 | + self.assertRaises(ValidationError, |
653 | + _decrypt_caveat, b"not really well encrypted stuff") |
654 | + |
655 | + |
656 | +class MacaroonRefreshFromRootTestCase(SSOBaseTestCase): |
657 | + """Test the deprecated refresh_macaroons. |
658 | + |
659 | + These tests are kept separated as that function won't evolve no more. |
660 | + """ |
661 | |
662 | def setUp(self): |
663 | - super(MacaroonRefreshTestCase, self).setUp() |
664 | - self.root_macaroon, self.macaroon_random_key = self.build_macaroon() |
665 | + super(MacaroonRefreshFromRootTestCase, self).setUp() |
666 | + self.root_macaroon, self.macaroon_random_key, _ = self.build_macaroon() |
667 | |
668 | # discharge the test macaroon |
669 | self.account = self.factory.make_account() |
670 | - self.discharge_macaroon = build_discharge_macaroon( |
671 | + self.discharge_macaroon = build_discharge_macaroon_from_root( |
672 | self.account, self.root_macaroon.serialize()) |
673 | |
674 | def test_root_macaroon_corrupt(self): |
675 | @@ -1102,8 +1166,8 @@ |
676 | |
677 | def test_macaroons_dont_verify_ok(self): |
678 | # just get *another* discharge so it's not for the same root macaroon |
679 | - other_root, _ = self.build_macaroon() |
680 | - other_discharge = build_discharge_macaroon( |
681 | + other_root, _, _ = self.build_macaroon() |
682 | + other_discharge = build_discharge_macaroon_from_root( |
683 | self.account, other_root.serialize()) |
684 | self.assertRaises(AuthenticationError, refresh_macaroons, |
685 | self.root_macaroon.serialize(), |
686 | @@ -1197,3 +1261,120 @@ |
687 | v.satisfy_general(checker) |
688 | v.verify(self.root_macaroon, self.macaroon_random_key, |
689 | [new_discharge]) |
690 | + |
691 | + |
692 | +class MacaroonRefreshTestCase(SSOBaseTestCase): |
693 | + |
694 | + def setUp(self): |
695 | + super(MacaroonRefreshTestCase, self).setUp() |
696 | + root_macaroon, _, self.random_key = self.build_macaroon() |
697 | + (caveat,) = [c for c in root_macaroon.third_party_caveats() |
698 | + if c.location == settings.MACAROON_SERVICE_LOCATION] |
699 | + self.caveat_id = caveat.caveat_id |
700 | + |
701 | + # get a discharge for the test macaroon |
702 | + self.account = self.factory.make_account() |
703 | + self.discharge_macaroon = build_discharge_macaroon( |
704 | + self.account, self.caveat_id) |
705 | + |
706 | + def test_caveat_id_corrupt(self): |
707 | + self.assertRaises( |
708 | + ValidationError, refresh_discharge, |
709 | + "Corrupted caveat id", self.discharge_macaroon.serialize()) |
710 | + |
711 | + def test_discharge_macaroon_corrupt(self): |
712 | + self.assertRaises( |
713 | + ValidationError, refresh_discharge, |
714 | + self.caveat_id, "Seriously corrupted macaroon") |
715 | + |
716 | + def test_macaroons_dont_verify_ok(self): |
717 | + # just get *another* discharge so it's not for the same root macaroon |
718 | + other_root, _, _ = self.build_macaroon() |
719 | + (other_caveat,) = [c for c in other_root.third_party_caveats() |
720 | + if c.location == settings.MACAROON_SERVICE_LOCATION] |
721 | + other_discharge = build_discharge_macaroon( |
722 | + self.account, other_caveat.caveat_id) |
723 | + self.assertRaises(AuthenticationError, refresh_discharge, |
724 | + self.caveat_id, other_discharge.serialize()) |
725 | + |
726 | + def test_deactivated_account(self): |
727 | + self.account.deactivate() |
728 | + self.assertRaises(AccountDeactivated, refresh_discharge, |
729 | + self.caveat_id, self.discharge_macaroon.serialize()) |
730 | + |
731 | + def test_password_changed(self): |
732 | + self.account.set_password("a new password") |
733 | + self.assertRaises(AuthenticationError, refresh_discharge, |
734 | + self.caveat_id, self.discharge_macaroon.serialize()) |
735 | + |
736 | + def test_password_with_no_datetime(self): |
737 | + # simulate an "old" account password (before we started to keep the |
738 | + # changed date); note that I'm bypassing the AccountPassword save(), |
739 | + # which will update the attribute that I want in Null! (and we confirm |
740 | + # that in the assert) |
741 | + self.account.accountpassword.date_changed = None |
742 | + super(AccountPassword, self.account.accountpassword).save() |
743 | + assert self.account.accountpassword.date_changed is None |
744 | + |
745 | + # check that auths ok |
746 | + refresh_discharge(self.caveat_id, self.discharge_macaroon.serialize()) |
747 | + |
748 | + def test_proper_refreshing(self): |
749 | + old_discharge = self.discharge_macaroon # just rename for readability |
750 | + service_location = settings.MACAROON_SERVICE_LOCATION |
751 | + |
752 | + def get_value(search_key): |
753 | + for caveat in old_discharge.first_party_caveats(): |
754 | + source, key, value = caveat.caveat_id.split("|", 2) |
755 | + if source == service_location and key == search_key: |
756 | + return value |
757 | + |
758 | + # get old values from the macaroon and also change the account to see |
759 | + # that reflected |
760 | + old_last_auth = get_value('last_auth') |
761 | + old_expires = get_value('expires') |
762 | + new_mail = self.factory.make_email_for_account( |
763 | + self.account, status=EmailStatus.PREFERRED) |
764 | + self.account.displayname = "New test display name" |
765 | + self.account.save() |
766 | + |
767 | + # call! |
768 | + before = now() |
769 | + new_discharge = refresh_discharge(self.caveat_id, |
770 | + old_discharge.serialize()) |
771 | + after = now() |
772 | + |
773 | + # test |
774 | + def checker(caveat): |
775 | + """Assure all caveats inside the discharged macaroon are ok.""" |
776 | + source, key, value = caveat.split("|", 2) |
777 | + |
778 | + if key == 'valid_since': |
779 | + valid_since = datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%f') |
780 | + self.assertGreater(valid_since, before) |
781 | + self.assertGreater(after, valid_since) |
782 | + return True |
783 | + |
784 | + if key == 'last_auth': |
785 | + self.assertEqual(value, old_last_auth) |
786 | + return True |
787 | + |
788 | + if key == 'account': |
789 | + acc = json.loads(base64.b64decode(value).decode("utf8")) |
790 | + self.assertEqual(acc['openid'], self.account.openid_identifier) |
791 | + self.assertEqual(acc['email'], new_mail.email) |
792 | + self.assertEqual(acc['displayname'], "New test display name") |
793 | + self.assertEqual(acc['is_verified'], self.account.is_verified) |
794 | + return True |
795 | + |
796 | + if key == 'expires': |
797 | + self.assertEqual(value, old_expires) |
798 | + return True |
799 | + |
800 | + # we're not validating an SSO from the discharged macaroon, fail! |
801 | + return False |
802 | + |
803 | + # verify using the NEW discharge macaroon |
804 | + v = Verifier() |
805 | + v.satisfy_general(checker) |
806 | + v.verify(new_discharge, self.random_key, []) |
807 | |
808 | === modified file 'src/identityprovider/tests/test_forms.py' |
809 | --- src/identityprovider/tests/test_forms.py 2016-04-11 11:57:38 +0000 |
810 | +++ src/identityprovider/tests/test_forms.py 2016-05-05 12:45:29 +0000 |
811 | @@ -1138,7 +1138,7 @@ |
812 | """The server always returns discharge macaroons to trusted sites, |
813 | regardless of the state of the checkbox in the UI. |
814 | """ |
815 | - root_macaroon, _ = self.build_macaroon() |
816 | + root_macaroon, _, _ = self.build_macaroon() |
817 | macaroon_request = MacaroonRequest(root_macaroon.serialize()) |
818 | form = MacaroonRequestForm( |
819 | request=self._get_request_with_post_args(), |
820 | @@ -1149,7 +1149,7 @@ |
821 | """The server returns discharge macaroons to untrusted sites when |
822 | the user checks the checkbox in the UI. |
823 | """ |
824 | - root_macaroon, _ = self.build_macaroon() |
825 | + root_macaroon, _, _ = self.build_macaroon() |
826 | macaroon_request = MacaroonRequest(root_macaroon.serialize()) |
827 | form = MacaroonRequestForm( |
828 | request=self._get_request_with_post_args(macaroon='macaroon'), |
829 | @@ -1160,7 +1160,7 @@ |
830 | """The server does not return discharge macaroons to untrusted sites |
831 | when the user does not check the checkbox in the UI. |
832 | """ |
833 | - root_macaroon, _ = self.build_macaroon() |
834 | + root_macaroon, _, _ = self.build_macaroon() |
835 | macaroon_request = MacaroonRequest(root_macaroon.serialize()) |
836 | form = MacaroonRequestForm( |
837 | request=self._get_request_with_post_args(), |
838 | @@ -1169,7 +1169,7 @@ |
839 | |
840 | def test_checkbox_status_for_trusted_site(self): |
841 | """Checkboxes are always checked if the site is trusted.""" |
842 | - root_macaroon, _ = self.build_macaroon() |
843 | + root_macaroon, _, _ = self.build_macaroon() |
844 | macaroon_request = MacaroonRequest(root_macaroon.serialize()) |
845 | form = MacaroonRequestForm( |
846 | request=self._get_request_with_post_args(), |
847 | @@ -1178,7 +1178,7 @@ |
848 | |
849 | def test_checkbox_status_for_untrusted_site(self): |
850 | """Checkboxes are checked by default if the site is untrusted.""" |
851 | - root_macaroon, _ = self.build_macaroon() |
852 | + root_macaroon, _, _ = self.build_macaroon() |
853 | macaroon_request = MacaroonRequest(root_macaroon.serialize()) |
854 | form = MacaroonRequestForm( |
855 | request=self._get_request_with_post_args(), |
856 | @@ -1189,7 +1189,7 @@ |
857 | """Checkboxes respect user preferences on untrusted sites where |
858 | available. |
859 | """ |
860 | - root_macaroon, _ = self.build_macaroon() |
861 | + root_macaroon, _, _ = self.build_macaroon() |
862 | macaroon_request = MacaroonRequest(root_macaroon.serialize()) |
863 | approved_data = { |
864 | 'requested': ['macaroon'], |
865 | |
866 | === modified file 'src/identityprovider/tests/test_macaroon.py' |
867 | --- src/identityprovider/tests/test_macaroon.py 2016-04-05 22:12:47 +0000 |
868 | +++ src/identityprovider/tests/test_macaroon.py 2016-05-05 12:45:29 +0000 |
869 | @@ -45,7 +45,7 @@ |
870 | def setUp(self): |
871 | super(MacaroonRequestTestCase, self).setUp() |
872 | |
873 | - self.root_macaroon, self.macaroon_random_key = self.build_macaroon() |
874 | + self.root_macaroon, self.macaroon_random_key, _ = self.build_macaroon() |
875 | self.req = MacaroonRequest(self.root_macaroon.serialize()) |
876 | |
877 | def assertMacaroonsEqual(self, expected, observed): |
878 | |
879 | === modified file 'src/identityprovider/tests/test_views_server.py' |
880 | --- src/identityprovider/tests/test_views_server.py 2016-04-04 15:41:06 +0000 |
881 | +++ src/identityprovider/tests/test_views_server.py 2016-05-05 12:45:29 +0000 |
882 | @@ -227,7 +227,7 @@ |
883 | self._test_auto_auth(sreg=['fullname']) |
884 | |
885 | def test_handle_user_response_auto_auth_discharge_macaroon(self): |
886 | - root_macaroon, macaroon_random_key = self.build_macaroon() |
887 | + root_macaroon, macaroon_random_key, _ = self.build_macaroon() |
888 | # Add padding to force a POST after signing. We don't know exactly |
889 | # how long the serialized discharge macaroon will be yet, but it |
890 | # will probably be at least 1024 bytes. |
891 | @@ -1065,7 +1065,7 @@ |
892 | # make sure rpconfig is set to auto authorize |
893 | OpenIDRPConfig.objects.create( |
894 | trust_root='http://localhost/', auto_authorize=True) |
895 | - root_macaroon, macaroon_random_key = self.build_macaroon() |
896 | + root_macaroon, macaroon_random_key, _ = self.build_macaroon() |
897 | param_overrides = { |
898 | 'openid.ns.macaroon': MACAROON_NS, |
899 | 'openid.macaroon.root': root_macaroon.serialize(), |
900 | @@ -1089,7 +1089,7 @@ |
901 | root_macaroon, macaroon_random_key, [discharge_macaroon])) |
902 | |
903 | def test_state_of_checkboxes_and_data_formats_macaroon(self): |
904 | - root_macaroon, _ = self.build_macaroon() |
905 | + root_macaroon, _, _ = self.build_macaroon() |
906 | param_overrides = { |
907 | 'openid.ns.macaroon': MACAROON_NS, |
908 | 'openid.macaroon.root': root_macaroon.serialize(), |
909 | @@ -1864,7 +1864,7 @@ |
910 | if with_teams: |
911 | params['openid.lp.query_membership'] = 'ubuntu-team' |
912 | if with_macaroon: |
913 | - root_macaroon, _ = self.build_macaroon() |
914 | + root_macaroon, _, _ = self.build_macaroon() |
915 | params['openid.ns.macaroon'] = MACAROON_NS |
916 | params['openid.macaroon.root'] = root_macaroon.serialize() |
917 | provider_url = get_provider_url(request) |
918 | |
919 | === modified file 'src/identityprovider/tests/utils.py' |
920 | --- src/identityprovider/tests/utils.py 2016-04-28 13:01:53 +0000 |
921 | +++ src/identityprovider/tests/utils.py 2016-05-05 12:45:29 +0000 |
922 | @@ -202,7 +202,7 @@ |
923 | test_rsa_pub_key.encrypt(json.dumps(info), 32)[0]) |
924 | root_macaroon.add_third_party_caveat( |
925 | service_location, random_key, info_encrypted) |
926 | - return root_macaroon, macaroon_random_key |
927 | + return root_macaroon, macaroon_random_key, random_key |
928 | |
929 | |
930 | class SSOBaseTestCase(SSOBaseTestCaseMixin, TestCase): |
931 | |
932 | === modified file 'src/identityprovider/views/server.py' |
933 | --- src/identityprovider/views/server.py 2016-04-29 14:17:15 +0000 |
934 | +++ src/identityprovider/views/server.py 2016-05-05 12:45:29 +0000 |
935 | @@ -42,7 +42,7 @@ |
936 | from openid.yadis.constants import YADIS_HEADER_NAME |
937 | |
938 | from identityprovider import signed |
939 | -from identityprovider.auth import build_discharge_macaroon |
940 | +from identityprovider.auth import build_discharge_macaroon_from_root |
941 | from identityprovider.const import ( |
942 | AX_DATA_FIELDS, |
943 | MACAROON_NS, |
944 | @@ -769,7 +769,7 @@ |
945 | rpconfig = utils.get_rpconfig(openid_request.trust_root) |
946 | form = MacaroonRequestForm(request, macaroon_request, rpconfig) |
947 | if form.data_approved_for_request: |
948 | - discharge_macaroon = build_discharge_macaroon( |
949 | + discharge_macaroon = build_discharge_macaroon_from_root( |
950 | request.user, macaroon_request.root_macaroon_raw) |
951 | macaroon_response = MacaroonResponse.extractResponse( |
952 | macaroon_request, discharge_macaroon.serialize()) |
LGTM