Skip to content

Impossible to use signed url v4 and the Service Account Credential APIs #355

Closed
@guillaumeblaquiere

Description

@guillaumeblaquiere

Months ago, I solved an issue to a Stack overflow user by explaining how to generate a signed URL without a service account JSON fey file. I also release an article on this

Today, a comment of a user told me that is doesn't work. They open a new Stack Overflow question and in their question, there is the v4 mentioned.

I dug into the code and yes, the v2 and the v4 haven't the same behavior: the v4 check if the credential can generate a signed URL by itself, that implies the useless check later that allows to use Service Account Credential API, instead of the service account private key to generate the signature.

Environment details

  • Linux (Cloud Function and Cloud Run)
  • Python version: python --version 3.7 and 3.8
  • google-cloud-storage version: latest (1.35.0)

Steps to reproduce

  1. Working code on Cloud Run (for example) Replace YOUR_BUCKET by a valid bucket
import os
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def sign_url():
    from google.cloud import storage
    from datetime import datetime, timedelta

    import google.auth

    credentials, project_id = google.auth.default()

    # Perform a refresh request to get the access token of the current credentials (Else, it's None)
    from google.auth.transport import requests
    r = requests.Request()
    credentials.refresh(r)

    client = storage.Client()
    bucket = client.get_bucket('YOUR_BUCKET')
    blob = bucket.get_blob('name.csv')

    service_account_email = credentials.service_account_email

    url = blob.generate_signed_url(service_account_email=service_account_email, access_token=credentials.token,version="v2", method="PUT",expiration=timedelta(minutes=120),content_type="application/octet-stream")
    return url, 200

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))

  1. Broken code on Cloud Run (for example) Replace YOUR_BUCKET by a valid bucket
import os
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def sign_url():
    from google.cloud import storage
    from datetime import datetime, timedelta

    import google.auth

    credentials, project_id = google.auth.default()

    # Perform a refresh request to get the access token of the current credentials (Else, it's None)
    from google.auth.transport import requests
    r = requests.Request()
    credentials.refresh(r)

    client = storage.Client()
    bucket = client.get_bucket('YOUR_BUCKET')
    blob = bucket.get_blob('name.csv')

    service_account_email = credentials.service_account_email

    url = blob.generate_signed_url(service_account_email=service_account_email, access_token=credentials.token,version="v4", method="PUT",expiration=timedelta(minutes=120),content_type="application/octet-stream")
    return url, 200

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))

Only the version (v2/v4) has changed

Fix proposal is coming.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api: storageIssues related to the googleapis/python-storage API.priority: p2Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions