From 1de3eda7acd9e42787002713f219aea452e21e7f Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone <exarkun@twistedmatrix.com> Date: Tue, 12 May 2020 09:27:04 -0400 Subject: [PATCH] Add a test for MorePassesRequired making it across the network Meant this to be in PR#152 but somehow forgot to even commit it... --- src/_zkapauthorizer/_storage_server.py | 21 +------- src/_zkapauthorizer/api.py | 4 +- src/_zkapauthorizer/storage_common.py | 20 ++++++++ .../tests/test_storage_protocol.py | 50 +++++++++++++++++++ 4 files changed, 74 insertions(+), 21 deletions(-) diff --git a/src/_zkapauthorizer/_storage_server.py b/src/_zkapauthorizer/_storage_server.py index 73753fe..bb89df0 100644 --- a/src/_zkapauthorizer/_storage_server.py +++ b/src/_zkapauthorizer/_storage_server.py @@ -88,6 +88,7 @@ from .foolscap import ( RIPrivacyPassAuthorizedStorageServer, ) from .storage_common import ( + MorePassesRequired, pass_value_attribute, required_passes, allocate_buckets_message, @@ -102,26 +103,6 @@ from .storage_common import ( SLOT_HEADER_SIZE = 468 LEASE_TRAILER_SIZE = 4 -@attr.s -class MorePassesRequired(Exception): - """ - Storage operations fail with ``MorePassesRequired`` when they are not - accompanied by a sufficient number of valid passes. - - :ivar int valid_count: The number of valid passes presented in the - operation. - - ivar int required_count: The number of valid passes which must be - presented for the operation to be authorized. - - :ivar list[int] signature_check_failed: Indices into the supplied list of - passes indicating passes which failed the signature check. - """ - valid_count = attr.ib() - required_count = attr.ib() - signature_check_failed = attr.ib() - - @attr.s class _ValidationResult(object): """ diff --git a/src/_zkapauthorizer/api.py b/src/_zkapauthorizer/api.py index 365e39a..70e4725 100644 --- a/src/_zkapauthorizer/api.py +++ b/src/_zkapauthorizer/api.py @@ -20,8 +20,10 @@ __all__ = [ "ZKAPAuthorizer", ] -from ._storage_server import ( +from .storage_common import ( MorePassesRequired, +) +from ._storage_server import ( LeaseRenewalRequired, ZKAPAuthorizerStorageServer, ) diff --git a/src/_zkapauthorizer/storage_common.py b/src/_zkapauthorizer/storage_common.py index f00997b..1a52b4d 100644 --- a/src/_zkapauthorizer/storage_common.py +++ b/src/_zkapauthorizer/storage_common.py @@ -30,6 +30,26 @@ from .validators import ( greater_than, ) +@attr.s +class MorePassesRequired(Exception): + """ + Storage operations fail with ``MorePassesRequired`` when they are not + accompanied by a sufficient number of valid passes. + + :ivar int valid_count: The number of valid passes presented in the + operation. + + ivar int required_count: The number of valid passes which must be + presented for the operation to be authorized. + + :ivar list[int] signature_check_failed: Indices into the supplied list of + passes indicating passes which failed the signature check. + """ + valid_count = attr.ib() + required_count = attr.ib() + signature_check_failed = attr.ib() + + def _message_maker(label): def make_message(storage_index): return u"{label} {storage_index}".format( diff --git a/src/_zkapauthorizer/tests/test_storage_protocol.py b/src/_zkapauthorizer/tests/test_storage_protocol.py index a267c06..612a853 100644 --- a/src/_zkapauthorizer/tests/test_storage_protocol.py +++ b/src/_zkapauthorizer/tests/test_storage_protocol.py @@ -111,6 +111,7 @@ from .foolscap import ( LocalRemote, ) from ..api import ( + MorePassesRequired, ZKAPAuthorizerStorageServer, ZKAPAuthorizerStorageClient, ) @@ -215,6 +216,55 @@ class ShareTests(TestCase): succeeded(matches_version_dictionary()), ) + @given( + storage_index=storage_indexes(), + renew_secret=lease_renew_secrets(), + cancel_secret=lease_cancel_secrets(), + sharenums=sharenum_sets(), + size=sizes(), + ) + def test_rejected_passes_reported(self, storage_index, renew_secret, cancel_secret, sharenums, size): + """ + Any passes rejected by the storage server are reported with a + ``MorePassesRequired`` exception sent to the client. + """ + # Hypothesis causes our storage server to be used many times. Clean + # up between iterations. + cleanup_storage_server(self.anonymous_storage_server) + + # Break our infinite pass factory by replacing the expected key with a + # new one. Now the passes are mis-signed as far as the server is + # concerned. The clunky way we control pass generation means it's + # hard to have anything but an all-or-nothing test. Perhaps some + # future refactoring will let us exercise a mix of passes with valid + # and invalid signatures. + self.signing_key = random_signing_key() + + num_passes = required_passes(self.pass_value, [size] * len(sharenums)) + + self.assertThat( + self.client.allocate_buckets( + storage_index, + renew_secret, + cancel_secret, + sharenums, + size, + canary=self.canary, + ), + failed( + AfterPreprocessing( + lambda f: f.value, + Equals( + MorePassesRequired( + valid_count=0, + required_count=num_passes, + signature_check_failed=range(num_passes), + ), + ), + ), + ), + ) + @given( storage_index=storage_indexes(), renew_secret=lease_renew_secrets(), -- GitLab