Skip to content

Commit

Permalink
Merge pull request #456 from Backblaze/change_auhtorize_account_signa…
Browse files Browse the repository at this point in the history
…ture

Change auhtorize account signature
  • Loading branch information
mpnowacki-reef committed Dec 12, 2023
2 parents becb8cb + 96b1890 commit c9eed62
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 21 deletions.
13 changes: 10 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ jobs:
fail-fast: false
matrix:
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "pypy-3.9", "pypy-3.10"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "pypy-3.9", "pypy-3.9-nightly", "pypy-3.10"]
exclude:
- os: "macos-latest"
python-version: "pypy-3.9"
Expand All @@ -94,6 +94,13 @@ jobs:
python-version: "pypy-3.10"
- os: "windows-latest"
python-version: "pypy-3.10"
# TODO: pypy-3.9 started breaking on windows, due to some prints leftover in pypy release
- os: "ubuntu-latest"
python-version: "pypy-3.9-nightly"
- os: "macos-latest"
python-version: "pypy-3.9-nightly"
- os: "windows-latest"
python-version: "pypy-3.9"
steps:
- uses: actions/checkout@v3
with:
Expand All @@ -106,12 +113,12 @@ jobs:
- name: Install dependencies
run: python -m pip install --upgrade nox pip setuptools
- name: Run unit tests
run: nox -vs unit
run: nox -vs unit -- -v
env:
SKIP_COVERAGE: ${{ startsWith(matrix.python-version, env.SKIP_COVERAGE_PYTHON_VERSION_PREFIX) }}
- name: Run integration tests
if: ${{ env.B2_TEST_APPLICATION_KEY != '' && env.B2_TEST_APPLICATION_KEY_ID != '' }}
run: nox -vs integration -- --dont-cleanup-old-buckets
run: nox -vs integration -- --dont-cleanup-old-buckets -v
doc:
needs: build
runs-on: ubuntu-latest
Expand Down
4 changes: 2 additions & 2 deletions b2sdk/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,13 @@ def authorize_automatically(self):
return self.session.authorize_automatically()

@limit_trace_arguments(only=('self', 'realm'))
def authorize_account(self, realm, application_key_id, application_key):
def authorize_account(self, application_key_id, application_key, realm='production'):
"""
Perform account authorization.
:param str realm: a realm to authorize account in (usually just "production")
:param str application_key_id: :term:`application key ID`
:param str application_key: user's :term:`application key`
:param str realm: a realm to authorize account in (usually just "production")
"""
self.session.authorize_account(realm, application_key_id, application_key)
self._populate_bucket_cache_from_key()
Expand Down
10 changes: 10 additions & 0 deletions b2sdk/v2/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Services(v3.Services):
# override to use legacy B2Session with legacy B2Http
# and to raise old style BucketIdNotFound exception
# and to use old style Bucket
# and to use legacy authorize_account signature
class B2Api(v3.B2Api):
SESSION_CLASS = staticmethod(B2Session)
BUCKET_CLASS = staticmethod(Bucket)
Expand All @@ -46,3 +47,12 @@ def get_bucket_by_id(self, bucket_id: str) -> v3.Bucket:
return super().get_bucket_by_id(bucket_id)
except v3BucketIdNotFound as e:
raise BucketIdNotFound(e.bucket_id)

# one could contemplate putting "@limit_trace_arguments(only=('self', 'realm'))" here but logfury meta magic copies
# the appropriate attributes from base classes
def authorize_account(self, realm, application_key_id, application_key):
return super().authorize_account(
application_key_id=application_key_id,
application_key=application_key,
realm=realm,
)
1 change: 1 addition & 0 deletions changelog.d/+authorize_account.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Change v3.B2Api.authorize_account signature to make `realm` optional and `"production"` by default.
1 change: 1 addition & 0 deletions changelog.d/+make_tests_in_ci_verbose.infrastructure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `-v` to pytest in CI.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Run windows pypy3.9 tests on nightly builds.
71 changes: 63 additions & 8 deletions test/unit/api/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,29 @@ def setUp(self):
self.raw_api = self.api.session.raw_api
(self.application_key_id, self.master_key) = self.raw_api.create_account()

@pytest.mark.apiver(from_ver=3)
def test_authorize_signature_v3_default_realm(self):
self.api.authorize_account(
self.application_key_id,
self.master_key,
)

@pytest.mark.apiver(from_ver=3)
def test_authorize_signature_v3_explicit_realm(self):
self.api.authorize_account(
self.application_key_id,
self.master_key,
'production',
)

