Skip to content

Commit db64cc6

Browse files
authored
fix: properly encode URI paths that contain non-standard characters (#658)
1 parent 4df6b07 commit db64cc6

File tree

26 files changed

+149
-26
lines changed

26 files changed

+149
-26
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "cc2cb6a3-fc49-4c83-9ca8-448e2f8131d6",
3+
"type": "bugfix",
4+
"description": "Fix bug in URI encoding during signing when dealing with special characters like '<', '>', and '/'",
5+
"issues": [
6+
"awslabs/smithy-kotlin#657"
7+
]
8+
}

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

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@ import aws.smithy.kotlin.runtime.http.UrlBuilder
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.toBuilder
16+
import aws.smithy.kotlin.runtime.http.util.encodeLabel
1617
import aws.smithy.kotlin.runtime.io.SdkByteReadChannel
1718
import aws.smithy.kotlin.runtime.time.TimestampFormat
1819
import aws.smithy.kotlin.runtime.util.*
19-
import aws.smithy.kotlin.runtime.util.text.encodeUrlPath
20-
import aws.smithy.kotlin.runtime.util.text.normalizePathSegments
21-
import aws.smithy.kotlin.runtime.util.text.urlEncodeComponent
22-
import aws.smithy.kotlin.runtime.util.text.urlReencodeComponent
20+
import aws.smithy.kotlin.runtime.util.text.*
2321

2422
/**
2523
* The data for a canonical request.
@@ -171,11 +169,10 @@ private const val STREAM_CHUNK_BYTES = 16384 // 16KB
171169
* @param config The signing configuration to use
172170
* @return The canonicalized path
173171
*/
174-
private fun UrlBuilder.canonicalPath(config: AwsSigningConfig): String {
175-
val raw = path.trim()
176-
val normalized = if (config.normalizeUriPath) raw.normalizePathSegments() else raw
177-
val preEncoded = normalized.encodeUrlPath()
178-
return if (config.useDoubleUriEncode) preEncoded.encodeUrlPath() else preEncoded
172+
internal fun UrlBuilder.canonicalPath(config: AwsSigningConfig): String {
173+
val segmentTransform = if (config.useDoubleUriEncode) { s: String -> s.encodeLabel() } else null
174+
val pathTransform = if (config.normalizeUriPath) String::normalizePathSegments else String::transformPathSegments
175+
return pathTransform(path.trim(), segmentTransform)
179176
}
180177

181178
/**

runtime/auth/aws-signing-default/common/test/aws/smithy/kotlin/runtime/auth/awssigning/DefaultCanonicalizerTest.kt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ package aws.smithy.kotlin.runtime.auth.awssigning
66

77
import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials
88
import aws.smithy.kotlin.runtime.auth.awssigning.tests.testCredentialsProvider
9-
import aws.smithy.kotlin.runtime.http.Headers
10-
import aws.smithy.kotlin.runtime.http.HttpBody
11-
import aws.smithy.kotlin.runtime.http.HttpMethod
12-
import aws.smithy.kotlin.runtime.http.parameters
9+
import aws.smithy.kotlin.runtime.http.*
1310
import aws.smithy.kotlin.runtime.http.request.*
1411
import aws.smithy.kotlin.runtime.time.Instant
1512
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -80,4 +77,21 @@ class DefaultCanonicalizerTest {
8077
}.entries()
8178
assertEquals(expectedHeaders, actual.request.headers.entries())
8279
}
80+
81+
// Targeted test for proper URI path escaping. See https://github.com/awslabs/smithy-kotlin/issues/657
82+
@Test
83+
fun testEscapablePath() {
84+
val uri = UrlBuilder()
85+
uri.path = "/2013-04-01/healthcheck/foo%3Cbar%3Ebaz%3C%2Fbar%3E"
86+
87+
val config = AwsSigningConfig {
88+
normalizeUriPath = true
89+
useDoubleUriEncode = true
90+
region = "the-moon"
91+
service = "landing-pad"
92+
credentialsProvider = testCredentialsProvider
93+
}
94+
95+
assertEquals("/2013-04-01/healthcheck/foo%253Cbar%253Ebaz%253C%252Fbar%253E", uri.canonicalPath(config))
96+
}
8397
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"credentials": {
3+
"access_key_id": "AKIDEXAMPLE",
4+
"secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"
5+
},
6+
"expiration_in_seconds": 3600,
7+
"normalize": true,
8+
"region": "us-east-1",
9+
"service": "service",
10+
"sign_body": false,
11+
"timestamp": "2015-08-30T12:36:00Z"
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
GET
2+
/foo/bar/baz%253Cqux%253Aquux
3+
4+
host:example.amazonaws.com
5+
x-amz-date:20150830T123600Z
6+
7+
host;x-amz-date
8+
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
64ee2b4fb5e80890c58f8ccc1221231f3e3a556ba0f9c485d32bb2742a74e8ac
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
GET /foo/bar/baz%3Cqux%3Aquux HTTP/1.1
2+
Host:example.amazonaws.com
3+
X-Amz-Date:20150830T123600Z
4+
Authorization:AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=64ee2b4fb5e80890c58f8ccc1221231f3e3a556ba0f9c485d32bb2742a74e8ac
5+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
AWS4-HMAC-SHA256
2+
20150830T123600Z
3+
20150830/us-east-1/service/aws4_request
4+
4eb677b0ad9b3c4265bdb9eb11e09772e7ba1a11ef323d6f89800e59186ae790
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
GET
2+
/foo/bar/baz%253Cqux%253Aquux
3+
X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fus-east-1%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host
4+
host:example.amazonaws.com
5+
6+
host
7+
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
d1f120edc32fec5ee3797a82306977229dca6d3614e3c530897b87db9442533c

0 commit comments

Comments
 (0)