Skip to content

Commit

Permalink
fix: allow signed url version v4 without signed credentials (googleap…
Browse files Browse the repository at this point in the history
…is#356)

* Fix: signed_url_v4 to accept credentials without private key. Preserve checks for efficiency in case of neither access_token nor service_account_email are provided.
Fix: tests v4 with token to take into account not Signing credential class.

* fix typo: 2 new lines before new test class

* fix doc: Improve docstring to explain the use of the access_token AND the service_account_email, or the signer email.

* fix: test coverage with the new IF branch

* lint

Co-authored-by: Tres Seaver <tseaver@palladion.com>
Co-authored-by: Frank Natividad <frankyn@users.noreply.github.com>
Co-authored-by: Frank Natividad <franknatividad@google.com>
  • Loading branch information
4 people authored and cojenco committed Oct 13, 2021
1 parent 164efeb commit 0aa944c
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 4 deletions.
12 changes: 9 additions & 3 deletions google/cloud/storage/_signing.py
Expand Up @@ -457,9 +457,12 @@ def generate_signed_url_v4(
google-cloud-python/issues/922
.. _reference: https://cloud.google.com/storage/docs/reference-headers
:type credentials: :class:`google.auth.credentials.Signing`
:param credentials: Credentials object with an associated private key to
sign text.
sign text. That credentials must provide signer_email
only if service_account_email and access_token are not
passed.
:type resource: str
:param resource: A pointer to a specific resource
Expand Down Expand Up @@ -533,7 +536,6 @@ def generate_signed_url_v4(
:returns: A signed URL you can use to access the resource
until expiration.
"""
ensure_signed_credentials(credentials)
expiration_seconds = get_expiration_seconds_v4(expiration)

if _request_timestamp is None:
Expand All @@ -542,7 +544,11 @@ def generate_signed_url_v4(
request_timestamp = _request_timestamp
datestamp = _request_timestamp[:8]

client_email = credentials.signer_email
client_email = service_account_email
if not access_token or not service_account_email:
ensure_signed_credentials(credentials)
client_email = credentials.signer_email

credential_scope = "{}/auto/storage/goog4_request".format(datestamp)
credential = "{}/{}".format(client_email, credential_scope)

Expand Down
50 changes: 49 additions & 1 deletion tests/unit/test__signing.py
Expand Up @@ -653,7 +653,22 @@ def test_w_custom_query_parameters_w_string_value(self):
def test_w_custom_query_parameters_w_none_value(self):
self._generate_helper(query_parameters={"qux": None})

def test_with_access_token(self):
def test_with_access_token_and_service_account_email(self):
resource = "/name/path"
credentials = _make_credentials()
email = mock.sentinel.service_account_email
with mock.patch(
"google.cloud.storage._signing._sign_message", return_value=b"DEADBEEF"
):
self._call_fut(
credentials,
resource=resource,
expiration=datetime.timedelta(days=5),
service_account_email=email,
access_token="token",
)

def test_with_access_token_and_service_account_email_and_signer_email(self):
resource = "/name/path"
signer_email = "service@example.com"
credentials = _make_credentials(signer_email=signer_email)
Expand All @@ -668,6 +683,39 @@ def test_with_access_token(self):
access_token="token",
)

def test_with_signer_email(self):
resource = "/name/path"
signer_email = "service@example.com"
credentials = _make_credentials(signer_email=signer_email)
credentials.sign_bytes.return_value = b"DEADBEEF"
self._call_fut(
credentials, resource=resource, expiration=datetime.timedelta(days=5),
)

def test_with_service_account_email_and_signer_email(self):
resource = "/name/path"
signer_email = "service@example.com"
credentials = _make_credentials(signer_email=signer_email)
credentials.sign_bytes.return_value = b"DEADBEEF"
self._call_fut(
credentials,
resource=resource,
expiration=datetime.timedelta(days=5),
service_account_email=signer_email,
)

def test_with_token_and_signer_email(self):
resource = "/name/path"
signer_email = "service@example.com"
credentials = _make_credentials(signer_email=signer_email)
credentials.sign_bytes.return_value = b"DEADBEEF"
self._call_fut(
credentials,
resource=resource,
expiration=datetime.timedelta(days=5),
access_token="token",
)


class Test_sign_message(unittest.TestCase):
@staticmethod
Expand Down

0 comments on commit 0aa944c

Please sign in to comment.