@pytest.mark.apiver(to_ver=2)
def test_authorize_signature_up_to_ver_2(self):
self.api.authorize_account(
'production',
self.application_key_id,
self.master_key,
)

def test_get_file_info(self):
self._authorize_account()
bucket = self.api.create_bucket('bucket1', 'allPrivate')
Expand Down Expand Up @@ -312,7 +335,11 @@ def test_buckets_with_encryption(self):

# now check it with no readBucketEncryption permission to see that it's unknown
key = create_key(self.api, ['listBuckets'], 'key1')
self.api.authorize_account('production', key.id_, key.application_key)
self.api.authorize_account(
application_key_id=key.id_,
application_key=key.application_key,
realm='production',
)
buckets = {
b.name: b
for b in self.api.list_buckets() # scan again with new key
Expand Down Expand Up @@ -352,7 +379,11 @@ def test_reauthorize_with_app_key(self):
key = create_key(self.api, ['listBuckets'], 'key1')

# authorize with the key
self.api.authorize_account('production', key.id_, key.application_key)
self.api.authorize_account(
application_key_id=key.id_,
application_key=key.application_key,
realm='production',
)

# expire the auth token we just got
self.raw_api.expire_auth_token(self.account_info.get_account_auth_token())
Expand All @@ -365,22 +396,34 @@ def test_list_buckets_with_restriction(self):
bucket1 = self.api.create_bucket('bucket1', 'allPrivate')
self.api.create_bucket('bucket2', 'allPrivate')
key = create_key(self.api, ['listBuckets'], 'key1', bucket_id=bucket1.id_)
self.api.authorize_account('production', key.id_, key.application_key)
self.api.authorize_account(
application_key_id=key.id_,
application_key=key.application_key,
realm='production',
)
assert [b.name for b in self.api.list_buckets(bucket_name=bucket1.name)] == ['bucket1']

def test_get_bucket_by_name_with_bucket_restriction(self):
self._authorize_account()
bucket1 = self.api.create_bucket('bucket1', 'allPrivate')
key = create_key(self.api, ['listBuckets'], 'key1', bucket_id=bucket1.id_)
self.api.authorize_account('production', key.id_, key.application_key)
self.api.authorize_account(
application_key_id=key.id_,
application_key=key.application_key,
realm='production',
)
assert self.api.get_bucket_by_name('bucket1').id_ == bucket1.id_

def test_list_buckets_with_restriction_and_wrong_name(self):
self._authorize_account()
bucket1 = self.api.create_bucket('bucket1', 'allPrivate')
bucket2 = self.api.create_bucket('bucket2', 'allPrivate')
key = create_key(self.api, ['listBuckets'], 'key1', bucket_id=bucket1.id_)
self.api.authorize_account('production', key.id_, key.application_key)
self.api.authorize_account(
application_key_id=key.id_,
application_key=key.application_key,
realm='production',
)
with pytest.raises(RestrictedBucket) as excinfo:
self.api.list_buckets(bucket_name=bucket2.name)
assert str(excinfo.value) == 'Application key is restricted to bucket: bucket1'
Expand All @@ -390,7 +433,11 @@ def test_list_buckets_with_restriction_and_no_name(self):
bucket1 = self.api.create_bucket('bucket1', 'allPrivate')
self.api.create_bucket('bucket2', 'allPrivate')
key = create_key(self.api, ['listBuckets'], 'key1', bucket_id=bucket1.id_)
self.api.authorize_account('production', key.id_, key.application_key)
self.api.authorize_account(
application_key_id=key.id_,
application_key=key.application_key,
realm='production',
)
with pytest.raises(RestrictedBucket) as excinfo:
self.api.list_buckets()
assert str(excinfo.value) == 'Application key is restricted to bucket: bucket1'
Expand All @@ -400,13 +447,21 @@ def test_list_buckets_with_restriction_and_wrong_id(self):
bucket1 = self.api.create_bucket('bucket1', 'allPrivate')
self.api.create_bucket('bucket2', 'allPrivate')
key = create_key(self.api, ['listBuckets'], 'key1', bucket_id=bucket1.id_)
self.api.authorize_account('production', key.id_, key.application_key)
self.api.authorize_account(
application_key_id=key.id_,
application_key=key.application_key,
realm='production',
)
with pytest.raises(RestrictedBucket) as excinfo:
self.api.list_buckets(bucket_id='not the one bound to the key')
assert str(excinfo.value) == f'Application key is restricted to bucket: {bucket1.id_}'

def _authorize_account(self):
self.api.authorize_account('production', self.application_key_id, self.master_key)
self.api.authorize_account(
application_key_id=self.application_key_id,
application_key=self.master_key,
realm='production',
)

def test_update_file_retention(self):
self._authorize_account()
Expand Down
24 changes: 20 additions & 4 deletions test/unit/bucket/test_bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,11 @@ def setUp(self):
self.api = self.get_api()
self.simulator = self.api.session.raw_api
(self.account_id, self.master_key) = self.simulator.create_account()
self.api.authorize_account('production', self.account_id, self.master_key)
self.api.authorize_account(
application_key_id=self.account_id,
application_key=self.master_key,
realm='production',
)
self.api_url = self.account_info.get_api_url()
self.account_auth_token = self.account_info.get_account_auth_token()
self.bucket = self.api.create_bucket(self.bucket_name, 'allPublic')
Expand Down Expand Up @@ -463,7 +467,11 @@ def test_version_by_name_file_lock(self):
]
)

