Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class SigV4AsymmetricTraitCustomization : KotlinIntegration {
override val order: Byte = -60

// services which support SigV4A but don't model it
private val unmodeledSigV4aServices = listOf("s3", "eventbridge")
private val unmodeledSigV4aServices = listOf("s3", "eventbridge", "sesv2")

override fun enabledForService(model: Model, settings: KotlinSettings): Boolean =
unmodeledSigV4aServices.contains(settings.sdkId.lowercase()) && !model.isTraitApplied(SigV4ATrait::class.java)
Expand Down
6 changes: 6 additions & 0 deletions services/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ subprojects {
}
}

if (project.name == "sesv2") {
dependencies {
implementation(libs.smithy.kotlin.aws.signing.crt) // needed for E2E test of SigV4a
}
}

// Run the tests with the classpath containing the compile dependencies (including 'main'),
// runtime dependencies, and the outputs of this compilation:
classpath = compileDependencyFiles + runtimeDependencyFiles + output.allOutputs
Expand Down
64 changes: 64 additions & 0 deletions services/sesv2/e2eTest/src/Sigv4aTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import aws.sdk.kotlin.services.sesv2.SesV2Client
import aws.sdk.kotlin.services.sesv2.sendEmail
import aws.smithy.kotlin.runtime.auth.awssigning.crt.CrtAwsSigner
import aws.smithy.kotlin.runtime.client.ProtocolRequestInterceptorContext
import aws.smithy.kotlin.runtime.http.HttpException
import aws.smithy.kotlin.runtime.http.auth.SigV4AsymmetricAuthScheme
import aws.smithy.kotlin.runtime.http.interceptors.HttpInterceptor
import aws.smithy.kotlin.runtime.http.request.HttpRequest
import kotlinx.coroutines.runBlocking
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertContains
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertNotNull

class Sigv4aTest {
@Test
@Ignore // TODO enable once SESv2 model adds endpointId and Sigv4a

Copy link
Member

Choose a reason for hiding this comment

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

nit: remove blank line

fun testSigv4a() = runBlocking {
val interceptor = RequestCapturingInterceptor()

SesV2Client.fromEnvironment {
retryStrategy {
maxAttempts = 1 // The call is intended to fail, no sense trying more than once
}

interceptors += interceptor

authSchemes = listOf(SigV4AsymmetricAuthScheme(CrtAwsSigner, "ses"))
}.use { ses ->
assertFailsWith<HttpException> {
ses.sendEmail {
// endpointId = "bdm3x3zl.n5x" // TODO uncomment
Copy link
Member

Choose a reason for hiding this comment

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

Will this TODO be completed in this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, we'll need to follow up. There's no public issue to track for doing so.

}
}
}

assertEquals(1, interceptor.requests.size)
val request = interceptor.requests.single()

assertContains("bdm3x3zl.n5x.endpoints.email.amazonaws.com", request.url.host.toString()) // Correct endpoint?
Copy link
Member

Choose a reason for hiding this comment

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

Is it the correct endpoint?

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, it is. The comment is probably misleading now, I'll update it.


val authHeader = assertNotNull(
request.headers["Authorization"],
"Missing Authorization header, found: ${request.headers.entries().map { it.key }}",
)
assertContains(authHeader, "AWS4-ECDSA-P256-SHA256") // Verify that request was signed with Sigv4a
}
}

private class RequestCapturingInterceptor : HttpInterceptor {
val requests = mutableListOf<HttpRequest>()

override fun readBeforeTransmit(context: ProtocolRequestInterceptorContext<Any, HttpRequest>) {
requests += context.protocolRequest
}
}
4 changes: 4 additions & 0 deletions services/sesv2/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"sdkId": "SESv2",
"enableEndpointAuthProvider": true
}
Loading