Created
July 14, 2019 01:26
-
-
Save jleskovar-tyro/620e18d05c69ee9568ece8609c21be66 to your computer and use it in GitHub Desktop.
Kotlin and AWS SDK v2 port of aws-request-signing-apache-interceptor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* An [HttpRequestInterceptor] that signs requests using any AWS [Aws4Signer] and [AwsCredentialsProvider]. | |
* | |
* NOTE: Ported to kotlin and v2 SDK from https://github.com/awslabs/aws-request-signing-apache-interceptor/ | |
*/ | |
class AwsRequestSigningInterceptor( | |
private val region: Region, | |
private val service: String, | |
private val signer: Aws4Signer, | |
private val awsCredentialsProvider: AwsCredentialsProvider | |
) : HttpRequestInterceptor { | |
override fun process(request: HttpRequest, context: HttpContext) { | |
val uriBuilder = URIBuilder(request.requestLine.uri) | |
// Copy Apache HttpRequest to an SDK request | |
val sdkRequest = createSignableRequest(context, request, uriBuilder) | |
// Sign it | |
val credentials = awsCredentialsProvider.resolveCredentials() | |
val signerParams = Aws4SignerParams.builder() | |
.signingRegion(region) | |
.signingName(service) | |
.awsCredentials(credentials) | |
.doubleUrlEncode(true) | |
.build() | |
val response = signer.sign(sdkRequest, signerParams) | |
// Now copy everything back | |
request.setHeaders(mapToHeaderList(response.headers()).toTypedArray()) | |
if (request is HttpEntityEnclosingRequest) { | |
if (request.entity != null) { | |
val basicHttpEntity = BasicHttpEntity() | |
basicHttpEntity.content = response.contentStreamProvider().get().newStream() | |
request.entity = basicHttpEntity | |
} | |
} | |
} | |
private fun createSignableRequest(context: HttpContext, request: HttpRequest, uriBuilder: URIBuilder): SdkHttpFullRequest { | |
val sdkHttpFullRequest = SdkHttpFullRequest.builder() | |
(context.getAttribute(HTTP_TARGET_HOST) as? HttpHost)?.let { | |
sdkHttpFullRequest.uri(URI.create(it.toURI())) | |
} | |
val httpMethod = HttpMethodName.fromValue(request.requestLine.method) | |
sdkHttpFullRequest.method(SdkHttpMethod.fromValue(httpMethod.name)) | |
sdkHttpFullRequest.encodedPath(uriBuilder.build().rawPath) | |
sdkHttpFullRequest.contentStreamProvider { ByteArrayInputStream(ByteArray(0)) } | |
(request as? HttpEntityEnclosingRequest)?.let { | |
it.entity?.content?.let { sdkHttpFullRequest.contentStreamProvider { it } } | |
} | |
uriBuilder.queryParams.forEach { sdkHttpFullRequest.appendRawQueryParameter(it.name, it.value) } | |
request.allHeaders.filter { !skipHeader(it) }.forEach { sdkHttpFullRequest.appendHeader(it.name, it.value) } | |
return sdkHttpFullRequest.build() | |
} | |
private fun mapToHeaderList(mapHeaders: MutableMap<String, MutableList<String>>): List<Header?> = | |
mapHeaders.map { BasicHeader(it.key, it.value.joinToString(",")) } | |
private fun skipHeader(header: Header): Boolean = | |
(("content-length".equals(header.name, ignoreCase = true) && "0" == header.value) // Strip Content-Length: 0 | |
|| "host".equals(header.name, ignoreCase = true)) // Host comes from endpoint | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Also found that issue, it can be removed