low_perm_api.authorize_account('production', low_perm_key.id_, low_perm_key.application_key)
low_perm_api.authorize_account(
application_key_id=low_perm_key.id_,
application_key=low_perm_key.application_key,
realm='production',
)
low_perm_bucket = low_perm_api.get_bucket_by_name('my-bucket-with-file-lock')

file_version = low_perm_bucket.get_file_info_by_name('a')
Expand Down Expand Up @@ -2680,7 +2688,11 @@ def test_authorize_for_bucket_ensures_cache(self):
bucket_id=self.bucket_id,
)

self.api.authorize_account('production', key.id_, key.application_key)
self.api.authorize_account(
application_key_id=key.id_,
application_key=key.application_key,
realm='production',
)

# Check whether the bucket fetching performs an API call.
with mock.patch.object(self.api, 'list_buckets') as mock_list_buckets:
Expand All @@ -2702,7 +2714,11 @@ def test_authorize_for_non_existing_bucket(self):
)

with self.assertRaises(RestrictedBucketMissing):
self.api.authorize_account('production', key.id_, key.application_key)
self.api.authorize_account(
application_key_id=key.id_,
application_key=key.application_key,
realm='production',
)


class TestDownloadLocalDirectoryIssues(TestCaseWithBucket):
Expand Down
6 changes: 5 additions & 1 deletion test/unit/file_version/test_file_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ def setUp(self):
)
self.raw_api = self.api.session.raw_api
(self.application_key_id, self.master_key) = self.raw_api.create_account()
self.api.authorize_account('production', self.application_key_id, self.master_key)
self.api.authorize_account(
application_key_id=self.application_key_id,
application_key=self.master_key,
realm='production',
)
self.bucket = self.api.create_bucket('testbucket', 'allPrivate', is_file_lock_enabled=True)
self.file_version = self.bucket.upload_bytes(
b'nothing', 'test_file', cache_control='private, max-age=3600'
Expand Down
6 changes: 5 additions & 1 deletion test/unit/replication/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ def api() -> B2Api:

simulator = api.session.raw_api
account_id, master_key = simulator.create_account()
api.authorize_account('production', account_id, master_key)
api.authorize_account(
application_key_id=account_id,
application_key=master_key,
realm='production',
)
# api_url = account_info.get_api_url()
# account_auth_token = account_info.get_account_auth_token()1
return api
Expand Down
6 changes: 5 additions & 1 deletion test/unit/v_all/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,11 @@ def setUp(self):
(self.application_key_id, self.master_key) = self.raw_api.create_account()

def _authorize_account(self):
self.api.authorize_account('production', self.application_key_id, self.master_key)
self.api.authorize_account(
realm='production',
application_key_id=self.application_key_id,
application_key=self.master_key,
)

@pytest.mark.apiver(to_ver=1)
def test_get_bucket_by_id_up_to_v1(self):
Expand Down
6 changes: 5 additions & 1 deletion test/unit/v_all/test_replication.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ def setUp(self):
self.application_key_id, self.master_key = self.raw_api.create_account()

def _authorize_account(self):
self.api.authorize_account('production', self.application_key_id, self.master_key)
self.api.authorize_account(
realm='production',
application_key_id=self.application_key_id,
application_key=self.master_key,
)

@pytest.mark.apiver(from_ver=2)
def test_setup_both(self):
Expand Down

0 comments on commit c9eed62

Please sign in to comment.