Skip to content

Implement Presigned Post URLs #3902

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

Merged
merged 32 commits into from
Jul 18, 2025
Merged

Conversation

GarrettBeatty
Copy link
Contributor

@GarrettBeatty GarrettBeatty commented Jul 2, 2025

Description

  1. Implement Presigned POST URL functionality

Motivation and Context

  1. Implement AmazonS3Client is missing Create Presigned Post #1901 & DOTNET-8098.
  2. https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-UsingHTTPPOST.html

Testing

  1. I created a test project in javascript and .net and compared the responses and validated they are the same. You can follow https://github.com/aws/aws-sdk-net/blob/gcbeatty/presigntesting/README_S3_TEST.md if you want to test yourself.
  2. Wrote unit tests and integration tests
  3. Dryrun - 5cec01d1-6a76-49e5-8699-39803aa29592

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My code follows the code style of this project
  • My change requires a change to the documentation
  • I have updated the documentation accordingly
  • I have read the README document
  • I have added tests to cover my changes
  • All new and existing tests passed

License

  • I confirm that this pull request can be released under the Apache 2 license

@GarrettBeatty GarrettBeatty changed the title presigned post Implement Presigned Post URLs Jul 2, 2025
@GarrettBeatty GarrettBeatty force-pushed the gcbeatty/presignedpostbcl branch from 6c58f61 to dd78028 Compare July 8, 2025 02:34
@GarrettBeatty GarrettBeatty force-pushed the gcbeatty/presignedpostimpl branch from 2625b99 to 8a43d25 Compare July 8, 2025 20:30
Base automatically changed from gcbeatty/presignedpostbcl to development July 8, 2025 23:29
@GarrettBeatty GarrettBeatty force-pushed the gcbeatty/presignedpostimpl branch from 0dcb789 to 509c246 Compare July 8, 2025 23:31
@GarrettBeatty GarrettBeatty force-pushed the gcbeatty/presignedpostimpl branch from 7a5fda0 to 2ee4790 Compare July 9, 2025 15:28

// Add the AWS signature fields
response.Fields[S3Constants.PostFormDataObjectKey] = request.Key ?? "";
response.Fields[S3Constants.PostFormDataPolicy] = signedPolicy.Policy;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

please note that S3Constants.PostFormDataPolicy] is Policy with a capital P. All of the other fields are lowercase but i was wanting to re-use this existing field. It doesnt matter if its lowercase or uppercase when sending to s3 though

@GarrettBeatty GarrettBeatty marked this pull request as ready for review July 9, 2025 21:02
@GarrettBeatty GarrettBeatty requested review from normj and boblodgett July 9, 2025 21:02
@@ -51,6 +51,7 @@
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Web" />
<Reference Include="System.Net.Http"/>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ive been trying to figure out why i need System.Net.Http here if i already have it defined in the S3 integration tests. if anyone knows let me know. without this added here i get


C:\codebuild\tmp\output\src17698009\src\aws-sdk-net\sdk\test\Services\S3\IntegrationTests\CreatePresignedPostTests.cs(303,35): error CS1069: The type name 'ByteArrayContent' could not be found in the namespace 'System.Net.Http'. This type has been forwarded to assembly 'System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' Consider adding a reference to that assembly. [C:\codebuild\tmp\output\src17698009\src\aws-sdk-net\sdk\test\IntegrationTests\AWSSDK.IntegrationTests.NetFramework.csproj]

@@ -0,0 +1,18 @@
{
"core": {
"updateMinimum": true,
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you need the Core section here if the only service being changed is S3? Also, would it make sense to make this a Minor change for S3 since it's a new feature?

Copy link
Contributor Author

@GarrettBeatty GarrettBeatty Jul 10, 2025

Choose a reason for hiding this comment

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

im updating code in the generator folder which is why i added core. but i guess you are saying generator is not part of core in this case

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i can update to minor

Copy link
Contributor

Choose a reason for hiding this comment

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

It's not, we normally include Core only if the generator change would impact all (or multiple) services. But in this case your change is S3 only.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed in 20bb0e5

@GarrettBeatty GarrettBeatty requested review from muhammad-othman and removed request for boblodgett July 13, 2025 01:18
/// </summary>
public CreatePresignedPostRequest()
{
Expires = AWSSDKUtils.CorrectedUtcNow.AddHours(1);
Copy link
Member

Choose a reason for hiding this comment

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

Why are we defaulting to an hour? Seems like this should be null requiring users to decide what the expiration should be and give it to us.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Okay then make sure the documentation for the Expires property says this defaults to an hour from when the CreatePresignedPostRequest instance was created.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated comment in bcd54bc

@GarrettBeatty GarrettBeatty requested a review from Copilot July 15, 2025 14:21
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements S3 presigned POST URL functionality for the AWS SDK for .NET, enabling browser-based file uploads directly to S3 without requiring server-side processing. The implementation includes comprehensive support for policy conditions, form fields, and AWS signature authentication.

  • Adds complete presigned POST URL support with three condition types: exact match, starts-with, and content-length-range
  • Implements proper AWS signature v4 authentication with policy document generation and validation
  • Provides both synchronous and asynchronous APIs with comprehensive error handling and input validation

Reviewed Changes

Copilot reviewed 15 out of 16 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
S3PostCondition.cs New model classes for policy conditions with factory methods and JSON serialization
CreatePresignedPostRequest.cs Request model with bucket name, key, expiration, fields, and conditions
CreatePresignedPostResponse.cs Response model containing URL and form fields for POST requests
AmazonS3Client.Extensions.cs Core implementation with policy generation, signing, and endpoint resolution
EndpointResolver.tt Template update to handle CreatePresignedPostRequest in endpoint resolution
Various test files Comprehensive unit and integration tests covering all functionality

@GarrettBeatty GarrettBeatty requested a review from normj July 15, 2025 21:27
throw new AmazonS3Exception("Credentials must be specified, cannot call method anonymously");

// Resolve credentials asynchronously
var immutableCredentials = await credentials.GetCredentialsAsync().ConfigureAwait(false);
Copy link
Member

Choose a reason for hiding this comment

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

Why are we resolving this credential if we aren't using it later?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

let me double check this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i updated in 22687c7 to use the resolved credentials. good catch

{
ValidateCreatePresignedPostRequest(request);

var credentials = Config.DefaultAWSCredentials ?? DefaultIdentityResolverConfiguration.ResolveDefaultIdentity<AWSCredentials>();
Copy link
Member

Choose a reason for hiding this comment

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

Same S3Express credentials comment.

@GarrettBeatty
Copy link
Contributor Author

doing one final dry run before merging fe2e67f3-2b95-44c6-9d6f-0b1a64e760d7

@GarrettBeatty GarrettBeatty merged commit bb84f7c into development Jul 18, 2025
3 checks passed
@GarrettBeatty GarrettBeatty deleted the gcbeatty/presignedpostimpl branch July 18, 2025 15:50
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.

4 participants