-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: enable auth resolution via endpoints #1109
Changes from 8 commits
0fea6cc
08c7a6f
9cb4801
02f4f06
322f555
b2a0b37
f19d8ad
cd23246
54d288d
27970b3
7b5be99
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"id": "38a790e8-0d9a-4dfb-9a8d-05fba0325f1e", | ||
"type": "feature", | ||
"description": "Enable auth scheme resolution via endpoints for S3 and EventBridge" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ import aws.sdk.kotlin.gradle.codegen.dsl.projectionRootDir | |
import aws.sdk.kotlin.gradle.codegen.dsl.smithyKotlinPlugin | ||
import software.amazon.smithy.gradle.tasks.SmithyBuild | ||
import software.amazon.smithy.model.Model | ||
import software.amazon.smithy.model.node.Node | ||
import software.amazon.smithy.model.shapes.ServiceShape | ||
import java.nio.file.Paths | ||
import java.util.* | ||
|
@@ -114,6 +115,20 @@ fun awsServiceProjections(): Provider<List<SmithyProjection>> { | |
imports = importPaths | ||
transforms = transformsForService(service) ?: emptyList() | ||
|
||
val packageSettingsFile = file(service.packageSettings) | ||
val packageSettings = if (packageSettingsFile.exists()) { | ||
val node = Node.parse(packageSettingsFile.inputStream()) | ||
node.asObjectNode().get() | ||
} else { | ||
Node.objectNode() | ||
} | ||
|
||
if (!packageSettings.isEmpty) { | ||
packageSettings.expectMember("sdkId", "${packageSettingsFile.absolutePath} does not contain member `sdkId`") | ||
val packageSdkId = packageSettings.getStringMember("sdkId").get().value | ||
check(service.sdkId == packageSdkId) { "${packageSettingsFile.absolutePath} `sdkId` ($packageSdkId) does not match expected `${service.sdkId}`" } | ||
} | ||
|
||
smithyKotlinPlugin { | ||
serviceShapeId = service.serviceShapeId | ||
packageName = service.packageName | ||
|
@@ -124,6 +139,9 @@ fun awsServiceProjections(): Provider<List<SmithyProjection>> { | |
generateFullProject = false | ||
generateDefaultBuildFiles = false | ||
} | ||
apiSettings { | ||
enableEndpointAuthProvider = packageSettings.getBooleanMember("enableEndpointAuthProvider").orNull()?.value | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -286,6 +304,12 @@ val AwsService.modelExtrasDir: String | |
val AwsService.transformsDir: String | ||
get() = rootProject.file("$destinationDir/transforms").absolutePath | ||
|
||
/** | ||
* Service specific package settings | ||
*/ | ||
val AwsService.packageSettings: String | ||
get() = rootProject.file("$destinationDir/package.json").absolutePath | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question/nit: Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No established name, I don't have a strong preference. I think I went with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't have a preference on the name—either package.json or config.json sounds fine to me. Taking a closer look at this now, does Smithy not already have a way to handle this? If not, should we consider moving this kind of functionality up into the smithy-kotlin later? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle what? This is custom logic to feed into |
||
|
||
fun forwardProperty(name: String) { | ||
getProperty(name)?.let { | ||
System.setProperty(name, it) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,21 +5,19 @@ | |
|
||
package aws.sdk.kotlin.codegen.customization.s3 | ||
|
||
import aws.sdk.kotlin.codegen.protocols.core.AwsHttpProtocolClientGenerator | ||
import aws.sdk.kotlin.codegen.protocols.core.putIfAbsent | ||
import software.amazon.smithy.kotlin.codegen.KotlinSettings | ||
import software.amazon.smithy.kotlin.codegen.core.KotlinWriter | ||
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes | ||
import software.amazon.smithy.kotlin.codegen.core.withBlock | ||
import software.amazon.smithy.kotlin.codegen.integration.AuthSchemeHandler | ||
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration | ||
import software.amazon.smithy.kotlin.codegen.integration.SectionWriterBinding | ||
import software.amazon.smithy.kotlin.codegen.model.expectShape | ||
import software.amazon.smithy.kotlin.codegen.model.knowledge.AwsSignatureVersion4 | ||
import software.amazon.smithy.kotlin.codegen.rendering.auth.SigV4AuthSchemeHandler | ||
import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolGenerator | ||
import software.amazon.smithy.model.Model | ||
import software.amazon.smithy.model.shapes.ServiceShape | ||
|
||
/** | ||
* Overrides the SigV4 auth scheme registered by [software.amazon.smithy.kotlin.codegen.rendering.auth.Sigv4AuthSchemeIntegration] for S3. | ||
* Set default signing attributes in the execution context (which ultimately becomes the signing context) for S3. | ||
*/ | ||
class S3SigningConfig : KotlinIntegration { | ||
// auth schemes are de-duped by taking the last one registered | ||
|
@@ -29,22 +27,14 @@ class S3SigningConfig : KotlinIntegration { | |
override fun enabledForService(model: Model, settings: KotlinSettings) = | ||
model.expectShape<ServiceShape>(settings.service).isS3 | ||
|
||
override fun authSchemes(ctx: ProtocolGenerator.GenerationContext): List<AuthSchemeHandler> = | ||
listOf(S3AuthSchemeHandler()) | ||
} | ||
|
||
private class S3AuthSchemeHandler : SigV4AuthSchemeHandler() { | ||
override fun instantiateAuthSchemeExpr(ctx: ProtocolGenerator.GenerationContext, writer: KotlinWriter) { | ||
val signingService = AwsSignatureVersion4.signingServiceName(ctx.service) | ||
writer.withBlock("#T(", ")", RuntimeTypes.Auth.HttpAuthAws.SigV4AuthScheme) { | ||
withBlock("#T.Config().apply {", "}", RuntimeTypes.Auth.HttpAuthAws.AwsHttpSigner) { | ||
write("signer = #T", RuntimeTypes.Auth.Signing.AwsSigningStandard.DefaultAwsSigner) | ||
write("service = #S", signingService) | ||
write("signedBodyHeader = #T.X_AMZ_CONTENT_SHA256", RuntimeTypes.Auth.Signing.AwsSigningCommon.AwsSignedBodyHeader) | ||
// https://github.com/awslabs/aws-sdk-kotlin/issues/200 | ||
writer.write("useDoubleUriEncode = false") | ||
writer.write("normalizeUriPath = false") | ||
} | ||
} | ||
override val sectionWriters: List<SectionWriterBinding> = listOf( | ||
SectionWriterBinding(AwsHttpProtocolClientGenerator.MergeServiceDefaults, ::renderDefaultSigningContext), | ||
) | ||
private fun renderDefaultSigningContext(writer: KotlinWriter, previousValue: String?) { | ||
val signingAttrs = RuntimeTypes.Auth.Signing.AwsSigningCommon.AwsSigningAttributes | ||
// https://github.com/awslabs/aws-sdk-kotlin/issues/200 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: this issue is closed, is it still relevant? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is here to remind us why path normalization and single URI encoding are important for S3. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I left it as a clue for posterity about why we care about this and where the requirements come from. |
||
writer.putIfAbsent(signingAttrs, "NormalizeUriPath", "false") | ||
writer.putIfAbsent(signingAttrs, "UseDoubleUriEncode", "false") | ||
writer.putIfAbsent(signingAttrs, "SignedBodyHeader", writer.format("#T.X_AMZ_CONTENT_SHA256", RuntimeTypes.Auth.Signing.AwsSigningCommon.AwsSignedBodyHeader)) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"sdkId": "EventBridge", | ||
"enableEndpointAuthProvider": true | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"sdkId": "S3", | ||
"enableEndpointAuthProvider": true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: I'm a little confused by this logic. It looks like if the file doesn't exist or contains only
{}
then we won't assert the existence of ansdkId
...why is that? Shouldn't it be an error if the file exists and is malformed?