Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: Gcs generates invalid presigned urls when predefinedAcl is set #5612

Open
1 task done
wlinna opened this issue Feb 7, 2025 · 0 comments
Open
1 task done

bug: Gcs generates invalid presigned urls when predefinedAcl is set #5612

wlinna opened this issue Feb 7, 2025 · 0 comments
Labels
bug Something isn't working

Comments

@wlinna
Copy link
Contributor

wlinna commented Feb 7, 2025

Describe the bug

Gcs does not handle predefinedAcl incorrectly when using presign. Trying to use the resulting URL will result in an error like this

<?xml version='1.0' encoding='UTF-8'?>
<Error>
	<Code>InvalidArgument</Code>
	<Message>Invalid argument.</Message>
	<Details>Invalid canned acl: publicRead</Details>
</Error>

It turns out that the XML API predefined ACLs uses kebab casing instead of camel casing, and thus publicRead should be converted to public-read when signing urls etc.

Here's the relevant documentation:
https://cloud.google.com/storage/docs/access-control/lists#predefined-acl

Steps to Reproduce

Here is a simple program that reproduces the problem

use std::time::Duration;
use opendal::{services::Gcs, Operator};

#[tokio::main]
async fn main() {
    let bucket = todo!("Enter your own bucket name"); 

    let gcs_no_acl = Operator::new(Gcs::default().bucket(&bucket)).unwrap().finish();
    let gcs_has_acl = Operator::new(Gcs::default().bucket(&bucket).predefined_acl("publicRead")).unwrap().finish();

    let client = reqwest::Client::new();

    {
        let presign = gcs_no_acl.presign_write("file_no_acl", Duration::from_secs(3600)).await.unwrap();
        let res = client.put(presign.uri().to_string()).headers(presign.header().clone())
            .body("Hello, world")
            .send().await.unwrap();

        let status = res.status();
        assert!(status.is_success());  // Works, and file_no_acl is present 
    }

    {
        let presign = gcs_has_acl.presign_write("file_has_acl", Duration::from_secs(3600)).await.unwrap();
        let res = client.put(presign.uri().to_string()).headers(presign.header().clone())
            .body("Hello, world")
            .send().await.unwrap();

        let status = res.status();
        let response_text = res.text().await.unwrap();
        println!("{response_text}");   //  TL;DR: Invalid canned acl: publicRead
        assert!(status.is_success());   // FAILS
    }
}

Expected Behavior

Both asserts should pass, and my bucket should have both file_no_acl and file_has_acl after running the program. Additionally, file_has_acl should have publicRead ACL set.

Additional Context

No response

Are you willing to submit a PR to fix this bug?

  • Yes, I would like to submit a PR.
@wlinna wlinna added the bug Something isn't working label Feb 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant