Merge ~cjwatson/launchpad:snap-validate-macaroons-harder into launchpad:master
- Git
- lp:~cjwatson/launchpad
- snap-validate-macaroons-harder
- Merge into master
Proposed by
Colin Watson
Status: | Merged |
---|---|
Approved by: | Colin Watson |
Approved revision: | da8d0afc19d32d310e83bdd94c94602febc8ee45 |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~cjwatson/launchpad:snap-validate-macaroons-harder |
Merge into: | launchpad:master |
Diff against target: |
331 lines (+96/-31) 4 files modified
lib/lp/snappy/browser/tests/test_snap.py (+8/-5) lib/lp/snappy/interfaces/snap.py (+11/-5) lib/lp/snappy/model/snap.py (+13/-3) lib/lp/snappy/tests/test_snap.py (+64/-18) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Thiago F. Pappacena (community) | Approve | ||
Review via email: mp+389774@code.launchpad.net |
Commit message
Validate macaroons in Snap.completeAu
Description of the change
This isn't a full verification (which Launchpad can't do anyway), just a check that the macaroons are well-formed.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/snappy/browser/tests/test_snap.py b/lib/lp/snappy/browser/tests/test_snap.py | |||
2 | index 0a481dc..37b3cda 100644 | |||
3 | --- a/lib/lp/snappy/browser/tests/test_snap.py | |||
4 | +++ b/lib/lp/snappy/browser/tests/test_snap.py | |||
5 | @@ -1,4 +1,4 @@ | |||
7 | 1 | # Copyright 2015-2019 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2015-2020 Canonical Ltd. This software is licensed under the |
8 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
9 | 3 | 3 | ||
10 | 4 | """Test snap package views.""" | 4 | """Test snap package views.""" |
11 | @@ -1187,7 +1187,7 @@ class TestSnapAuthorizeView(BaseTestSnapView): | |||
12 | 1187 | # If the form does not include a discharge macaroon, the "complete" | 1187 | # If the form does not include a discharge macaroon, the "complete" |
13 | 1188 | # action fails. | 1188 | # action fails. |
14 | 1189 | with person_logged_in(self.snap.owner): | 1189 | with person_logged_in(self.snap.owner): |
16 | 1190 | self.snap.store_secrets = {"root": "root"} | 1190 | self.snap.store_secrets = {"root": Macaroon().serialize()} |
17 | 1191 | transaction.commit() | 1191 | transaction.commit() |
18 | 1192 | form = {"field.actions.complete": "1"} | 1192 | form = {"field.actions.complete": "1"} |
19 | 1193 | view = create_initialized_view( | 1193 | view = create_initialized_view( |
20 | @@ -1203,12 +1203,14 @@ class TestSnapAuthorizeView(BaseTestSnapView): | |||
21 | 1203 | def test_complete_authorization(self): | 1203 | def test_complete_authorization(self): |
22 | 1204 | # If the form includes a discharge macaroon, the "complete" action | 1204 | # If the form includes a discharge macaroon, the "complete" action |
23 | 1205 | # succeeds and records the new secrets. | 1205 | # succeeds and records the new secrets. |
24 | 1206 | root_macaroon = Macaroon() | ||
25 | 1207 | discharge_macaroon = Macaroon() | ||
26 | 1206 | with person_logged_in(self.snap.owner): | 1208 | with person_logged_in(self.snap.owner): |
28 | 1207 | self.snap.store_secrets = {"root": "root"} | 1209 | self.snap.store_secrets = {"root": root_macaroon.serialize()} |
29 | 1208 | transaction.commit() | 1210 | transaction.commit() |
30 | 1209 | form = { | 1211 | form = { |
31 | 1210 | "field.actions.complete": "1", | 1212 | "field.actions.complete": "1", |
33 | 1211 | "field.discharge_macaroon": "discharge", | 1213 | "field.discharge_macaroon": discharge_macaroon.serialize(), |
34 | 1212 | } | 1214 | } |
35 | 1213 | view = create_initialized_view( | 1215 | view = create_initialized_view( |
36 | 1214 | self.snap, "+authorize", form=form, method="POST", | 1216 | self.snap, "+authorize", form=form, method="POST", |
37 | @@ -1223,7 +1225,8 @@ class TestSnapAuthorizeView(BaseTestSnapView): | |||
38 | 1223 | self.snap.name, | 1225 | self.snap.name, |
39 | 1224 | view.request.response.notifications[0].message) | 1226 | view.request.response.notifications[0].message) |
40 | 1225 | self.assertEqual( | 1227 | self.assertEqual( |
42 | 1226 | {"root": "root", "discharge": "discharge"}, | 1228 | {"root": root_macaroon.serialize(), |
43 | 1229 | "discharge": discharge_macaroon.serialize()}, | ||
44 | 1227 | self.snap.store_secrets) | 1230 | self.snap.store_secrets) |
45 | 1228 | 1231 | ||
46 | 1229 | 1232 | ||
47 | diff --git a/lib/lp/snappy/interfaces/snap.py b/lib/lp/snappy/interfaces/snap.py | |||
48 | index a6460b7..eca689b 100644 | |||
49 | --- a/lib/lp/snappy/interfaces/snap.py | |||
50 | +++ b/lib/lp/snappy/interfaces/snap.py | |||
51 | @@ -1,4 +1,4 @@ | |||
53 | 1 | # Copyright 2015-2019 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2015-2020 Canonical Ltd. This software is licensed under the |
54 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
55 | 3 | 3 | ||
56 | 4 | """Snap package interfaces.""" | 4 | """Snap package interfaces.""" |
57 | @@ -8,6 +8,7 @@ from __future__ import absolute_import, print_function, unicode_literals | |||
58 | 8 | __metaclass__ = type | 8 | __metaclass__ = type |
59 | 9 | 9 | ||
60 | 10 | __all__ = [ | 10 | __all__ = [ |
61 | 11 | 'BadMacaroon', | ||
62 | 11 | 'BadSnapSearchContext', | 12 | 'BadSnapSearchContext', |
63 | 12 | 'BadSnapSource', | 13 | 'BadSnapSource', |
64 | 13 | 'CannotAuthorizeStoreUploads', | 14 | 'CannotAuthorizeStoreUploads', |
65 | @@ -28,7 +29,7 @@ __all__ = [ | |||
66 | 28 | 'SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG', | 29 | 'SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG', |
67 | 29 | 'SNAP_TESTING_FLAGS', | 30 | 'SNAP_TESTING_FLAGS', |
68 | 30 | 'SNAP_WEBHOOKS_FEATURE_FLAG', | 31 | 'SNAP_WEBHOOKS_FEATURE_FLAG', |
70 | 31 | 'SnapAuthorizationBadMacaroon', | 32 | 'SnapAuthorizationBadGeneratedMacaroon', |
71 | 32 | 'SnapBuildAlreadyPending', | 33 | 'SnapBuildAlreadyPending', |
72 | 33 | 'SnapBuildArchiveOwnerMismatch', | 34 | 'SnapBuildArchiveOwnerMismatch', |
73 | 34 | 'SnapBuildDisallowedArchitecture', | 35 | 'SnapBuildDisallowedArchitecture', |
74 | @@ -237,11 +238,16 @@ class CannotAuthorizeStoreUploads(Exception): | |||
75 | 237 | 238 | ||
76 | 238 | 239 | ||
77 | 239 | @error_status(http_client.INTERNAL_SERVER_ERROR) | 240 | @error_status(http_client.INTERNAL_SERVER_ERROR) |
79 | 240 | class SnapAuthorizationBadMacaroon(Exception): | 241 | class SnapAuthorizationBadGeneratedMacaroon(Exception): |
80 | 241 | """The macaroon generated to authorize store uploads is unusable.""" | 242 | """The macaroon generated to authorize store uploads is unusable.""" |
81 | 242 | 243 | ||
82 | 243 | 244 | ||
83 | 244 | @error_status(http_client.BAD_REQUEST) | 245 | @error_status(http_client.BAD_REQUEST) |
84 | 246 | class BadMacaroon(Exception): | ||
85 | 247 | """A macaroon supplied by the user is invalid.""" | ||
86 | 248 | |||
87 | 249 | |||
88 | 250 | @error_status(http_client.BAD_REQUEST) | ||
89 | 245 | class CannotRequestAutoBuilds(Exception): | 251 | class CannotRequestAutoBuilds(Exception): |
90 | 246 | """Snap package is not configured for automatic builds.""" | 252 | """Snap package is not configured for automatic builds.""" |
91 | 247 | 253 | ||
92 | @@ -597,8 +603,8 @@ class ISnapEdit(IWebhookTarget): | |||
93 | 597 | :raises BadRequestPackageUploadResponse: if the store returns an | 603 | :raises BadRequestPackageUploadResponse: if the store returns an |
94 | 598 | error or a response without a macaroon when asked to issue a | 604 | error or a response without a macaroon when asked to issue a |
95 | 599 | package_upload macaroon. | 605 | package_upload macaroon. |
98 | 600 | :raises SnapAuthorizationBadMacaroon: if the package_upload macaroon | 606 | :raises SnapAuthorizationBadGeneratedMacaroon: if the package_upload |
99 | 601 | returned by the store has unsuitable SSO caveats. | 607 | macaroon returned by the store has unsuitable SSO caveats. |
100 | 602 | :return: The SSO caveat ID from the package_upload macaroon returned | 608 | :return: The SSO caveat ID from the package_upload macaroon returned |
101 | 603 | by the store. The third-party site should acquire a discharge | 609 | by the store. The third-party site should acquire a discharge |
102 | 604 | macaroon for this caveat using OpenID and then call | 610 | macaroon for this caveat using OpenID and then call |
103 | diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py | |||
104 | index 4860fad..aa147ef 100644 | |||
105 | --- a/lib/lp/snappy/model/snap.py | |||
106 | +++ b/lib/lp/snappy/model/snap.py | |||
107 | @@ -139,6 +139,7 @@ from lp.services.webhooks.interfaces import IWebhookSet | |||
108 | 139 | from lp.services.webhooks.model import WebhookTargetMixin | 139 | from lp.services.webhooks.model import WebhookTargetMixin |
109 | 140 | from lp.snappy.adapters.buildarch import determine_architectures_to_build | 140 | from lp.snappy.adapters.buildarch import determine_architectures_to_build |
110 | 141 | from lp.snappy.interfaces.snap import ( | 141 | from lp.snappy.interfaces.snap import ( |
111 | 142 | BadMacaroon, | ||
112 | 142 | BadSnapSearchContext, | 143 | BadSnapSearchContext, |
113 | 143 | BadSnapSource, | 144 | BadSnapSource, |
114 | 144 | CannotAuthorizeStoreUploads, | 145 | CannotAuthorizeStoreUploads, |
115 | @@ -154,7 +155,7 @@ from lp.snappy.interfaces.snap import ( | |||
116 | 154 | NoSourceForSnap, | 155 | NoSourceForSnap, |
117 | 155 | NoSuchSnap, | 156 | NoSuchSnap, |
118 | 156 | SNAP_PRIVATE_FEATURE_FLAG, | 157 | SNAP_PRIVATE_FEATURE_FLAG, |
120 | 157 | SnapAuthorizationBadMacaroon, | 158 | SnapAuthorizationBadGeneratedMacaroon, |
121 | 158 | SnapBuildAlreadyPending, | 159 | SnapBuildAlreadyPending, |
122 | 159 | SnapBuildArchiveOwnerMismatch, | 160 | SnapBuildArchiveOwnerMismatch, |
123 | 160 | SnapBuildDisallowedArchitecture, | 161 | SnapBuildDisallowedArchitecture, |
124 | @@ -588,9 +589,10 @@ class Snap(Storm, WebhookTargetMixin): | |||
125 | 588 | # in some other service, since the user can't do anything about it | 589 | # in some other service, since the user can't do anything about it |
126 | 589 | # and it should show up in our OOPS reports. | 590 | # and it should show up in our OOPS reports. |
127 | 590 | if not sso_caveats: | 591 | if not sso_caveats: |
129 | 591 | raise SnapAuthorizationBadMacaroon("Macaroon has no SSO caveats") | 592 | raise SnapAuthorizationBadGeneratedMacaroon( |
130 | 593 | "Macaroon has no SSO caveats") | ||
131 | 592 | elif len(sso_caveats) > 1: | 594 | elif len(sso_caveats) > 1: |
133 | 593 | raise SnapAuthorizationBadMacaroon( | 595 | raise SnapAuthorizationBadGeneratedMacaroon( |
134 | 594 | "Macaroon has multiple SSO caveats") | 596 | "Macaroon has multiple SSO caveats") |
135 | 595 | self.store_secrets = {'root': root_macaroon_raw} | 597 | self.store_secrets = {'root': root_macaroon_raw} |
136 | 596 | return sso_caveats[0].caveat_id | 598 | return sso_caveats[0].caveat_id |
137 | @@ -599,6 +601,10 @@ class Snap(Storm, WebhookTargetMixin): | |||
138 | 599 | discharge_macaroon=None): | 601 | discharge_macaroon=None): |
139 | 600 | """See `ISnap`.""" | 602 | """See `ISnap`.""" |
140 | 601 | if root_macaroon is not None: | 603 | if root_macaroon is not None: |
141 | 604 | try: | ||
142 | 605 | Macaroon.deserialize(root_macaroon) | ||
143 | 606 | except Exception: | ||
144 | 607 | raise BadMacaroon("root_macaroon is invalid.") | ||
145 | 602 | self.store_secrets = {"root": root_macaroon} | 608 | self.store_secrets = {"root": root_macaroon} |
146 | 603 | else: | 609 | else: |
147 | 604 | if self.store_secrets is None or "root" not in self.store_secrets: | 610 | if self.store_secrets is None or "root" not in self.store_secrets: |
148 | @@ -606,6 +612,10 @@ class Snap(Storm, WebhookTargetMixin): | |||
149 | 606 | "beginAuthorization must be called before " | 612 | "beginAuthorization must be called before " |
150 | 607 | "completeAuthorization.") | 613 | "completeAuthorization.") |
151 | 608 | if discharge_macaroon is not None: | 614 | if discharge_macaroon is not None: |
152 | 615 | try: | ||
153 | 616 | Macaroon.deserialize(discharge_macaroon) | ||
154 | 617 | except Exception: | ||
155 | 618 | raise BadMacaroon("discharge_macaroon is invalid.") | ||
156 | 609 | container = getUtility(IEncryptedContainer, "snap-store-secrets") | 619 | container = getUtility(IEncryptedContainer, "snap-store-secrets") |
157 | 610 | if container.can_encrypt: | 620 | if container.can_encrypt: |
158 | 611 | self.store_secrets["discharge_encrypted"] = ( | 621 | self.store_secrets["discharge_encrypted"] = ( |
159 | diff --git a/lib/lp/snappy/tests/test_snap.py b/lib/lp/snappy/tests/test_snap.py | |||
160 | index 0b712fe..8c87c8a 100644 | |||
161 | --- a/lib/lp/snappy/tests/test_snap.py | |||
162 | +++ b/lib/lp/snappy/tests/test_snap.py | |||
163 | @@ -3287,20 +3287,23 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
164 | 3287 | def test_completeAuthorization(self): | 3287 | def test_completeAuthorization(self): |
165 | 3288 | with admin_logged_in(): | 3288 | with admin_logged_in(): |
166 | 3289 | snappy_series = self.factory.makeSnappySeries() | 3289 | snappy_series = self.factory.makeSnappySeries() |
167 | 3290 | root_macaroon = Macaroon() | ||
168 | 3291 | discharge_macaroon = Macaroon() | ||
169 | 3290 | snap = self.factory.makeSnap( | 3292 | snap = self.factory.makeSnap( |
170 | 3291 | registrant=self.person, store_upload=True, | 3293 | registrant=self.person, store_upload=True, |
171 | 3292 | store_series=snappy_series, | 3294 | store_series=snappy_series, |
172 | 3293 | store_name=self.factory.getUniqueUnicode(), | 3295 | store_name=self.factory.getUniqueUnicode(), |
174 | 3294 | store_secrets={"root": "dummy-root"}) | 3296 | store_secrets={"root": root_macaroon.serialize()}) |
175 | 3295 | snap_url = api_url(snap) | 3297 | snap_url = api_url(snap) |
176 | 3296 | logout() | 3298 | logout() |
177 | 3297 | response = self.webservice.named_post( | 3299 | response = self.webservice.named_post( |
178 | 3298 | snap_url, "completeAuthorization", | 3300 | snap_url, "completeAuthorization", |
180 | 3299 | discharge_macaroon="dummy-discharge") | 3301 | discharge_macaroon=discharge_macaroon.serialize()) |
181 | 3300 | self.assertEqual(200, response.status) | 3302 | self.assertEqual(200, response.status) |
182 | 3301 | with person_logged_in(self.person): | 3303 | with person_logged_in(self.person): |
183 | 3302 | self.assertEqual( | 3304 | self.assertEqual( |
185 | 3303 | {"root": "dummy-root", "discharge": "dummy-discharge"}, | 3305 | {"root": root_macaroon.serialize(), |
186 | 3306 | "discharge": discharge_macaroon.serialize()}, | ||
187 | 3304 | snap.store_secrets) | 3307 | snap.store_secrets) |
188 | 3305 | 3308 | ||
189 | 3306 | def test_completeAuthorization_without_beginAuthorization(self): | 3309 | def test_completeAuthorization_without_beginAuthorization(self): |
190 | @@ -3312,22 +3315,26 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
191 | 3312 | store_name=self.factory.getUniqueUnicode()) | 3315 | store_name=self.factory.getUniqueUnicode()) |
192 | 3313 | snap_url = api_url(snap) | 3316 | snap_url = api_url(snap) |
193 | 3314 | logout() | 3317 | logout() |
194 | 3318 | discharge_macaroon = Macaroon() | ||
195 | 3315 | response = self.webservice.named_post( | 3319 | response = self.webservice.named_post( |
196 | 3316 | snap_url, "completeAuthorization", | 3320 | snap_url, "completeAuthorization", |
202 | 3317 | discharge_macaroon="dummy-discharge") | 3321 | discharge_macaroon=discharge_macaroon.serialize()) |
203 | 3318 | self.assertEqual(400, response.status) | 3322 | self.assertThat(response, MatchesStructure.byEquality( |
204 | 3319 | self.assertEqual( | 3323 | status=400, |
205 | 3320 | "beginAuthorization must be called before completeAuthorization.", | 3324 | body=( |
206 | 3321 | response.body) | 3325 | b"beginAuthorization must be called before " |
207 | 3326 | b"completeAuthorization."))) | ||
208 | 3322 | 3327 | ||
209 | 3323 | def test_completeAuthorization_unauthorized(self): | 3328 | def test_completeAuthorization_unauthorized(self): |
210 | 3324 | with admin_logged_in(): | 3329 | with admin_logged_in(): |
211 | 3325 | snappy_series = self.factory.makeSnappySeries() | 3330 | snappy_series = self.factory.makeSnappySeries() |
212 | 3331 | root_macaroon = Macaroon() | ||
213 | 3332 | discharge_macaroon = Macaroon() | ||
214 | 3326 | snap = self.factory.makeSnap( | 3333 | snap = self.factory.makeSnap( |
215 | 3327 | registrant=self.person, store_upload=True, | 3334 | registrant=self.person, store_upload=True, |
216 | 3328 | store_series=snappy_series, | 3335 | store_series=snappy_series, |
217 | 3329 | store_name=self.factory.getUniqueUnicode(), | 3336 | store_name=self.factory.getUniqueUnicode(), |
219 | 3330 | store_secrets={"root": "dummy-root"}) | 3337 | store_secrets={"root": root_macaroon.serialize()}) |
220 | 3331 | snap_url = api_url(snap) | 3338 | snap_url = api_url(snap) |
221 | 3332 | other_person = self.factory.makePerson() | 3339 | other_person = self.factory.makePerson() |
222 | 3333 | other_webservice = webservice_for_person( | 3340 | other_webservice = webservice_for_person( |
223 | @@ -3335,7 +3342,7 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
224 | 3335 | other_webservice.default_api_version = "devel" | 3342 | other_webservice.default_api_version = "devel" |
225 | 3336 | response = other_webservice.named_post( | 3343 | response = other_webservice.named_post( |
226 | 3337 | snap_url, "completeAuthorization", | 3344 | snap_url, "completeAuthorization", |
228 | 3338 | discharge_macaroon="dummy-discharge") | 3345 | discharge_macaroon=discharge_macaroon.serialize()) |
229 | 3339 | self.assertEqual(401, response.status) | 3346 | self.assertEqual(401, response.status) |
230 | 3340 | 3347 | ||
231 | 3341 | def test_completeAuthorization_both_macaroons(self): | 3348 | def test_completeAuthorization_both_macaroons(self): |
232 | @@ -3349,13 +3356,17 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
233 | 3349 | store_name=self.factory.getUniqueUnicode()) | 3356 | store_name=self.factory.getUniqueUnicode()) |
234 | 3350 | snap_url = api_url(snap) | 3357 | snap_url = api_url(snap) |
235 | 3351 | logout() | 3358 | logout() |
236 | 3359 | root_macaroon = Macaroon() | ||
237 | 3360 | discharge_macaroon = Macaroon() | ||
238 | 3352 | response = self.webservice.named_post( | 3361 | response = self.webservice.named_post( |
239 | 3353 | snap_url, "completeAuthorization", | 3362 | snap_url, "completeAuthorization", |
241 | 3354 | root_macaroon="dummy-root", discharge_macaroon="dummy-discharge") | 3363 | root_macaroon=root_macaroon.serialize(), |
242 | 3364 | discharge_macaroon=discharge_macaroon.serialize()) | ||
243 | 3355 | self.assertEqual(200, response.status) | 3365 | self.assertEqual(200, response.status) |
244 | 3356 | with person_logged_in(self.person): | 3366 | with person_logged_in(self.person): |
245 | 3357 | self.assertEqual( | 3367 | self.assertEqual( |
247 | 3358 | {"root": "dummy-root", "discharge": "dummy-discharge"}, | 3368 | {"root": root_macaroon.serialize(), |
248 | 3369 | "discharge": discharge_macaroon.serialize()}, | ||
249 | 3359 | snap.store_secrets) | 3370 | snap.store_secrets) |
250 | 3360 | 3371 | ||
251 | 3361 | def test_completeAuthorization_only_root_macaroon(self): | 3372 | def test_completeAuthorization_only_root_macaroon(self): |
252 | @@ -3370,11 +3381,44 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
253 | 3370 | store_name=self.factory.getUniqueUnicode()) | 3381 | store_name=self.factory.getUniqueUnicode()) |
254 | 3371 | snap_url = api_url(snap) | 3382 | snap_url = api_url(snap) |
255 | 3372 | logout() | 3383 | logout() |
256 | 3384 | root_macaroon = Macaroon() | ||
257 | 3373 | response = self.webservice.named_post( | 3385 | response = self.webservice.named_post( |
259 | 3374 | snap_url, "completeAuthorization", root_macaroon="dummy-root") | 3386 | snap_url, "completeAuthorization", |
260 | 3387 | root_macaroon=root_macaroon.serialize()) | ||
261 | 3375 | self.assertEqual(200, response.status) | 3388 | self.assertEqual(200, response.status) |
262 | 3376 | with person_logged_in(self.person): | 3389 | with person_logged_in(self.person): |
264 | 3377 | self.assertEqual({"root": "dummy-root"}, snap.store_secrets) | 3390 | self.assertEqual( |
265 | 3391 | {"root": root_macaroon.serialize()}, snap.store_secrets) | ||
266 | 3392 | |||
267 | 3393 | def test_completeAuthorization_malformed_root_macaroon(self): | ||
268 | 3394 | with admin_logged_in(): | ||
269 | 3395 | snappy_series = self.factory.makeSnappySeries() | ||
270 | 3396 | snap = self.factory.makeSnap( | ||
271 | 3397 | registrant=self.person, store_upload=True, | ||
272 | 3398 | store_series=snappy_series, | ||
273 | 3399 | store_name=self.factory.getUniqueUnicode()) | ||
274 | 3400 | snap_url = api_url(snap) | ||
275 | 3401 | logout() | ||
276 | 3402 | response = self.webservice.named_post( | ||
277 | 3403 | snap_url, "completeAuthorization", root_macaroon="nonsense") | ||
278 | 3404 | self.assertThat(response, MatchesStructure.byEquality( | ||
279 | 3405 | status=400, body=b"root_macaroon is invalid.")) | ||
280 | 3406 | |||
281 | 3407 | def test_completeAuthorization_malformed_discharge_macaroon(self): | ||
282 | 3408 | with admin_logged_in(): | ||
283 | 3409 | snappy_series = self.factory.makeSnappySeries() | ||
284 | 3410 | snap = self.factory.makeSnap( | ||
285 | 3411 | registrant=self.person, store_upload=True, | ||
286 | 3412 | store_series=snappy_series, | ||
287 | 3413 | store_name=self.factory.getUniqueUnicode()) | ||
288 | 3414 | snap_url = api_url(snap) | ||
289 | 3415 | logout() | ||
290 | 3416 | response = self.webservice.named_post( | ||
291 | 3417 | snap_url, "completeAuthorization", | ||
292 | 3418 | root_macaroon=Macaroon().serialize(), | ||
293 | 3419 | discharge_macaroon="nonsense") | ||
294 | 3420 | self.assertThat(response, MatchesStructure.byEquality( | ||
295 | 3421 | status=400, body=b"discharge_macaroon is invalid.")) | ||
296 | 3378 | 3422 | ||
297 | 3379 | def test_completeAuthorization_encrypted(self): | 3423 | def test_completeAuthorization_encrypted(self): |
298 | 3380 | private_key = PrivateKey.generate() | 3424 | private_key = PrivateKey.generate() |
299 | @@ -3384,16 +3428,18 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
300 | 3384 | bytes(private_key.public_key)).decode("UTF-8")) | 3428 | bytes(private_key.public_key)).decode("UTF-8")) |
301 | 3385 | with admin_logged_in(): | 3429 | with admin_logged_in(): |
302 | 3386 | snappy_series = self.factory.makeSnappySeries() | 3430 | snappy_series = self.factory.makeSnappySeries() |
303 | 3431 | root_macaroon = Macaroon() | ||
304 | 3432 | discharge_macaroon = Macaroon() | ||
305 | 3387 | snap = self.factory.makeSnap( | 3433 | snap = self.factory.makeSnap( |
306 | 3388 | registrant=self.person, store_upload=True, | 3434 | registrant=self.person, store_upload=True, |
307 | 3389 | store_series=snappy_series, | 3435 | store_series=snappy_series, |
308 | 3390 | store_name=self.factory.getUniqueUnicode(), | 3436 | store_name=self.factory.getUniqueUnicode(), |
310 | 3391 | store_secrets={"root": "dummy-root"}) | 3437 | store_secrets={"root": root_macaroon.serialize()}) |
311 | 3392 | snap_url = api_url(snap) | 3438 | snap_url = api_url(snap) |
312 | 3393 | logout() | 3439 | logout() |
313 | 3394 | response = self.webservice.named_post( | 3440 | response = self.webservice.named_post( |
314 | 3395 | snap_url, "completeAuthorization", | 3441 | snap_url, "completeAuthorization", |
316 | 3396 | discharge_macaroon="dummy-discharge") | 3442 | discharge_macaroon=discharge_macaroon.serialize()) |
317 | 3397 | self.assertEqual(200, response.status) | 3443 | self.assertEqual(200, response.status) |
318 | 3398 | self.pushConfig( | 3444 | self.pushConfig( |
319 | 3399 | "snappy", | 3445 | "snappy", |
320 | @@ -3402,9 +3448,9 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
321 | 3402 | container = getUtility(IEncryptedContainer, "snap-store-secrets") | 3448 | container = getUtility(IEncryptedContainer, "snap-store-secrets") |
322 | 3403 | with person_logged_in(self.person): | 3449 | with person_logged_in(self.person): |
323 | 3404 | self.assertThat(snap.store_secrets, MatchesDict({ | 3450 | self.assertThat(snap.store_secrets, MatchesDict({ |
325 | 3405 | "root": Equals("dummy-root"), | 3451 | "root": Equals(root_macaroon.serialize()), |
326 | 3406 | "discharge_encrypted": AfterPreprocessing( | 3452 | "discharge_encrypted": AfterPreprocessing( |
328 | 3407 | container.decrypt, Equals("dummy-discharge")), | 3453 | container.decrypt, Equals(discharge_macaroon.serialize())), |
329 | 3408 | })) | 3454 | })) |
330 | 3409 | 3455 | ||
331 | 3410 | def makeBuildableDistroArchSeries(self, **kwargs): | 3456 | def makeBuildableDistroArchSeries(self, **kwargs): |
LGTM