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: add toggle to SigV4AuthScheme to turn off body signing #1822

Merged
merged 9 commits into from
Nov 18, 2024

Conversation

dayaffe
Copy link
Contributor

@dayaffe dayaffe commented Nov 14, 2024

Issue #

SWIFT-1849, PR: smithy-lang/smithy-swift#857

Description of changes

  • Add signing property requestUnsignedBody. Note this wont effect middlewares or anything else on purpose until we go to actually sign
  • In AWSSigV4Signer before we go to sign, check for requestUnsignedBody and if its true, overrule isUnsignedBody, setting header x-amz-content-sha256 to UNSIGNED-PAYLOAD

Usage

let config = try await S3Client.S3ClientConfiguration(
    authSchemes: [SigV4AuthScheme(requestUnsignedBody: true)]
)
let client = S3Client(config: config)

New/existing dependencies impact assessment, if applicable

Conventional Commits

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Copy link
Contributor

@sichanyoo sichanyoo left a comment

Choose a reason for hiding this comment

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

Comments re: test

s3Config.authSchemes = [SigV4AuthScheme(requestUnsignedBody: true)]
}

func testS3PresignedRequest() async throws {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: FIx test name

@@ -0,0 +1,45 @@
//
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add:

  • One more test case that has payload over the chunked threshold
  • An interceptor that asserts that:
    • Authorization header isn't present as expected
    • x-amz-content-sha256 header values match expected values (UNSIGNED-PAYLOAD for single chunk request, and STREAMING-UNSIGNED-PAYLOAD-TRAILER for aws chunked request)

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 believe Authorization header is still expected to be there. We are still signing the request just not the body. Will do the rest

Copy link
Contributor

Choose a reason for hiding this comment

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

That's true, and gotcha

@dayaffe dayaffe requested a review from sichanyoo November 15, 2024 20:51
Copy link
Contributor

@sichanyoo sichanyoo left a comment

Choose a reason for hiding this comment

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

nit: Change integration test file name and test cases to mean unsigned payload, not unsigned request


func testS3ToggleUnsignedRequestStreaming() async throws {
let key = "test-streaming.txt"
let data = Data((0..<(1024 * 1024)).map { _ in UInt8.random(in: UInt8.min...UInt8.max) })
Copy link
Contributor

Choose a reason for hiding this comment

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

We also create a data of specified length filled with randomness in S3ConcurrentTests, probably elsewhere like the chunked streaming tests as well.

Perhaps we should extract the logic to do that to a helper function so it may be reused?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure I can move this out

@@ -69,6 +74,11 @@ public struct SigV4AuthScheme: AuthScheme {
value: context.isChunkedEligibleStream
)

// Optionally toggle unsigned body
if self.requestUnsignedBody == true {
Copy link
Contributor

Choose a reason for hiding this comment

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

assume the explicit == true is because self.requestUnsignedBody may be nil as well as false?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes

.withUnsignedPayloadTrait(value: false)
.build()
let updatedProperties = try customSigV4AuthScheme.customizeSigningProperties(signingProperties: Attributes(), context: context)
XCTAssertTrue(try XCTUnwrap(updatedProperties.get(key: SigningPropertyKeys.requestUnsignedBody)))
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe break the XCTUnwrap & XCAssert into two lines for clarity

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Was following other tests format -- if we think its more clear to separate we should go through and change all the tests effected though I personally dont have any issue with this style

@@ -15,9 +15,14 @@ import struct Smithy.Attributes
public struct SigV4AuthScheme: AuthScheme {
public let schemeID: String = "aws.auth#sigv4"
public let signer: Signer = AWSSigV4Signer()
public var requestUnsignedBody: Bool?
Copy link
Contributor

Choose a reason for hiding this comment

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

The possible values for Bool? are true, false, and nil.

true means unsigned body is requested.
nil means unsigned body was not specified in the auth scheme resolver.

So what is false? I can certainly create a auth scheme resolver with requestUnsignedBody: false. Would that ever be used? Is it undefined? (If it doesn't, we should consider a different data type than Bool? for this setting.)

@@ -18,38 +18,27 @@ final class S3ConcurrentTests: S3XCTestCase {
// Payload just below chunked threshold
// Tests concurrent upload of simple data payloads
func test_10x_1MB_getObject() async throws {
fileData = try generateDummyTextData(count: CHUNKED_THRESHOLD - 1)
fileData = S3ConcurrentTests.generateRandomTextData(ofSizeInMB: 1)
Copy link
Contributor

Choose a reason for hiding this comment

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

There is a folder IntegrationTests/AWSIntegrationTestUtils where I think this method belongs

try await repeatConcurrentlyWithArgs(count: 10, test: getObject, args: fileData!)
}

// Payload 256 bytes with 200 concurrent requests, sends as simple data
// Tests very high concurrency with small data payloads
func test_200x_256B_getObject() async throws {
fileData = try generateDummyTextData(count: 256)
let bytes_256 = Double(256) / (1024 * 1024)
Copy link
Contributor

Choose a reason for hiding this comment

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

Any Swift literal with a decimal point is a Double. So you can just use 256.0 or 256. instead of the Double initializer.

@@ -116,4 +116,12 @@ class S3XCTestCase: XCTestCase {
let input = DeleteBucketInput(bucket: bucketName)
_ = try await client.deleteBucket(input: input)
}

static func generateRandomTextData(ofSizeInMB megabytes: Double) -> Data {
Copy link
Contributor

Choose a reason for hiding this comment

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

This method should take a precise integer number of bytes.

I'm okay with it if we have a convenience form that takes a Double number of MB then converts that to bytes.

Also, as mentioned above, let's move this to integration test utils.

@dayaffe dayaffe dismissed sichanyoo’s stale review November 18, 2024 16:24

Modified names, was a nit

@dayaffe dayaffe merged commit f5e6c7f into main Nov 18, 2024
29 checks passed
@dayaffe dayaffe deleted the day/unsigned-body-toggle branch November 18, 2024 16:24
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.

3 participants