From b02158b367cd5e1765e57b854e758dc732c40af9 Mon Sep 17 00:00:00 2001 From: Michael Dowling Date: Thu, 26 Mar 2020 17:38:53 -0700 Subject: [PATCH] Ensure HttpApiKeyAuth headers are added to CORS This change updates SecuritySchemeConverters to take in the trait being converted so that things like HttpApiKeyAuth can add their designated header to the CORS list of allowed headers. --- .../openapi/AddCorsPreflightIntegration.java | 10 +++++++++- .../openapi/CognitoUserPoolsConverter.java | 2 +- .../smithy/aws/apigateway/openapi/CorsHeader.java | 11 ++++++++++- .../fromsmithy/SecuritySchemeConverter.java | 6 ++++-- .../fromsmithy/security/AwsV4Converter.java | 2 +- .../security/HttpApiKeyAuthConverter.java | 7 +++++++ .../security/HttpApiKeyAuthConverterTest.java | 15 +++++++++++++++ .../security/http-api-key-security.json | 2 +- .../security/http-api-key-security.openapi.json | 2 +- 9 files changed, 49 insertions(+), 8 deletions(-) diff --git a/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/AddCorsPreflightIntegration.java b/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/AddCorsPreflightIntegration.java index b9e587c0202..9a3018b8545 100644 --- a/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/AddCorsPreflightIntegration.java +++ b/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/AddCorsPreflightIntegration.java @@ -111,7 +111,7 @@ private static Map deduceCorsHeaders( // Add all headers generated by security schemes. for (SecuritySchemeConverter converter : context.getSecuritySchemeConverters()) { - headerNames.addAll(converter.getAuthRequestHeaders()); + headerNames.addAll(getSecuritySchemeRequestHeaders(context, converter)); } LOGGER.fine(() -> String.format( @@ -121,6 +121,14 @@ private static Map deduceCorsHeaders( return corsHeaders; } + private static Set getSecuritySchemeRequestHeaders( + Context context, + SecuritySchemeConverter converter + ) { + T t = context.getService().expectTrait(converter.getAuthSchemeType()); + return converter.getAuthRequestHeaders(t); + } + private static Collection findAllHeaders(String path, PathItem pathItem) { // Get all "in" = "header" parameters and gather up their "name" properties. return pathItem.getOperations().values().stream() diff --git a/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/CognitoUserPoolsConverter.java b/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/CognitoUserPoolsConverter.java index 97d0b535699..8bb415806e6 100644 --- a/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/CognitoUserPoolsConverter.java +++ b/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/CognitoUserPoolsConverter.java @@ -60,7 +60,7 @@ public SecurityScheme createSecurityScheme(Context context, Cog } @Override - public Set getAuthRequestHeaders() { + public Set getAuthRequestHeaders(CognitoUserPoolsTrait trait) { return REQUEST_HEADERS; } } diff --git a/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/CorsHeader.java b/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/CorsHeader.java index 759ecd011c7..26fb8d54968 100644 --- a/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/CorsHeader.java +++ b/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/CorsHeader.java @@ -53,10 +53,19 @@ static Set deduceOperationHeaders( // and any headers explicitly modeled on the operation. Set result = new TreeSet<>(cors.getAdditionalExposedHeaders()); result.addAll(context.getOpenApiProtocol().getProtocolResponseHeaders(context, shape)); + for (SecuritySchemeConverter converter : context.getSecuritySchemeConverters()) { - result.addAll(converter.getAuthResponseHeaders()); + result.addAll(getSecuritySchemeResponseHeaders(context, converter)); } return result; } + + private static Set getSecuritySchemeResponseHeaders( + Context context, + SecuritySchemeConverter converter + ) { + T t = context.getService().expectTrait(converter.getAuthSchemeType()); + return converter.getAuthResponseHeaders(t); + } } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/SecuritySchemeConverter.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/SecuritySchemeConverter.java index 6d33a5f5cc4..06e84b48107 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/SecuritySchemeConverter.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/SecuritySchemeConverter.java @@ -91,9 +91,10 @@ default List createSecurityRequirements(Context context * *

This is useful when integrating with things like CORS.

* + * @param authTrait The auth trait that is being used. * @return A set of header names. */ - default Set getAuthRequestHeaders() { + default Set getAuthRequestHeaders(T authTrait) { return SetUtils.of(); } @@ -103,9 +104,10 @@ default Set getAuthRequestHeaders() { * *

This is useful when integrating with things like CORS.

* + * @param authTrait The auth trait that is being used. * @return A set of header names. */ - default Set getAuthResponseHeaders() { + default Set getAuthResponseHeaders(T authTrait) { return SetUtils.of(); } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/security/AwsV4Converter.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/security/AwsV4Converter.java index 397efb0785a..4fea698fc1b 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/security/AwsV4Converter.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/security/AwsV4Converter.java @@ -49,7 +49,7 @@ public SecurityScheme createSecurityScheme(Context context, Sig } @Override - public Set getAuthRequestHeaders() { + public Set getAuthRequestHeaders(SigV4Trait trait) { return REQUEST_HEADERS; } } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/security/HttpApiKeyAuthConverter.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/security/HttpApiKeyAuthConverter.java index bf2c43230e9..7b0b3f5650a 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/security/HttpApiKeyAuthConverter.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/security/HttpApiKeyAuthConverter.java @@ -15,11 +15,13 @@ package software.amazon.smithy.openapi.fromsmithy.security; +import java.util.Set; import software.amazon.smithy.model.traits.HttpApiKeyAuthTrait; import software.amazon.smithy.model.traits.Trait; import software.amazon.smithy.openapi.fromsmithy.Context; import software.amazon.smithy.openapi.fromsmithy.SecuritySchemeConverter; import software.amazon.smithy.openapi.model.SecurityScheme; +import software.amazon.smithy.utils.SetUtils; /** * Uses an HTTP header named X-Api-Key that contains an API key. @@ -42,4 +44,9 @@ public SecurityScheme createSecurityScheme(Context context, Htt .in(trait.getIn().toString()) .build(); } + + @Override + public Set getAuthRequestHeaders(HttpApiKeyAuthTrait trait) { + return SetUtils.of(trait.getName()); + } } diff --git a/smithy-openapi/src/test/java/software/amazon/smithy/openapi/fromsmithy/security/HttpApiKeyAuthConverterTest.java b/smithy-openapi/src/test/java/software/amazon/smithy/openapi/fromsmithy/security/HttpApiKeyAuthConverterTest.java index 32e60ca59a7..1ddb64b5003 100644 --- a/smithy-openapi/src/test/java/software/amazon/smithy/openapi/fromsmithy/security/HttpApiKeyAuthConverterTest.java +++ b/smithy-openapi/src/test/java/software/amazon/smithy/openapi/fromsmithy/security/HttpApiKeyAuthConverterTest.java @@ -1,9 +1,13 @@ package software.amazon.smithy.openapi.fromsmithy.security; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; + import org.junit.jupiter.api.Test; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.traits.HttpApiKeyAuthTrait; import software.amazon.smithy.openapi.fromsmithy.OpenApiConverter; import software.amazon.smithy.openapi.model.OpenApi; import software.amazon.smithy.utils.IoUtils; @@ -22,4 +26,15 @@ public void addsCustomApiKeyAuth() { Node.assertEquals(result, expectedNode); } + + @Test + public void returnsTraitHeader() { + HttpApiKeyAuthConverter converter = new HttpApiKeyAuthConverter(); + HttpApiKeyAuthTrait trait = HttpApiKeyAuthTrait.builder() + .name("x-api-key") + .in(HttpApiKeyAuthTrait.Location.HEADER) + .build(); + + assertThat(converter.getAuthRequestHeaders(trait), containsInAnyOrder("x-api-key")); + } } diff --git a/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/security/http-api-key-security.json b/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/security/http-api-key-security.json index 2066a1684d1..1223262910f 100644 --- a/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/security/http-api-key-security.json +++ b/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/security/http-api-key-security.json @@ -12,7 +12,7 @@ "traits": { "aws.protocols#restJson1": true, "smithy.api#httpApiKeyAuth": { - "name": "X-Api-Key", + "name": "x-api-key", "in": "header" } } diff --git a/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/security/http-api-key-security.openapi.json b/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/security/http-api-key-security.openapi.json index 75d8a40462b..38aeb089b95 100644 --- a/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/security/http-api-key-security.openapi.json +++ b/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/security/http-api-key-security.openapi.json @@ -20,7 +20,7 @@ "securitySchemes": { "smithy.api#httpApiKeyAuth": { "type": "apiKey", - "name": "X-Api-Key", + "name": "x-api-key", "in": "header" } }