Skip to content

Commit 7db715a

Browse files
authored
fix(codegen): disable signing for sts operations AssumeRoleWithSaml and AssumeRoleWithWebIdentity (#407)
1 parent 3dcef25 commit 7db715a

File tree

4 files changed

+134
-1
lines changed

4 files changed

+134
-1
lines changed

.github/scripts/mk-generated.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ set -e
1414

1515
# Redirect stdout to stderr for all the code in `{ .. }`
1616
{
17-
git diff --quiet || (echo 'working tree not clean, aborting' && exit 1)
1817
gh_branch=${GITHUB_HEAD_REF##*/}
1918
base_branch=${GITHUB_BASE_REF##*/}
2019
if [ -n "$base_branch" ]; then
@@ -28,6 +27,15 @@ set -e
2827
gen_branch="__generated-$current_branch"
2928
repo_root=$(git rev-parse --show-toplevel)
3029
cd "$repo_root" && ./gradlew :codegen:sdk:bootstrap
30+
# repo may be dirty due to gradle.properties being manipulated to have upstream deps match (e.g. by set_upstream_versions.py)
31+
# test that we are running in a GitHub workflow before blowing away any unsaved changes
32+
if [[ -z "${GITHUB_WORKFLOW}" ]]; then
33+
git diff --quiet || (echo 'working tree not clean, aborting' && exit 1)
34+
else
35+
echo "working tree dirty, violently resetting HEAD"
36+
git reset HEAD --hard
37+
fi
38+
3139
target="$(mktemp -d)"
3240
mv "$repo_root"/services "$target"
3341
# checkout and reset $gen_branch to be based on the __generated__ history
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
6+
package aws.sdk.kotlin.codegen.customization.sts
7+
8+
import aws.sdk.kotlin.codegen.sdkId
9+
import software.amazon.smithy.kotlin.codegen.KotlinSettings
10+
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
11+
import software.amazon.smithy.kotlin.codegen.model.expectShape
12+
import software.amazon.smithy.model.Model
13+
import software.amazon.smithy.model.shapes.OperationShape
14+
import software.amazon.smithy.model.shapes.ServiceShape
15+
import software.amazon.smithy.model.shapes.ShapeId
16+
import software.amazon.smithy.model.traits.AuthTrait
17+
import software.amazon.smithy.model.transform.ModelTransformer
18+
19+
/**
20+
* STS needs to have the auth trait manually set to []
21+
*
22+
* See https://github.com/awslabs/aws-sdk-kotlin/issues/280
23+
*/
24+
class StsDisableAuthForOperations : KotlinIntegration {
25+
26+
private val optionalAuthOperations = setOf(
27+
ShapeId.from("com.amazonaws.sts#AssumeRoleWithSAML"),
28+
ShapeId.from("com.amazonaws.sts#AssumeRoleWithWebIdentity")
29+
)
30+
31+
override fun enabledForService(model: Model, settings: KotlinSettings): Boolean =
32+
model.expectShape<ServiceShape>(settings.service).sdkId == "STS"
33+
34+
override fun preprocessModel(model: Model, settings: KotlinSettings): Model =
35+
ModelTransformer.create()
36+
.mapShapes(model) {
37+
if (optionalAuthOperations.contains(it.id) && it is OperationShape) {
38+
it.toBuilder().addTrait(AuthTrait(emptySet())).build()
39+
} else {
40+
it
41+
}
42+
}
43+
}

codegen/smithy-aws-kotlin-codegen/src/main/resources/META-INF/services/software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ aws.sdk.kotlin.codegen.customization.polly.PollyPresigner
1616
aws.sdk.kotlin.codegen.customization.BoxServices
1717
aws.sdk.kotlin.codegen.customization.glacier.GlacierBodyChecksum
1818
aws.sdk.kotlin.codegen.customization.machinelearning.MachineLearningEndpointCustomization
19+
aws.sdk.kotlin.codegen.customization.sts.StsDisableAuthForOperations
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
6+
package aws.sdk.kotlin.services.sts
7+
8+
import aws.sdk.kotlin.runtime.auth.credentials.Credentials
9+
import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
10+
import aws.smithy.kotlin.runtime.http.Headers
11+
import aws.smithy.kotlin.runtime.http.HttpBody
12+
import aws.smithy.kotlin.runtime.http.HttpStatusCode
13+
import aws.smithy.kotlin.runtime.http.engine.HttpClientEngineBase
14+
import aws.smithy.kotlin.runtime.http.engine.callContext
15+
import aws.smithy.kotlin.runtime.http.request.HttpRequest
16+
import aws.smithy.kotlin.runtime.http.response.HttpCall
17+
import aws.smithy.kotlin.runtime.http.response.HttpResponse
18+
import aws.smithy.kotlin.runtime.testing.runSuspendTest
19+
import aws.smithy.kotlin.runtime.time.Instant
20+
import kotlin.test.Test
21+
import kotlin.test.assertFalse
22+
import kotlin.test.assertNotNull
23+
import kotlin.test.assertTrue
24+
25+
/**
26+
* Tests related to STS model and whether requests need to be signed or not
27+
*/
28+
class StsAuthTests {
29+
30+
private val mockEngine = object : HttpClientEngineBase("mock-engine") {
31+
var capturedRequest: HttpRequest? = null
32+
33+
override suspend fun roundTrip(request: HttpRequest): HttpCall {
34+
capturedRequest = request
35+
val callContext = callContext()
36+
val now = Instant.now()
37+
return HttpCall(request, HttpResponse(HttpStatusCode.OK, Headers.Empty, HttpBody.Empty), now, now, callContext)
38+
}
39+
}
40+
41+
private val credentials = Credentials("ANOTREAL", "notrealrnrELgWzOk3IFjzDKtFBhDby", "notarealsessiontoken")
42+
43+
@Test
44+
fun testAssumeRoleIsSigned(): Unit = runSuspendTest {
45+
val client = StsClient {
46+
region = "us-east-2"
47+
credentialsProvider = StaticCredentialsProvider(credentials)
48+
httpClientEngine = mockEngine
49+
}
50+
51+
runCatching { client.assumeRole { } }
52+
val request = assertNotNull(mockEngine.capturedRequest)
53+
assertTrue(request.headers.contains("AUTHORIZATION"))
54+
}
55+
56+
@Test
57+
fun testWebIdentityIsUnsigned(): Unit = runSuspendTest {
58+
val client = StsClient {
59+
region = "us-east-2"
60+
credentialsProvider = StaticCredentialsProvider(credentials)
61+
httpClientEngine = mockEngine
62+
}
63+
64+
runCatching { client.assumeRoleWithWebIdentity { } }
65+
val request = assertNotNull(mockEngine.capturedRequest)
66+
assertFalse(request.headers.contains("AUTHORIZATION"), "assumeRoleWithWebIdentity should not require a signed request")
67+
}
68+
69+
@Test
70+
fun testAssumeRoleSamlIsUnsigned(): Unit = runSuspendTest {
71+
val client = StsClient {
72+
region = "us-east-2"
73+
credentialsProvider = StaticCredentialsProvider(credentials)
74+
httpClientEngine = mockEngine
75+
}
76+
77+
runCatching { client.assumeRoleWithSaml { } }
78+
val request = assertNotNull(mockEngine.capturedRequest)
79+
assertFalse(request.headers.contains("AUTHORIZATION"), "assumeRoleWithSaml should not require a signed request")
80+
}
81+
}

0 commit comments

Comments
 (0)