Skip to content

Commit 2515eae

Browse files
authored
fix: allow non-HTTPS URLs in presigning (#862)
1 parent 62977c9 commit 2515eae

File tree

4 files changed

+110
-2
lines changed

4 files changed

+110
-2
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "aeef9722-fc30-4771-80f3-abcca702b45f",
3+
"type": "bugfix",
4+
"description": "Allow non-HTTPS URLs in presigning",
5+
"issues": [
6+
"awslabs/aws-sdk-kotlin#938"
7+
]
8+
}

runtime/auth/aws-signing-common/build.gradle.kts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ kotlin {
2323
}
2424
}
2525

26+
commonTest {
27+
dependencies {
28+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
29+
}
30+
}
31+
2632
all {
2733
languageSettings.optIn("aws.smithy.kotlin.runtime.InternalApi")
2834
}

runtime/auth/aws-signing-common/common/src/aws/smithy/kotlin/runtime/auth/awssigning/Presigner.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import aws.smithy.kotlin.runtime.http.operation.ResolveEndpointRequest
1313
import aws.smithy.kotlin.runtime.http.request.HttpRequest
1414
import aws.smithy.kotlin.runtime.http.request.HttpRequestBuilder
1515
import aws.smithy.kotlin.runtime.http.request.header
16-
import aws.smithy.kotlin.runtime.net.Scheme
1716
import aws.smithy.kotlin.runtime.net.Url
1817
import aws.smithy.kotlin.runtime.operation.ExecutionContext
1918

@@ -53,7 +52,7 @@ public suspend fun presignRequest(
5352
return HttpRequest(
5453
method = signedRequest.method,
5554
url = Url(
56-
scheme = Scheme.HTTPS,
55+
scheme = endpoint.uri.scheme,
5756
host = endpoint.uri.host,
5857
port = endpoint.uri.port,
5958
path = signedRequest.url.path,
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
package aws.smithy.kotlin.runtime.auth.awssigning
6+
7+
import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials
8+
import aws.smithy.kotlin.runtime.auth.awscredentials.CredentialsProvider
9+
import aws.smithy.kotlin.runtime.client.endpoints.Endpoint
10+
import aws.smithy.kotlin.runtime.http.Headers
11+
import aws.smithy.kotlin.runtime.http.operation.EndpointResolver
12+
import aws.smithy.kotlin.runtime.http.operation.ResolveEndpointRequest
13+
import aws.smithy.kotlin.runtime.http.request.HttpRequest
14+
import aws.smithy.kotlin.runtime.http.request.HttpRequestBuilder
15+
import aws.smithy.kotlin.runtime.http.request.url
16+
import aws.smithy.kotlin.runtime.net.Url
17+
import aws.smithy.kotlin.runtime.operation.ExecutionContext
18+
import aws.smithy.kotlin.runtime.util.Attributes
19+
import kotlinx.coroutines.ExperimentalCoroutinesApi
20+
import kotlinx.coroutines.test.runTest
21+
import kotlin.test.Test
22+
import kotlin.test.assertEquals
23+
24+
private const val NON_HTTPS_URL = "http://localhost:8080/path/to/resource?foo=bar"
25+
26+
@OptIn(ExperimentalCoroutinesApi::class)
27+
class PresignerTest {
28+
// Verify that custom endpoint URL schemes aren't changed.
29+
// See https://github.com/awslabs/aws-sdk-kotlin/issues/938
30+
@Test
31+
fun testSignedUrlAllowsHttp() = testSigningUrl("http://localhost:8080/path/to/resource?foo=bar")
32+
33+
// Verify that custom endpoint URL schemes aren't changed.
34+
// See https://github.com/awslabs/aws-sdk-kotlin/issues/938
35+
@Test
36+
fun testSignedUrlAllowsHttps() = testSigningUrl("https://localhost:8088/path/to/resource?bar=foo")
37+
38+
private fun testSigningUrl(url: String) = runTest {
39+
val expectedUrl = Url.parse(url)
40+
41+
val unsignedRequestBuilder = HttpRequestBuilder()
42+
val ctx = ExecutionContext()
43+
val credentialsProvider = TestCredentialsProvider(Credentials("foo", "bar"))
44+
val endpointResolver = TestEndpointResolver(Endpoint(expectedUrl))
45+
val signer = TestSigner(HttpRequest { url(expectedUrl) })
46+
val signingConfig: AwsSigningConfig.Builder.() -> Unit = {
47+
service = "launch-service"
48+
region = "the-moon"
49+
}
50+
51+
val presignedRequest = presignRequest(
52+
unsignedRequestBuilder,
53+
ctx,
54+
credentialsProvider,
55+
endpointResolver,
56+
signer,
57+
signingConfig,
58+
)
59+
60+
val actualUrl = presignedRequest.url
61+
62+
assertEquals(expectedUrl.scheme, actualUrl.scheme)
63+
assertEquals(expectedUrl.host, actualUrl.host)
64+
assertEquals(expectedUrl.port, actualUrl.port)
65+
assertEquals(expectedUrl.path, actualUrl.path)
66+
expectedUrl.parameters.forEach { key, value ->
67+
assertEquals(value, actualUrl.parameters.getAll(key))
68+
}
69+
}
70+
}
71+
72+
private class TestCredentialsProvider(private val credentials: Credentials) : CredentialsProvider {
73+
override suspend fun resolve(attributes: Attributes): Credentials = credentials
74+
}
75+
76+
private class TestEndpointResolver(private val resolvedEndpoint: Endpoint) : EndpointResolver {
77+
override suspend fun resolve(request: ResolveEndpointRequest): Endpoint = resolvedEndpoint
78+
}
79+
80+
private class TestSigner(private val signedOutput: HttpRequest) : AwsSigner {
81+
override suspend fun sign(request: HttpRequest, config: AwsSigningConfig): AwsSigningResult<HttpRequest> =
82+
AwsSigningResult(signedOutput, byteArrayOf())
83+
84+
override suspend fun signChunk(
85+
chunkBody: ByteArray,
86+
prevSignature: ByteArray,
87+
config: AwsSigningConfig,
88+
): AwsSigningResult<Unit> = error("Method should not be called")
89+
90+
override suspend fun signChunkTrailer(
91+
trailingHeaders: Headers,
92+
prevSignature: ByteArray,
93+
config: AwsSigningConfig,
94+
): AwsSigningResult<Unit> = error("Method should not be called")
95+
}

0 commit comments

Comments
 (0)