Skip to content

Commit 66e30ac

Browse files
authored
account id routing and credentials interface (#998)
1 parent a15b53f commit 66e30ac

File tree

9 files changed

+137
-46
lines changed

9 files changed

+137
-46
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"id": "6467a679-d9c3-4741-8219-28d7d32abf5f",
3+
"type": "misc",
4+
"description": "**BREAKING**: make `Credentials` an interface",
5+
"requiresMinorVersionBump": true
6+
}

codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/integration/SectionWriter.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,25 @@ fun interface SectionWriter {
3434
fun write(writer: KotlinWriter, previousValue: String?)
3535
}
3636

37+
/**
38+
* A [SectionWriter] that always appends to the existing section contents (if any).
39+
*/
40+
fun interface AppendingSectionWriter : SectionWriter {
41+
override fun write(writer: KotlinWriter, previousValue: String?) {
42+
if (!previousValue.isNullOrBlank()) {
43+
writer.write(previousValue)
44+
}
45+
append(writer)
46+
}
47+
48+
/**
49+
* This function writes code for the bound section.
50+
* @param writer the writer used to write contents to for the active section, contents are always appended
51+
* in the case of multiple section writers being bound to the same section.
52+
*/
53+
fun append(writer: KotlinWriter)
54+
}
55+
3756
/**
3857
* Binds a [SectionId] to a specific [SectionWriter]. Integrations may provide
3958
* lists of these bindings to allow overriding of codegen output at defined points

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ org.gradle.jvmargs=-Xmx2G -XX:MaxMetaspaceSize=1G
1111
sdkVersion=0.28.3-SNAPSHOT
1212

1313
# codegen
14-
codegenVersion=0.28.2
14+
codegenVersion=0.28.3-SNAPSHOT
1515

1616
# kotlin
17-
kotlinVersion=1.9.20
17+
kotlinVersion=1.9.20

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ slf4j-v1x-version = "1.7.36"
1313
crt-kotlin-version = "0.8.2"
1414

1515
# codegen
16-
smithy-version = "1.41.0"
16+
smithy-version = "1.41.1"
1717
smithy-gradle-version = "0.7.0"
1818

1919
# testing

runtime/auth/aws-credentials/api/aws-credentials.api

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,27 @@ public final class aws/smithy/kotlin/runtime/auth/awscredentials/CachedCredentia
1212
public abstract interface class aws/smithy/kotlin/runtime/auth/awscredentials/CloseableCredentialsProvider : aws/smithy/kotlin/runtime/auth/awscredentials/CredentialsProvider, java/io/Closeable {
1313
}
1414

15-
public final class aws/smithy/kotlin/runtime/auth/awscredentials/Credentials : aws/smithy/kotlin/runtime/identity/Identity {
16-
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Laws/smithy/kotlin/runtime/time/Instant;Ljava/lang/String;)V
17-
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Laws/smithy/kotlin/runtime/time/Instant;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
18-
public final fun component1 ()Ljava/lang/String;
19-
public final fun component2 ()Ljava/lang/String;
20-
public final fun component3 ()Ljava/lang/String;
21-
public final fun component4 ()Laws/smithy/kotlin/runtime/time/Instant;
22-
public final fun component5 ()Ljava/lang/String;
23-
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Laws/smithy/kotlin/runtime/time/Instant;Ljava/lang/String;)Laws/smithy/kotlin/runtime/auth/awscredentials/Credentials;
24-
public static synthetic fun copy$default (Laws/smithy/kotlin/runtime/auth/awscredentials/Credentials;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Laws/smithy/kotlin/runtime/time/Instant;Ljava/lang/String;ILjava/lang/Object;)Laws/smithy/kotlin/runtime/auth/awscredentials/Credentials;
25-
public fun equals (Ljava/lang/Object;)Z
26-
public final fun getAccessKeyId ()Ljava/lang/String;
27-
public synthetic fun getAttributes ()Laws/smithy/kotlin/runtime/util/Attributes;
28-
public fun getAttributes ()Laws/smithy/kotlin/runtime/util/MutableAttributes;
29-
public fun getExpiration ()Laws/smithy/kotlin/runtime/time/Instant;
30-
public final fun getProviderName ()Ljava/lang/String;
31-
public final fun getSecretAccessKey ()Ljava/lang/String;
32-
public final fun getSessionToken ()Ljava/lang/String;
33-
public fun hashCode ()I
34-
public fun toString ()Ljava/lang/String;
15+
public abstract interface class aws/smithy/kotlin/runtime/auth/awscredentials/Credentials : aws/smithy/kotlin/runtime/identity/Identity {
16+
public static final field Companion Laws/smithy/kotlin/runtime/auth/awscredentials/Credentials$Companion;
17+
public abstract fun getAccessKeyId ()Ljava/lang/String;
18+
public abstract fun getProviderName ()Ljava/lang/String;
19+
public abstract fun getSecretAccessKey ()Ljava/lang/String;
20+
public abstract fun getSessionToken ()Ljava/lang/String;
21+
}
22+
23+
public final class aws/smithy/kotlin/runtime/auth/awscredentials/Credentials$Companion {
24+
public final fun invoke (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Laws/smithy/kotlin/runtime/time/Instant;Ljava/lang/String;Laws/smithy/kotlin/runtime/util/Attributes;)Laws/smithy/kotlin/runtime/auth/awscredentials/Credentials;
25+
public static synthetic fun invoke$default (Laws/smithy/kotlin/runtime/auth/awscredentials/Credentials$Companion;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Laws/smithy/kotlin/runtime/time/Instant;Ljava/lang/String;Laws/smithy/kotlin/runtime/util/Attributes;ILjava/lang/Object;)Laws/smithy/kotlin/runtime/auth/awscredentials/Credentials;
26+
}
27+
28+
public final class aws/smithy/kotlin/runtime/auth/awscredentials/Credentials$DefaultImpls {
29+
public static fun getProviderName (Laws/smithy/kotlin/runtime/auth/awscredentials/Credentials;)Ljava/lang/String;
30+
public static fun getSessionToken (Laws/smithy/kotlin/runtime/auth/awscredentials/Credentials;)Ljava/lang/String;
31+
}
32+
33+
public final class aws/smithy/kotlin/runtime/auth/awscredentials/CredentialsKt {
34+
public static final fun copy (Laws/smithy/kotlin/runtime/auth/awscredentials/Credentials;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Laws/smithy/kotlin/runtime/time/Instant;Ljava/lang/String;Laws/smithy/kotlin/runtime/util/Attributes;)Laws/smithy/kotlin/runtime/auth/awscredentials/Credentials;
35+
public static synthetic fun copy$default (Laws/smithy/kotlin/runtime/auth/awscredentials/Credentials;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Laws/smithy/kotlin/runtime/time/Instant;Ljava/lang/String;Laws/smithy/kotlin/runtime/util/Attributes;ILjava/lang/Object;)Laws/smithy/kotlin/runtime/auth/awscredentials/Credentials;
3536
}
3637

3738
public abstract interface class aws/smithy/kotlin/runtime/auth/awscredentials/CredentialsProvider : aws/smithy/kotlin/runtime/identity/IdentityProvider {

runtime/auth/aws-credentials/common/src/aws/smithy/kotlin/runtime/auth/awscredentials/CachedCredentialsProvider.kt

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,10 @@ public class CachedCredentialsProvider(
6161
return cachedCredentials.getOrLoad {
6262
coroutineContext.trace<CachedCredentialsProvider> { "refreshing credentials cache" }
6363
val providerCreds = source.resolve()
64-
if (providerCreds.expiration != null) {
65-
val expiration = minOf(providerCreds.expiration, (clock.now() + expireCredentialsAfter))
66-
ExpiringValue(providerCreds, expiration)
67-
} else {
68-
val expiration = clock.now() + expireCredentialsAfter
69-
val creds = providerCreds.copy(expiration = expiration)
70-
ExpiringValue(creds, expiration)
71-
}
64+
val cacheExpiration = listOfNotNull(providerCreds.expiration, clock.now() + expireCredentialsAfter).min()
65+
val credsExpiration = providerCreds.expiration ?: cacheExpiration
66+
val creds = providerCreds.copy(expiration = credsExpiration)
67+
ExpiringValue(creds, cacheExpiration)
7268
}
7369
}
7470

runtime/auth/aws-credentials/common/src/aws/smithy/kotlin/runtime/auth/awscredentials/Credentials.kt

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,84 @@ package aws.smithy.kotlin.runtime.auth.awscredentials
77
import aws.smithy.kotlin.runtime.identity.Identity
88
import aws.smithy.kotlin.runtime.identity.IdentityAttributes
99
import aws.smithy.kotlin.runtime.time.Instant
10-
import aws.smithy.kotlin.runtime.util.MutableAttributes
11-
import aws.smithy.kotlin.runtime.util.mutableAttributes
10+
import aws.smithy.kotlin.runtime.util.*
1211

1312
/**
1413
* Represents a set of AWS credentials
1514
*
1615
* For more information see [AWS security credentials](https://docs.aws.amazon.com/general/latest/gr/aws-security-credentials.html#AccessKeys)
1716
*/
18-
// FIXME - should probably be an interface
19-
public data class Credentials(
20-
val accessKeyId: String,
21-
val secretAccessKey: String,
22-
val sessionToken: String? = null,
23-
override val expiration: Instant? = null,
24-
val providerName: String? = null,
25-
) : Identity {
26-
override val attributes: MutableAttributes = mutableAttributes()
27-
init {
28-
providerName?.let {
29-
attributes[IdentityAttributes.ProviderName] = it
17+
public interface Credentials : Identity {
18+
public companion object {
19+
/**
20+
* Create a new [Credentials] instance
21+
*/
22+
public operator fun invoke(
23+
accessKeyId: String,
24+
secretAccessKey: String,
25+
sessionToken: String? = null,
26+
expiration: Instant? = null,
27+
providerName: String? = null,
28+
attributes: Attributes? = null,
29+
): Credentials {
30+
val resolvedAttributes = if (providerName != null && attributes?.getOrNull(IdentityAttributes.ProviderName) != providerName) {
31+
val merged = attributes?.toMutableAttributes() ?: mutableAttributes()
32+
merged.setIfValueNotNull(IdentityAttributes.ProviderName, providerName)
33+
merged
34+
} else {
35+
attributes ?: emptyAttributes()
36+
}
37+
38+
return CredentialsImpl(accessKeyId, secretAccessKey, sessionToken, expiration, resolvedAttributes)
3039
}
3140
}
41+
42+
/**
43+
* Identifies the user interacting with services
44+
*/
45+
public val accessKeyId: String
46+
47+
/**
48+
* Secret key used to authenticate the user and sign requests
49+
*/
50+
public val secretAccessKey: String
51+
52+
/**
53+
* Session token associated with short term credentials with an expiration.
54+
*/
55+
public val sessionToken: String?
56+
get() = null
57+
58+
/**
59+
* The name of the credentials provider that sourced these credentials (if known).
60+
*/
61+
public val providerName: String?
62+
get() = attributes.getOrNull(IdentityAttributes.ProviderName)
3263
}
64+
65+
public fun Credentials.copy(
66+
accessKeyId: String = this.accessKeyId,
67+
secretAccessKey: String = this.secretAccessKey,
68+
sessionToken: String? = this.sessionToken,
69+
expiration: Instant? = this.expiration,
70+
providerName: String? = this.providerName,
71+
attributes: Attributes? = this.attributes,
72+
): Credentials {
73+
val updatedAttributes = if (this.providerName != null && providerName == null) {
74+
// if provider name was previously set and is updated to null we need to remove it from the current attributes
75+
attributes?.toMutableAttributes()?.apply {
76+
remove(IdentityAttributes.ProviderName)
77+
}?.takeIf(Attributes::isNotEmpty)
78+
} else {
79+
attributes
80+
}
81+
return Credentials(accessKeyId, secretAccessKey, sessionToken, expiration, providerName, updatedAttributes)
82+
}
83+
84+
private data class CredentialsImpl(
85+
override val accessKeyId: String,
86+
override val secretAccessKey: String,
87+
override val sessionToken: String? = null,
88+
override val expiration: Instant? = null,
89+
override val attributes: Attributes = emptyAttributes(),
90+
) : Credentials

runtime/runtime-core/api/runtime-core.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,6 +1300,7 @@ public final class aws/smithy/kotlin/runtime/util/AttributesKt {
13001300
public static final fun attributesOf (Lkotlin/jvm/functions/Function1;)Laws/smithy/kotlin/runtime/util/Attributes;
13011301
public static final fun emptyAttributes ()Laws/smithy/kotlin/runtime/util/Attributes;
13021302
public static final fun get (Laws/smithy/kotlin/runtime/util/Attributes;Laws/smithy/kotlin/runtime/util/AttributeKey;)Ljava/lang/Object;
1303+
public static final fun isNotEmpty (Laws/smithy/kotlin/runtime/util/Attributes;)Z
13031304
public static final fun merge (Laws/smithy/kotlin/runtime/util/MutableAttributes;Laws/smithy/kotlin/runtime/util/Attributes;)V
13041305
public static final fun mutableAttributes ()Laws/smithy/kotlin/runtime/util/MutableAttributes;
13051306
public static final fun mutableAttributesOf (Lkotlin/jvm/functions/Function1;)Laws/smithy/kotlin/runtime/util/MutableAttributes;

runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/util/Attributes.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ package aws.smithy.kotlin.runtime.util
1212
* @param name the name of the attribute (for diagnostics)
1313
*/
1414
public data class AttributeKey<T>(public val name: String) {
15-
override fun toString(): String = if (name.isBlank()) super.toString() else "ExecutionAttributeKey: $name"
15+
init {
16+
require(name.isNotBlank()) { "AttributeKey name must not be blank" }
17+
}
18+
override fun toString(): String = "AttributeKey($name)"
1619
}
1720

1821
/**
@@ -60,6 +63,12 @@ public interface MutableAttributes : Attributes {
6063
public fun <T : Any> computeIfAbsent(key: AttributeKey<T>, block: () -> T): T
6164
}
6265

66+
/**
67+
* Flag indicating if attributes is not empty
68+
*/
69+
public val Attributes.isNotEmpty: Boolean
70+
get() = !isEmpty
71+
6372
/**
6473
* Gets a value of the attribute for the specified [key] or throws an [IllegalStateException] if key does not exist
6574
*/
@@ -155,6 +164,7 @@ private class AttributesImpl constructor(seed: Attributes) : MutableAttributes {
155164
}
156165

157166
override fun hashCode(): Int = map.hashCode()
167+
override fun toString(): String = map.toString()
158168
}
159169

160170
private object EmptyAttributes : Attributes {

0 commit comments

Comments
 (0)