Skip to content

Commit baaa2a0

Browse files
authored
feat(rt): STS assume role and web identity credentials providers (#36)
1 parent 2a88b7d commit baaa2a0

File tree

5 files changed

+228
-0
lines changed

5 files changed

+228
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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.crt.auth.credentials
7+
8+
import aws.sdk.kotlin.crt.io.ClientBootstrap
9+
import aws.sdk.kotlin.crt.io.TlsContext
10+
11+
/**
12+
* Provides credentials from STS by assuming a role
13+
*/
14+
public expect class StsAssumeRoleCredentialsProvider
15+
internal constructor(builder: StsAssumeRoleCredentialsProviderBuilder) : CredentialsProvider {
16+
public companion object
17+
}
18+
19+
public class StsAssumeRoleCredentialsProviderBuilder {
20+
/**
21+
* Connection bootstrap to use for any network connections made while sourcing credentials.
22+
*/
23+
public var clientBootstrap: ClientBootstrap? = null
24+
25+
/**
26+
* The tls context to use for any secure network connections made while sourcing credentials.
27+
*/
28+
public var tlsContext: TlsContext? = null
29+
30+
/**
31+
* The underlying Credentials Provider to use for source credentials.
32+
*/
33+
public var credentialsProvider: CredentialsProvider? = null
34+
35+
/**
36+
* The target role's ARN.
37+
*/
38+
public var roleArn: String? = null
39+
40+
/**
41+
* The name to associate with the session
42+
*/
43+
public var sessionName: String? = null
44+
45+
/**
46+
* The number of seconds from authentication that the session is valid for
47+
*/
48+
public var durationSeconds: Int? = null
49+
50+
public fun build(): StsAssumeRoleCredentialsProvider = StsAssumeRoleCredentialsProvider(this)
51+
}
52+
53+
/**
54+
* Construct a new credentials provider using a builder.
55+
*/
56+
public fun StsAssumeRoleCredentialsProvider.Companion.build(block: StsAssumeRoleCredentialsProviderBuilder.() -> Unit):
57+
StsAssumeRoleCredentialsProvider = StsAssumeRoleCredentialsProviderBuilder().apply(block).build()
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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.crt.auth.credentials
7+
8+
import aws.sdk.kotlin.crt.io.ClientBootstrap
9+
import aws.sdk.kotlin.crt.io.TlsContext
10+
11+
/**
12+
* Sts with web identity credentials provider sources a set of temporary security credentials for users who have been
13+
* authenticated in a mobile or web application with a web identity provider.
14+
*/
15+
public expect class StsWebIdentityCredentialsProvider
16+
internal constructor(builder: StsWebIdentityCredentialsProviderBuilder) : CredentialsProvider {
17+
public companion object
18+
}
19+
20+
public class StsWebIdentityCredentialsProviderBuilder {
21+
/**
22+
* Connection bootstrap to use for any network connections made while sourcing credentials.
23+
*/
24+
public var clientBootstrap: ClientBootstrap? = null
25+
26+
/**
27+
* The tls context to use for any secure network connections made while sourcing credentials.
28+
*/
29+
public var tlsContext: TlsContext? = null
30+
31+
public fun build(): StsWebIdentityCredentialsProvider = StsWebIdentityCredentialsProvider(this)
32+
}
33+
34+
/**
35+
* Construct a new credentials provider using a builder.
36+
*/
37+
public fun StsWebIdentityCredentialsProvider.Companion.build(block: StsWebIdentityCredentialsProviderBuilder.() -> Unit):
38+
StsWebIdentityCredentialsProvider = StsWebIdentityCredentialsProviderBuilder().apply(block).build()
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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.crt.auth.credentials
7+
8+
import kotlinx.coroutines.*
9+
import kotlinx.coroutines.CoroutineStart
10+
import kotlinx.coroutines.future.asCompletableFuture
11+
import kotlinx.coroutines.runBlocking
12+
import java.util.concurrent.CompletableFuture
13+
import software.amazon.awssdk.crt.auth.credentials.Credentials as CredentialsJni
14+
import software.amazon.awssdk.crt.auth.credentials.CredentialsProvider as CredentialsProviderJni
15+
import software.amazon.awssdk.crt.auth.credentials.StsCredentialsProvider as StsCredentialsProviderJni
16+
17+
// Based from the Java SDK default
18+
// https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sts/model/AssumeRoleRequest.html#durationSeconds
19+
private const val DEFAULT_DURATION_SECONDS = 3600
20+
21+
public actual class StsAssumeRoleCredentialsProvider
22+
internal actual constructor(builder: StsAssumeRoleCredentialsProviderBuilder) :
23+
CredentialsProvider, JniCredentialsProvider() {
24+
public actual companion object {}
25+
26+
override val jniCredentials: CredentialsProviderJni =
27+
StsCredentialsProviderJni
28+
.builder()
29+
.withClientBootstrap(builder.clientBootstrap?.jniBootstrap)
30+
.withTlsContext(builder.tlsContext?.jniCtx)
31+
.withCredsProvider(adapt(builder.credentialsProvider))
32+
.withDurationSeconds(builder.durationSeconds ?: DEFAULT_DURATION_SECONDS)
33+
.withRoleArn(builder.roleArn)
34+
.withSessionName(builder.sessionName)
35+
.build()
36+
}
37+
38+
// Convert the SDK version of CredentialsProvider type to the CRT version
39+
internal fun adapt(credentialsProvider: CredentialsProvider?): CredentialsProviderJni? {
40+
return if (credentialsProvider == null) {
41+
null
42+
} else {
43+
toCrtCredentialsProvider(credentialsProvider)
44+
}
45+
}
46+
47+
private fun toCrtCredentialsProvider(sdkCredentialsProvider: CredentialsProvider): CredentialsProviderJni {
48+
return object : CredentialsProviderJni() {
49+
50+
override fun getCredentials(): CompletableFuture<CredentialsJni> = runBlocking {
51+
val deferred = async(start = CoroutineStart.UNDISPATCHED) {
52+
toCrtCredentials(sdkCredentialsProvider.getCredentials())
53+
}
54+
55+
deferred.asCompletableFuture()
56+
}
57+
}
58+
}
59+
60+
private fun toCrtCredentials(sdkCredentials: Credentials): CredentialsJni {
61+
return object : CredentialsJni() {
62+
override fun getAccessKeyId(): ByteArray {
63+
return sdkCredentials.accessKeyId.encodeToByteArray()
64+
}
65+
66+
override fun getSecretAccessKey(): ByteArray {
67+
return sdkCredentials.secretAccessKey.encodeToByteArray()
68+
}
69+
70+
override fun getSessionToken(): ByteArray {
71+
return sdkCredentials.sessionToken?.encodeToByteArray() ?: ByteArray(0)
72+
}
73+
}
74+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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.crt.auth.credentials
7+
8+
import software.amazon.awssdk.crt.auth.credentials.CredentialsProvider as CredentialsProviderJni
9+
import software.amazon.awssdk.crt.auth.credentials.StsWebIdentityCredentialsProvider as StsWebIdentityCredentialsProviderJni
10+
11+
public actual class StsWebIdentityCredentialsProvider
12+
internal actual constructor(builder: StsWebIdentityCredentialsProviderBuilder) :
13+
CredentialsProvider, JniCredentialsProvider() {
14+
public actual companion object {}
15+
16+
override val jniCredentials: CredentialsProviderJni =
17+
StsWebIdentityCredentialsProviderJni
18+
.builder()
19+
.withClientBootstrap(builder.clientBootstrap?.jniBootstrap)
20+
.withTlsContext(builder.tlsContext?.jniCtx)
21+
.build()
22+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
package aws.sdk.kotlin.crt.auth.credentials
6+
7+
import kotlin.test.Test
8+
import kotlin.test.assertContentEquals
9+
import kotlin.test.assertNotNull
10+
11+
private val ACCESS_KEY = "ACCESS_KEY".encodeToByteArray()
12+
private val SECRET_ACCESS_KEY = "SECRET_ACCESS_KEY".encodeToByteArray()
13+
private val SESSION_TOKEN = "SESSION_TOKEN".encodeToByteArray()
14+
15+
class StsAssumeRoleCredentialsProviderJVMTest {
16+
17+
@Test
18+
fun itAdaptsSdkToCrtCredentialsProviderTypes() {
19+
val sdkCredentialsProvider = object : CredentialsProvider {
20+
override suspend fun getCredentials(): Credentials =
21+
Credentials(ACCESS_KEY, SECRET_ACCESS_KEY, SESSION_TOKEN)
22+
23+
override fun close() {}
24+
override suspend fun waitForShutdown() {}
25+
}
26+
27+
val adapted = adapt(sdkCredentialsProvider)
28+
29+
assertNotNull(adapted)
30+
31+
val adaptedCreds = adapted.credentials.get()
32+
33+
assertContentEquals(adaptedCreds.accessKeyId, ACCESS_KEY)
34+
assertContentEquals(adaptedCreds.secretAccessKey, SECRET_ACCESS_KEY)
35+
assertContentEquals(adaptedCreds.sessionToken, SESSION_TOKEN)
36+
}
37+
}

0 commit comments

Comments
 (0)