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

feat: support query-based requests #6

Merged
merged 1 commit into from
Jul 10, 2024
Merged

Conversation

itsHenry35
Copy link

@KevinWang15
Copy link

KevinWang15 commented Jul 7, 2024

Hi @itsHenry35,

Thank you for your timely pull request.

I've tested your code, and I noticed that this change might not always be correct.

In most cases, amzDate is present in the header.

As an alternative, we could consider the following approach:

var date string
if date = req.Header.Get(amzDate); date == "" {
    if date = r.Header.Get(headerDate); date == "" {
        if date = queryf.Get(amzDate); date == "" {
            return errMissingDateHeader
        }
    }
}

Additionally, I'd like to suggest squashing your commits to remove the "chore: remove generated binary" commit before submitting this PR (or you could use git commit --amend).

Once again, thanks for the excellent work!

@itsHenry35
Copy link
Author

Hi @itsHenry35,

Thank you for your timely pull request.

I've tested your code, and I noticed that this change might not always be correct.

In most cases, `amzDate` is present in the header.

As an alternative, we could consider the following approach:

var date string
if date = req.Header.Get(amzDate); date == "" {
    if date = r.Header.Get(headerDate); date == "" {
        if date = queryf.Get(amzDate); date == "" {
            return errMissingDateHeader
        }
    }
}

Additionally, I'd like to suggest squashing your commits to remove the "chore: remove generated binary" commit before submitting this PR (or you could use git commit --amend).

Once again, thanks for the excellent work!

Oh, i was opposed to just add a if judgement instead of replacing it, but I did it by mistake. Sorry for the fault, I will correct it

@KevinWang15
Copy link

@itsHenry35 Great, I have tested your code. Now it works. LGTM

cc @ncw PTAL

Copy link
Member

@ncw ncw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for doing this - every step towards greater compatibility is a good one :-)

I put some comments inline for discussion.

Thanks

Nick

Edit we should also think of some tests!

if v4Auth == "" {
// try query based
v4Auth = fmt.Sprintf("%s Credential=%s,SignedHeaders=%s, Signature=%s", queryf.Get(amzAlgorithm), queryf.Get(amzCredential), queryf.Get(amzSignedHeaders), queryf.Get(amzSignature))
if v4Auth == "" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will never be true. What is this test for?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
Please have a look as a reference. When the client generates a web url for easier accessing on web browsers, the authorization headers are passed in query-mode instead of headers. In this case, the v4Auth will be "" and we can get the auth params from the url query.

Copy link

@KevinWang15 KevinWang15 Jul 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code change is for support for "pre-signed URLs", a feature quite commonly used in S3.

Example (https://runkit.com/kevinwang15/668e1f70270f8e0008046ad9):

const AWS = require("aws-sdk");

const s3 = new AWS.S3({
    endpoint: 'https://127.0.0.1',
    accessKeyId: 'aaaa',
    secretAccessKey: 'ssss',
    s3ForcePathStyle: true,
    signatureVersion: 'v4',
    sslEnabled: true,
});


function generateDownloadUrl(bucket, key) {
    const params = {
        Bucket: bucket,
        Key: key,
        Expires: 3600,
    };

    s3.getSignedUrl('getObject', params, (err, url) => {
        if (err) {
            console.error(err);
        } else {
            console.log(url);
        }
    });
}

generateDownloadUrl('bucket1', 'a.txt');

It produces URLs like

https://127.0.0.1/bucket1/a.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=aaaa%2F20240710%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240710T053620Z&X-Amz-Expires=3600&X-Amz-Signature=623b5d21aa2698af14d046d40008a72ef4ba3dfed9bb90d412e6dba4a6ec8706&X-Amz-SignedHeaders=host

This URL can be used anywhere - send a GET request and it will give you the file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are talking at cross purposes! I agree with what you said above but it wasn't my question.

My specific query is this:

In this line we set v4Auth to something

v4Auth = fmt.Sprintf("%s Credential=%s, SignedHeaders=%s, Signature=%s", queryf.Get(amzAlgorithm), queryf.Get(amzCredential), queryf.Get(amzSignedHeaders), queryf.Get(amzSignature))

This can never be ""

And in the line after we check it against "" which can never be true surely?

if v4Auth == "" {

Which is indicative of some kind of logic error.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh sorry, it's my fault, I'm going to correct it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for correction. I've corrected this logical error, pls have a look at the new force-pushed code.

signature/signature-v4.go Outdated Show resolved Hide resolved
signature/signature-v4.go Outdated Show resolved Hide resolved
@KevinWang15
Copy link

Code has been updated, LGTM
@ncw PTAL again, thanks

- Add query-based authentication alongside header-based
- Support "UNSIGNED-PAYLOAD"
- Add fallback options for date header extraction
- Fix ordering of query keys by using req.URL.Query().Encode() instead of req.URL.RawQuery
Copy link
Member

@ncw ncw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great now - thank you :-)

I'll just wait for the CI to go green then I'll merge.

Do you want to propose a PR for rclone to update the go.mod to fix the corresponding rclone issue?

@itsHenry35
Copy link
Author

This is looking great now - thank you :-)

I'll just wait for the CI to go green then I'll merge.

Do you want to propose a PR for rclone to update the go.mod to fix the corresponding rclone issue?

Yeah, of course. I will propose the PR after the merge. Thx ^:^

@ncw ncw merged commit d61b9c9 into rclone:master Jul 10, 2024
8 checks passed
@ncw
Copy link
Member

ncw commented Jul 10, 2024

Thank you - great job :-)

@itsHenry35
Copy link
Author

itsHenry35 commented Jul 10, 2024

This is looking great now - thank you :-)

I'll just wait for the CI to go green then I'll merge.

Do you want to propose a PR for rclone to update the go.mod to fix the corresponding rclone issue?

@ncw I've submitted the PR. Feel free to review it. Thanks! rclone/rclone#7944

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

signature error with cyberduck serve s3: Allow Presigned Requests for Serving S3
3 participants