Skip to content

Commit 48e75cb

Browse files
luigi617luigi
andauthored
Service sdk sigv4 (#1381)
Co-authored-by: luigi <[email protected]>
1 parent 2651b9a commit 48e75cb

30 files changed

+2555
-1071
lines changed

codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinDependency.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ data class KotlinDependency(
156156
val KOTLINX_CBOR_SERDE = KotlinDependency(GradleConfiguration.Implementation, "kotlinx.serialization", "org.jetbrains.kotlinx", "kotlinx-serialization-cbor", KOTLINX_VERSION)
157157
val KOTLINX_JSON_SERDE = KotlinDependency(GradleConfiguration.Implementation, "kotlinx.serialization.json", "org.jetbrains.kotlinx", "kotlinx-serialization-json", KOTLINX_VERSION)
158158
val KTOR_SERVER_AUTH = KotlinDependency(GradleConfiguration.Implementation, "io.ktor.server.auth", "io.ktor", "ktor-server-auth", KTOR_VERSION)
159+
val KTOR_SERVER_DOUBLE_RECEIVE = KotlinDependency(GradleConfiguration.Implementation, "io.ktor.server.plugins.doublereceive", "io.ktor", "ktor-server-double-receive-jvm", KTOR_VERSION)
159160
}
160161

161162
override fun getDependencies(): List<SymbolDependency> {

codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ object RuntimeTypes {
205205

206206
object Net : RuntimeTypePackage(KotlinDependency.CORE, "net") {
207207
val Host = symbol("Host")
208+
val Scheme = symbol("Scheme")
208209

209210
object Url : RuntimeTypePackage(KotlinDependency.CORE, "net.url") {
210211
val QueryParameters = symbol("QueryParameters")
@@ -393,6 +394,7 @@ object RuntimeTypes {
393394
val mergeAuthOptions = symbol("mergeAuthOptions")
394395
val sigV4 = symbol("sigV4")
395396
val sigV4A = symbol("sigV4A")
397+
val SignHttpRequest = symbol("SignHttpRequest")
396398
}
397399

398400
object AwsSigningCrt : RuntimeTypePackage(KotlinDependency.AWS_SIGNING_CRT) {
@@ -530,12 +532,15 @@ object RuntimeTypes {
530532

531533
val requestReceive = symbol("receive", "request")
532534
val requestUri = symbol("uri", "request")
535+
val requestHeader = symbol("header", "request")
533536
val requestHttpMethod = symbol("httpMethod", "request")
534537
val requestApplicationRequest = symbol("ApplicationRequest", "request")
535538
val requestContentLength = symbol("contentLength", "request")
536539
val requestContentType = symbol("contentType", "request")
537540
val requestAcceptItems = symbol("acceptItems", "request")
541+
val requestPath = symbol("path", "request")
538542

543+
val responseResponse = symbol("respond", "response")
539544
val responseResponseText = symbol("respondText", "response")
540545
val responseRespondBytes = symbol("respondBytes", "response")
541546
}
@@ -560,6 +565,8 @@ object RuntimeTypes {
560565
val HttpStatusCode = symbol("HttpStatusCode")
561566
val parseAndSortHeader = symbol("parseAndSortHeader")
562567
val HttpHeaders = symbol("HttpHeaders")
568+
val HeadersBuilder = symbol("HeadersBuilder")
569+
val Parameters = symbol("Parameters")
563570
val Cbor = symbol("Cbor", "ContentType.Application")
564571
val Json = symbol("Json", "ContentType.Application")
565572
val Any = symbol("Any", "ContentType.Application")
@@ -597,6 +604,15 @@ object RuntimeTypes {
597604
val authenticate = symbol("authenticate")
598605
val Principal = symbol("Principal")
599606
val bearer = symbol("bearer")
607+
val AuthenticationConfig = symbol("AuthenticationConfig")
608+
val AuthenticationProvider = symbol("AuthenticationProvider")
609+
val AuthenticationFailedCause = symbol("AuthenticationFailedCause")
610+
val AuthenticationContext = symbol("AuthenticationContext")
611+
val AuthenticationStrategy = symbol("AuthenticationStrategy")
612+
}
613+
614+
object KtorServerDoubleReceive : RuntimeTypePackage(KotlinDependency.KTOR_SERVER_DOUBLE_RECEIVE) {
615+
val DoubleReceive = symbol("DoubleReceive")
600616
}
601617

602618
object KotlinxCborSerde : RuntimeTypePackage(KotlinDependency.KOTLINX_CBOR_SERDE) {

codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/KtorStubGenerator.kt

Lines changed: 0 additions & 871 deletions
This file was deleted.

codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ServiceStubConfigurations.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import software.amazon.smithy.aws.traits.protocols.RestJson1Trait
44
import software.amazon.smithy.build.FileManifest
55
import software.amazon.smithy.kotlin.codegen.core.GenerationContext
66
import software.amazon.smithy.kotlin.codegen.core.KotlinDelegator
7+
import software.amazon.smithy.kotlin.codegen.service.ktor.KtorStubGenerator
78
import software.amazon.smithy.model.shapes.ServiceShape
89
import software.amazon.smithy.model.shapes.ShapeId
910
import software.amazon.smithy.model.shapes.ShapeType

codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ServiceStubGenerator.kt

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@ internal interface ServiceStubGenerator {
1515
}
1616

1717
internal abstract class AbstractStubGenerator(
18-
protected val ctx: GenerationContext,
19-
protected val delegator: KotlinDelegator,
20-
protected val fileManifest: FileManifest,
18+
val ctx: GenerationContext,
19+
val delegator: KotlinDelegator,
20+
val fileManifest: FileManifest,
2121
) : ServiceStubGenerator {
2222

23-
protected val serviceShape = ctx.settings.getService(ctx.model)
24-
protected val operations = TopDownIndex.of(ctx.model)
23+
val serviceShape = ctx.settings.getService(ctx.model)
24+
val operations = TopDownIndex.of(ctx.model)
2525
.getContainedOperations(serviceShape)
2626
.sortedBy { it.defaultName() }
2727

28-
protected val pkgName = ctx.settings.pkg.name
28+
val pkgName = ctx.settings.pkg.name
2929

3030
final override fun render() {
3131
renderServiceFrameworkConfig()
@@ -101,6 +101,7 @@ internal abstract class AbstractStubGenerator(
101101
withBlock("private data class Data(", ")") {
102102
write("val port: Int,")
103103
write("val engine: #T,", ServiceTypes(pkgName).serviceEngine)
104+
write("val region: String,")
104105
write("val requestBodyLimit: Long,")
105106
write("val requestReadTimeoutSeconds: Int,")
106107
write("val responseWriteTimeoutSeconds: Int,")
@@ -111,6 +112,7 @@ internal abstract class AbstractStubGenerator(
111112
write("")
112113
write("val port: Int get() = backing?.port ?: notInitialised(#S)", "port")
113114
write("val engine: #T get() = backing?.engine ?: notInitialised(#S)", ServiceTypes(pkgName).serviceEngine, "engine")
115+
write("val region: String get() = backing?.region ?: notInitialised(#S)", "region")
114116
write("val requestBodyLimit: Long get() = backing?.requestBodyLimit ?: notInitialised(#S)", "requestBodyLimit")
115117
write("val requestReadTimeoutSeconds: Int get() = backing?.requestReadTimeoutSeconds ?: notInitialised(#S)", "requestReadTimeoutSeconds")
116118
write("val responseWriteTimeoutSeconds: Int get() = backing?.responseWriteTimeoutSeconds ?: notInitialised(#S)", "responseWriteTimeoutSeconds")
@@ -121,6 +123,7 @@ internal abstract class AbstractStubGenerator(
121123
withInlineBlock("fun init(", ")") {
122124
write("port: Int,")
123125
write("engine: #T,", ServiceTypes(pkgName).serviceEngine)
126+
write("region: String,")
124127
write("requestBodyLimit: Long,")
125128
write("requestReadTimeoutSeconds: Int,")
126129
write("responseWriteTimeoutSeconds: Int,")
@@ -130,7 +133,7 @@ internal abstract class AbstractStubGenerator(
130133
}
131134
withBlock("{", "}") {
132135
write("check(backing == null) { #S }", "ServiceFrameworkConfig has already been initialised")
133-
write("backing = Data(port, engine, requestBodyLimit, requestReadTimeoutSeconds, responseWriteTimeoutSeconds, closeGracePeriodMillis, closeTimeoutMillis, logLevel)")
136+
write("backing = Data(port, engine, region, requestBodyLimit, requestReadTimeoutSeconds, responseWriteTimeoutSeconds, closeGracePeriodMillis, closeTimeoutMillis, logLevel)")
134137
}
135138
write("")
136139
withBlock("private fun notInitialised(prop: String): Nothing {", "}") {
@@ -178,6 +181,7 @@ internal abstract class AbstractStubGenerator(
178181
protected fun renderMainFile() {
179182
val portName = "port"
180183
val engineFactoryName = "engineFactory"
184+
val regionName = "region"
181185
val requestBodyLimitName = "requestBodyLimit"
182186
val requestReadTimeoutSecondsName = "requestReadTimeoutSeconds"
183187
val responseWriteTimeoutSecondsName = "responseWriteTimeoutSeconds"
@@ -191,6 +195,7 @@ internal abstract class AbstractStubGenerator(
191195
write("")
192196
write("val defaultPort = 8080")
193197
write("val defaultEngine = #T.NETTY_ENGINE.value", ServiceTypes(pkgName).serviceEngine)
198+
write("val defaultRegion = #S", "us-east-1")
194199
write("val defaultRequestBodyLimit = 10L * 1024 * 1024")
195200
write("val defaultRequestReadTimeoutSeconds = 30")
196201
write("val defaultResponseWriteTimeoutSeconds = 30")
@@ -201,6 +206,7 @@ internal abstract class AbstractStubGenerator(
201206
withBlock("#T.init(", ")", ServiceTypes(pkgName).serviceFrameworkConfig) {
202207
write("port = argMap[#S]?.toInt() ?: defaultPort, ", portName)
203208
write("engine = #T.fromValue(argMap[#S] ?: defaultEngine), ", ServiceTypes(pkgName).serviceEngine, engineFactoryName)
209+
write("region = argMap[#S]?.toString() ?: defaultRegion, ", regionName)
204210
write("requestBodyLimit = argMap[#S]?.toLong() ?: defaultRequestBodyLimit, ", requestBodyLimitName)
205211
write("requestReadTimeoutSeconds = argMap[#S]?.toInt() ?: defaultRequestReadTimeoutSeconds, ", requestReadTimeoutSecondsName)
206212
write("responseWriteTimeoutSeconds = argMap[#S]?.toInt() ?: defaultResponseWriteTimeoutSeconds, ", responseWriteTimeoutSecondsName)

codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/ConstraintGenerator.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ internal class ConstraintGenerator(
6161

6262
private fun renderRequestConstraintsValidation() {
6363
delegator.useFileWriter("${opName}RequestConstraints.kt", "$pkgName.constraints") { writer ->
64-
writer.addImport("$pkgName.model", "${operation.id.name}Request")
64+
val inputShape = ctx.model.expectShape(operation.input.get())
65+
val inputSymbol = ctx.symbolProvider.toSymbol(inputShape)
6566

66-
writer.withBlock("public fun check${opName}RequestConstraint(data: ${opName}Request) {", "}") {
67+
writer.withBlock("public fun check${opName}RequestConstraint(data: #T) {", "}", inputSymbol) {
6768
for (memberShape in inputMembers.values) {
6869
generateConstraintValidations("data.", memberShape, writer)
6970
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package software.amazon.smithy.kotlin.codegen.service.ktor
2+
3+
import software.amazon.smithy.aws.traits.auth.SigV4ATrait
4+
import software.amazon.smithy.aws.traits.auth.SigV4Trait
5+
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes
6+
import software.amazon.smithy.kotlin.codegen.core.withBlock
7+
import software.amazon.smithy.kotlin.codegen.model.getTrait
8+
import software.amazon.smithy.kotlin.codegen.service.ServiceTypes
9+
10+
internal fun KtorStubGenerator.writeAuthentication() {
11+
delegator.useFileWriter("UserPrincipal.kt", "$pkgName.auth") { writer ->
12+
writer.withBlock("public data class UserPrincipal(", ")") {
13+
write("val user: String")
14+
}
15+
}
16+
17+
delegator.useFileWriter("Validation.kt", "$pkgName.auth") { writer ->
18+
19+
writer.withBlock("internal object BearerValidation {", "}") {
20+
withBlock("public fun bearerValidation(token: String): UserPrincipal? {", "}") {
21+
write("// TODO: implement me:")
22+
write("// Validate the provided bearer token and return a UserPrincipal if valid.")
23+
write("// Return a UserPrincipal with user information (e.g., user id, roles) if valid,")
24+
write("// or return null if the token is invalid or expired.")
25+
write("if (true) return UserPrincipal(#S) else return null", "Authenticated User")
26+
}
27+
}
28+
}
29+
30+
delegator.useFileWriter("Authentication.kt", "$pkgName.auth") { writer ->
31+
writer.withBlock("internal fun #T.configureAuthentication() {", "}", RuntimeTypes.KtorServerCore.Application) {
32+
write("")
33+
withBlock(
34+
"#T(#T) {",
35+
"}",
36+
RuntimeTypes.KtorServerCore.install,
37+
RuntimeTypes.KtorServerAuth.Authentication,
38+
) {
39+
withBlock("#T(#S) {", "}", RuntimeTypes.KtorServerAuth.bearer, "auth-bearer") {
40+
write("realm = #S", "Access to API")
41+
write("authenticate { cred -> BearerValidation.bearerValidation(cred.token) }")
42+
}
43+
withBlock("sigV4(name = #S) {", "}", "aws-sigv4") {
44+
write("region = #T.region", ServiceTypes(pkgName).serviceFrameworkConfig)
45+
serviceShape.getTrait<SigV4Trait>()?.let {
46+
write("service = #S", it.name)
47+
}
48+
}
49+
withBlock("sigV4A(name = #S) {", "}", "aws-sigv4a") {
50+
write("region = #T.region", ServiceTypes(pkgName).serviceFrameworkConfig)
51+
serviceShape.getTrait<SigV4ATrait>()?.let {
52+
write("service = #S", it.name)
53+
}
54+
}
55+
write("provider(#S) { authenticate { ctx -> ctx.principal(Unit) } }", "no-auth")
56+
}
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)