From 20644d87172843542dda5aa38339e087f84cc772 Mon Sep 17 00:00:00 2001 From: John Viegas Date: Thu, 7 Jul 2022 06:29:47 -0700 Subject: [PATCH] Skip Signing of requests which are defined with authtype as none --- .../bugfix-AWSSDKforJavav2-52c39b2.json | 6 + .../poet/client/specs/JsonProtocolSpec.java | 5 +- .../poet/client/specs/QueryProtocolSpec.java | 9 +- .../poet/client/specs/XmlProtocolSpec.java | 8 +- .../traits/NoneAuthTypeRequestTrait.java | 51 ++++++ .../poet/client/c2j/json/service-2.json | 8 + .../poet/client/c2j/query/service-2.json | 8 + .../poet/client/c2j/xml/service-2.json | 8 + .../test-aws-json-async-client-class.java | 60 +++++++ .../client/test-query-async-client-class.java | 57 +++++++ .../poet/client/test-query-client-class.java | 48 ++++++ .../client/test-xml-async-client-class.java | 56 ++++++ .../poet/client/test-xml-client-class.java | 46 +++++ .../internal/AwsExecutionContextBuilder.java | 19 ++- .../SdkInternalExecutionAttribute.java | 4 + .../customresponsemetadata/service-2.json | 10 ++ .../codegen-resources/xml/service-2.json | 10 ++ .../services/NoneAuthTypeRequestTest.java | 160 ++++++++++++++++++ 18 files changed, 564 insertions(+), 9 deletions(-) create mode 100644 .changes/next-release/bugfix-AWSSDKforJavav2-52c39b2.json create mode 100644 codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/traits/NoneAuthTypeRequestTrait.java create mode 100644 test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/NoneAuthTypeRequestTest.java diff --git a/.changes/next-release/bugfix-AWSSDKforJavav2-52c39b2.json b/.changes/next-release/bugfix-AWSSDKforJavav2-52c39b2.json new file mode 100644 index 000000000000..fe56c12d71b0 --- /dev/null +++ b/.changes/next-release/bugfix-AWSSDKforJavav2-52c39b2.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "AWS SDK for Java v2", + "contributor": "", + "description": "Requests which are defined with AuthType as None should not be signed or authorized by the SDK." +} diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java index a880bd5a1b31..09f075c33e1a 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java @@ -41,6 +41,7 @@ import software.amazon.awssdk.codegen.poet.PoetExtension; import software.amazon.awssdk.codegen.poet.client.traits.HttpChecksumRequiredTrait; import software.amazon.awssdk.codegen.poet.client.traits.HttpChecksumTrait; +import software.amazon.awssdk.codegen.poet.client.traits.NoneAuthTypeRequestTrait; import software.amazon.awssdk.codegen.poet.eventstream.EventStreamUtils; import software.amazon.awssdk.codegen.poet.model.EventStreamSpecHelper; import software.amazon.awssdk.core.SdkPojoBuilder; @@ -177,7 +178,8 @@ public CodeBlock executionHandler(OperationModel opModel) { .add(".withInput($L)\n", opModel.getInput().getVariableName()) .add(".withMetricCollector(apiCallMetricCollector)") .add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel)) - .add(HttpChecksumTrait.create(opModel)); + .add(HttpChecksumTrait.create(opModel)) + .add(NoneAuthTypeRequestTrait.create(opModel)); if (opModel.hasStreamingInput()) { codeBlock.add(".withRequestBody(requestBody)") @@ -245,6 +247,7 @@ public CodeBlock asyncExecutionHandler(IntermediateModel intermediateModel, Oper .add(asyncRequestBody) .add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel)) .add(HttpChecksumTrait.create(opModel)) + .add(NoneAuthTypeRequestTrait.create(opModel)) .add(".withInput($L)$L);", opModel.getInput().getVariableName(), asyncResponseTransformerVariable(isStreaming, isRestJson, opModel)); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/QueryProtocolSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/QueryProtocolSpec.java index 6837acec3517..2935074d5080 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/QueryProtocolSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/QueryProtocolSpec.java @@ -30,6 +30,7 @@ import software.amazon.awssdk.codegen.poet.PoetExtension; import software.amazon.awssdk.codegen.poet.client.traits.HttpChecksumRequiredTrait; import software.amazon.awssdk.codegen.poet.client.traits.HttpChecksumTrait; +import software.amazon.awssdk.codegen.poet.client.traits.NoneAuthTypeRequestTrait; import software.amazon.awssdk.core.async.AsyncResponseTransformer; import software.amazon.awssdk.core.client.handler.ClientExecutionParams; import software.amazon.awssdk.core.http.HttpResponseHandler; @@ -113,7 +114,9 @@ public CodeBlock executionHandler(OperationModel opModel) { .add(".withInput($L)", opModel.getInput().getVariableName()) .add(".withMetricCollector(apiCallMetricCollector)") .add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel)) - .add(HttpChecksumTrait.create(opModel)); + .add(HttpChecksumTrait.create(opModel)) + .add(NoneAuthTypeRequestTrait.create(opModel)); + if (opModel.hasStreamingInput()) { return codeBlock.add(".withRequestBody(requestBody)") @@ -145,7 +148,9 @@ public CodeBlock asyncExecutionHandler(IntermediateModel intermediateModel, Oper .add(".withErrorResponseHandler(errorResponseHandler)\n") .add(".withMetricCollector(apiCallMetricCollector)\n") .add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel)) - .add(HttpChecksumTrait.create(opModel)); + .add(HttpChecksumTrait.create(opModel)) + .add(NoneAuthTypeRequestTrait.create(opModel)); + builder.add(hostPrefixExpression(opModel) + asyncRequestBody + ".withInput($L)$L);", opModel.getInput().getVariableName(), diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/XmlProtocolSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/XmlProtocolSpec.java index 6e4d404f8c84..23cc746c107c 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/XmlProtocolSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/XmlProtocolSpec.java @@ -36,6 +36,7 @@ import software.amazon.awssdk.codegen.poet.PoetExtension; import software.amazon.awssdk.codegen.poet.client.traits.HttpChecksumRequiredTrait; import software.amazon.awssdk.codegen.poet.client.traits.HttpChecksumTrait; +import software.amazon.awssdk.codegen.poet.client.traits.NoneAuthTypeRequestTrait; import software.amazon.awssdk.codegen.poet.eventstream.EventStreamUtils; import software.amazon.awssdk.codegen.poet.model.EventStreamSpecHelper; import software.amazon.awssdk.core.SdkPojoBuilder; @@ -132,7 +133,9 @@ public CodeBlock executionHandler(OperationModel opModel) { discoveredEndpoint(opModel)) .add(".withInput($L)", opModel.getInput().getVariableName()) .add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel)) - .add(HttpChecksumTrait.create(opModel)); + .add(HttpChecksumTrait.create(opModel)) + .add(NoneAuthTypeRequestTrait.create(opModel)); + s3ArnableFields(opModel, model).ifPresent(codeBlock::add); @@ -207,7 +210,8 @@ public CodeBlock asyncExecutionHandler(IntermediateModel intermediateModel, Oper .add(".withMetricCollector(apiCallMetricCollector)\n") .add(asyncRequestBody(opModel)) .add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel)) - .add(HttpChecksumTrait.create(opModel)); + .add(HttpChecksumTrait.create(opModel)) + .add(NoneAuthTypeRequestTrait.create(opModel)); s3ArnableFields(opModel, model).ifPresent(builder::add); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/traits/NoneAuthTypeRequestTrait.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/traits/NoneAuthTypeRequestTrait.java new file mode 100644 index 000000000000..99bded7b1f8b --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/traits/NoneAuthTypeRequestTrait.java @@ -0,0 +1,51 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.codegen.poet.client.traits; + +import com.squareup.javapoet.CodeBlock; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.codegen.model.intermediate.OperationModel; +import software.amazon.awssdk.codegen.model.service.AuthType; +import software.amazon.awssdk.core.client.handler.ClientExecutionParams; +import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute; + +/** + * Trait which defines if a given request needs to be authenticated. + * A request is not authenticated only if it has "auththpe" trait explicitly marked as "none" + */ +@SdkInternalApi +public class NoneAuthTypeRequestTrait { + + private NoneAuthTypeRequestTrait() { + } + + /** + * Generate a ".putExecutionAttribute(...)" code-block for the provided operation model. This should be used within the + * context of initializing {@link ClientExecutionParams}. If and only if "authType" trait is explicitly set as "none" the set + * the execution attribute as false. + */ + public static CodeBlock create(OperationModel operationModel) { + + if (operationModel.getAuthType() == AuthType.NONE) { + CodeBlock.Builder codeBuilder = CodeBlock.builder(); + codeBuilder.add(CodeBlock.of(".putExecutionAttribute($T.IS_NONE_AUTH_TYPE_REQUEST, $L)", + SdkInternalExecutionAttribute.class, operationModel.getAuthType() != AuthType.NONE)); + return codeBuilder.build(); + } else { + return CodeBlock.of(""); + } + } +} \ No newline at end of file diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/json/service-2.json b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/json/service-2.json index d3581d4b7605..a6b68565f196 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/json/service-2.json +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/json/service-2.json @@ -22,6 +22,14 @@ }, "httpChecksumRequired": true }, + "OperationWithNoneAuthType": { + "name": "APostOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "authtype": "none" + }, "APostOperation": { "name": "APostOperation", "http": { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/query/service-2.json b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/query/service-2.json index e38452426e33..68b9939c0235 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/query/service-2.json +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/query/service-2.json @@ -21,6 +21,14 @@ }, "httpChecksumRequired": true }, + "OperationWithNoneAuthType": { + "name": "APostOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "authtype": "none" + }, "APostOperation": { "name": "APostOperation", "http": { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/xml/service-2.json b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/xml/service-2.json index 46ae6c88037e..e310ea6de689 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/xml/service-2.json +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/xml/service-2.json @@ -21,6 +21,14 @@ }, "httpChecksumRequired": true }, + "OperationWithNoneAuthType": { + "name": "NoneAuthTypeOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "authtype": "none" + }, "APostOperation": { "name": "APostOperation", "http": { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-aws-json-async-client-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-aws-json-async-client-class.java index f10d49bbce3a..15955652b6ed 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-aws-json-async-client-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-aws-json-async-client-class.java @@ -75,6 +75,8 @@ import software.amazon.awssdk.services.json.model.JsonRequest; import software.amazon.awssdk.services.json.model.OperationWithChecksumRequiredRequest; import software.amazon.awssdk.services.json.model.OperationWithChecksumRequiredResponse; +import software.amazon.awssdk.services.json.model.OperationWithNoneAuthTypeRequest; +import software.amazon.awssdk.services.json.model.OperationWithNoneAuthTypeResponse; import software.amazon.awssdk.services.json.model.PaginatedOperationWithResultKeyRequest; import software.amazon.awssdk.services.json.model.PaginatedOperationWithResultKeyResponse; import software.amazon.awssdk.services.json.model.PaginatedOperationWithoutResultKeyRequest; @@ -99,6 +101,7 @@ import software.amazon.awssdk.services.json.transform.InputEventMarshaller; import software.amazon.awssdk.services.json.transform.InputEventTwoMarshaller; import software.amazon.awssdk.services.json.transform.OperationWithChecksumRequiredRequestMarshaller; +import software.amazon.awssdk.services.json.transform.OperationWithNoneAuthTypeRequestMarshaller; import software.amazon.awssdk.services.json.transform.PaginatedOperationWithResultKeyRequestMarshaller; import software.amazon.awssdk.services.json.transform.PaginatedOperationWithoutResultKeyRequestMarshaller; import software.amazon.awssdk.services.json.transform.StreamingInputOperationRequestMarshaller; @@ -617,6 +620,63 @@ public CompletableFuture operationWithChe } } + /** + * Invokes the OperationWithNoneAuthType operation asynchronously. + * + * @param operationWithNoneAuthTypeRequest + * @return A Java Future containing the result of the OperationWithNoneAuthType operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. + * + * @sample JsonAsyncClient.OperationWithNoneAuthType + * @see AWS API Documentation + */ + @Override + public CompletableFuture operationWithNoneAuthType( + OperationWithNoneAuthTypeRequest operationWithNoneAuthTypeRequest) { + List metricPublishers = resolveMetricPublishers(clientConfiguration, operationWithNoneAuthTypeRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "Json Service"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "OperationWithNoneAuthType"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, OperationWithNoneAuthTypeResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("OperationWithNoneAuthType") + .withMarshaller(new OperationWithNoneAuthTypeRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withMetricCollector(apiCallMetricCollector) + .putExecutionAttribute(SdkInternalExecutionAttribute.IS_NONE_AUTH_TYPE_REQUEST, false) + .withInput(operationWithNoneAuthTypeRequest)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + /** * Some paginated operation with result_key in paginators.json file * diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-async-client-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-async-client-class.java index d1a370a7bd45..fe3bef6d7d6d 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-async-client-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-async-client-class.java @@ -44,6 +44,8 @@ import software.amazon.awssdk.services.query.model.InvalidInputException; import software.amazon.awssdk.services.query.model.OperationWithChecksumRequiredRequest; import software.amazon.awssdk.services.query.model.OperationWithChecksumRequiredResponse; +import software.amazon.awssdk.services.query.model.OperationWithNoneAuthTypeRequest; +import software.amazon.awssdk.services.query.model.OperationWithNoneAuthTypeResponse; import software.amazon.awssdk.services.query.model.PutOperationWithChecksumRequest; import software.amazon.awssdk.services.query.model.PutOperationWithChecksumResponse; import software.amazon.awssdk.services.query.model.QueryException; @@ -56,6 +58,7 @@ import software.amazon.awssdk.services.query.transform.APostOperationWithOutputRequestMarshaller; import software.amazon.awssdk.services.query.transform.GetOperationWithChecksumRequestMarshaller; import software.amazon.awssdk.services.query.transform.OperationWithChecksumRequiredRequestMarshaller; +import software.amazon.awssdk.services.query.transform.OperationWithNoneAuthTypeRequestMarshaller; import software.amazon.awssdk.services.query.transform.PutOperationWithChecksumRequestMarshaller; import software.amazon.awssdk.services.query.transform.StreamingInputOperationRequestMarshaller; import software.amazon.awssdk.services.query.transform.StreamingOutputOperationRequestMarshaller; @@ -322,6 +325,60 @@ public CompletableFuture operationWithChe } } + /** + * Invokes the OperationWithNoneAuthType operation asynchronously. + * + * @param operationWithNoneAuthTypeRequest + * @return A Java Future containing the result of the OperationWithNoneAuthType operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. + *
    + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • QueryException Base class for all service exceptions. Unknown exceptions will be thrown as an + * instance of this type.
  • + *
+ * @sample QueryAsyncClient.OperationWithNoneAuthType + * @see AWS API Documentation + */ + @Override + public CompletableFuture operationWithNoneAuthType( + OperationWithNoneAuthTypeRequest operationWithNoneAuthTypeRequest) { + List metricPublishers = resolveMetricPublishers(clientConfiguration, operationWithNoneAuthTypeRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "Query Service"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "OperationWithNoneAuthType"); + + HttpResponseHandler responseHandler = protocolFactory + .createResponseHandler(OperationWithNoneAuthTypeResponse::builder); + + HttpResponseHandler errorResponseHandler = protocolFactory.createErrorResponseHandler(); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("OperationWithNoneAuthType") + .withMarshaller(new OperationWithNoneAuthTypeRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withMetricCollector(apiCallMetricCollector) + .putExecutionAttribute(SdkInternalExecutionAttribute.IS_NONE_AUTH_TYPE_REQUEST, false) + .withInput(operationWithNoneAuthTypeRequest)); + CompletableFuture whenCompleteFuture = null; + whenCompleteFuture = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + return CompletableFutureUtils.forwardExceptionTo(whenCompleteFuture, executeFuture); + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + /** * Invokes the PutOperationWithChecksum operation asynchronously. * diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-client-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-client-class.java index 8de1a37a780d..6cf1fb52f335 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-client-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-client-class.java @@ -34,6 +34,8 @@ import software.amazon.awssdk.services.query.model.InvalidInputException; import software.amazon.awssdk.services.query.model.OperationWithChecksumRequiredRequest; import software.amazon.awssdk.services.query.model.OperationWithChecksumRequiredResponse; +import software.amazon.awssdk.services.query.model.OperationWithNoneAuthTypeRequest; +import software.amazon.awssdk.services.query.model.OperationWithNoneAuthTypeResponse; import software.amazon.awssdk.services.query.model.PutOperationWithChecksumRequest; import software.amazon.awssdk.services.query.model.PutOperationWithChecksumResponse; import software.amazon.awssdk.services.query.model.QueryException; @@ -45,6 +47,7 @@ import software.amazon.awssdk.services.query.transform.APostOperationWithOutputRequestMarshaller; import software.amazon.awssdk.services.query.transform.GetOperationWithChecksumRequestMarshaller; import software.amazon.awssdk.services.query.transform.OperationWithChecksumRequiredRequestMarshaller; +import software.amazon.awssdk.services.query.transform.OperationWithNoneAuthTypeRequestMarshaller; import software.amazon.awssdk.services.query.transform.PutOperationWithChecksumRequestMarshaller; import software.amazon.awssdk.services.query.transform.StreamingInputOperationRequestMarshaller; import software.amazon.awssdk.services.query.transform.StreamingOutputOperationRequestMarshaller; @@ -273,6 +276,51 @@ public OperationWithChecksumRequiredResponse operationWithChecksumRequired( } } + /** + * Invokes the OperationWithNoneAuthType operation. + * + * @param operationWithNoneAuthTypeRequest + * @return Result of the OperationWithNoneAuthType operation returned by the service. + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws QueryException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample QueryClient.OperationWithNoneAuthType + * @see AWS API Documentation + */ + @Override + public OperationWithNoneAuthTypeResponse operationWithNoneAuthType( + OperationWithNoneAuthTypeRequest operationWithNoneAuthTypeRequest) throws AwsServiceException, SdkClientException, + QueryException { + + HttpResponseHandler responseHandler = protocolFactory + .createResponseHandler(OperationWithNoneAuthTypeResponse::builder); + + HttpResponseHandler errorResponseHandler = protocolFactory.createErrorResponseHandler(); + List metricPublishers = resolveMetricPublishers(clientConfiguration, operationWithNoneAuthTypeRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "Query Service"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "OperationWithNoneAuthType"); + + return clientHandler + .execute(new ClientExecutionParams() + .withOperationName("OperationWithNoneAuthType").withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).withInput(operationWithNoneAuthTypeRequest) + .withMetricCollector(apiCallMetricCollector) + .putExecutionAttribute(SdkInternalExecutionAttribute.IS_NONE_AUTH_TYPE_REQUEST, false) + .withMarshaller(new OperationWithNoneAuthTypeRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + /** * Invokes the PutOperationWithChecksum operation. * diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-xml-async-client-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-xml-async-client-class.java index 8a0d99bfd384..435bdb79a85c 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-xml-async-client-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-xml-async-client-class.java @@ -55,6 +55,8 @@ import software.amazon.awssdk.services.xml.model.InvalidInputException; import software.amazon.awssdk.services.xml.model.OperationWithChecksumRequiredRequest; import software.amazon.awssdk.services.xml.model.OperationWithChecksumRequiredResponse; +import software.amazon.awssdk.services.xml.model.OperationWithNoneAuthTypeRequest; +import software.amazon.awssdk.services.xml.model.OperationWithNoneAuthTypeResponse; import software.amazon.awssdk.services.xml.model.PutOperationWithChecksumRequest; import software.amazon.awssdk.services.xml.model.PutOperationWithChecksumResponse; import software.amazon.awssdk.services.xml.model.StreamingInputOperationRequest; @@ -68,6 +70,7 @@ import software.amazon.awssdk.services.xml.transform.EventStreamOperationRequestMarshaller; import software.amazon.awssdk.services.xml.transform.GetOperationWithChecksumRequestMarshaller; import software.amazon.awssdk.services.xml.transform.OperationWithChecksumRequiredRequestMarshaller; +import software.amazon.awssdk.services.xml.transform.OperationWithNoneAuthTypeRequestMarshaller; import software.amazon.awssdk.services.xml.transform.PutOperationWithChecksumRequestMarshaller; import software.amazon.awssdk.services.xml.transform.StreamingInputOperationRequestMarshaller; import software.amazon.awssdk.services.xml.transform.StreamingOutputOperationRequestMarshaller; @@ -406,6 +409,59 @@ public CompletableFuture operationWithChe } } + /** + * Invokes the OperationWithNoneAuthType operation asynchronously. + * + * @param operationWithNoneAuthTypeRequest + * @return A Java Future containing the result of the OperationWithNoneAuthType operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. + *
    + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • XmlException Base class for all service exceptions. Unknown exceptions will be thrown as an instance + * of this type.
  • + *
+ * @sample XmlAsyncClient.OperationWithNoneAuthType + * @see AWS API Documentation + */ + @Override + public CompletableFuture operationWithNoneAuthType( + OperationWithNoneAuthTypeRequest operationWithNoneAuthTypeRequest) { + List metricPublishers = resolveMetricPublishers(clientConfiguration, operationWithNoneAuthTypeRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "Xml Service"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "OperationWithNoneAuthType"); + + HttpResponseHandler> responseHandler = protocolFactory + .createCombinedResponseHandler(OperationWithNoneAuthTypeResponse::builder, + new XmlOperationMetadata().withHasStreamingSuccessResponse(false)); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("OperationWithNoneAuthType") + .withMarshaller(new OperationWithNoneAuthTypeRequestMarshaller(protocolFactory)) + .withCombinedResponseHandler(responseHandler).withMetricCollector(apiCallMetricCollector) + .putExecutionAttribute(SdkInternalExecutionAttribute.IS_NONE_AUTH_TYPE_REQUEST, false) + .withInput(operationWithNoneAuthTypeRequest)); + CompletableFuture whenCompleteFuture = null; + whenCompleteFuture = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + CompletableFutureUtils.forwardExceptionTo(whenCompleteFuture, executeFuture); + return whenCompleteFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + /** * Invokes the PutOperationWithChecksum operation asynchronously. * diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-xml-client-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-xml-client-class.java index 3d16dc2475f8..4669f2718983 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-xml-client-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-xml-client-class.java @@ -36,6 +36,8 @@ import software.amazon.awssdk.services.xml.model.InvalidInputException; import software.amazon.awssdk.services.xml.model.OperationWithChecksumRequiredRequest; import software.amazon.awssdk.services.xml.model.OperationWithChecksumRequiredResponse; +import software.amazon.awssdk.services.xml.model.OperationWithNoneAuthTypeRequest; +import software.amazon.awssdk.services.xml.model.OperationWithNoneAuthTypeResponse; import software.amazon.awssdk.services.xml.model.PutOperationWithChecksumRequest; import software.amazon.awssdk.services.xml.model.PutOperationWithChecksumResponse; import software.amazon.awssdk.services.xml.model.StreamingInputOperationRequest; @@ -47,6 +49,7 @@ import software.amazon.awssdk.services.xml.transform.APostOperationWithOutputRequestMarshaller; import software.amazon.awssdk.services.xml.transform.GetOperationWithChecksumRequestMarshaller; import software.amazon.awssdk.services.xml.transform.OperationWithChecksumRequiredRequestMarshaller; +import software.amazon.awssdk.services.xml.transform.OperationWithNoneAuthTypeRequestMarshaller; import software.amazon.awssdk.services.xml.transform.PutOperationWithChecksumRequestMarshaller; import software.amazon.awssdk.services.xml.transform.StreamingInputOperationRequestMarshaller; import software.amazon.awssdk.services.xml.transform.StreamingOutputOperationRequestMarshaller; @@ -265,6 +268,49 @@ public OperationWithChecksumRequiredResponse operationWithChecksumRequired( } } + /** + * Invokes the OperationWithNoneAuthType operation. + * + * @param operationWithNoneAuthTypeRequest + * @return Result of the OperationWithNoneAuthType operation returned by the service. + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws XmlException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample XmlClient.OperationWithNoneAuthType + * @see AWS API Documentation + */ + @Override + public OperationWithNoneAuthTypeResponse operationWithNoneAuthType( + OperationWithNoneAuthTypeRequest operationWithNoneAuthTypeRequest) throws AwsServiceException, SdkClientException, + XmlException { + + HttpResponseHandler> responseHandler = protocolFactory + .createCombinedResponseHandler(OperationWithNoneAuthTypeResponse::builder, + new XmlOperationMetadata().withHasStreamingSuccessResponse(false)); + List metricPublishers = resolveMetricPublishers(clientConfiguration, operationWithNoneAuthTypeRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "Xml Service"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "OperationWithNoneAuthType"); + + return clientHandler + .execute(new ClientExecutionParams() + .withOperationName("OperationWithNoneAuthType").withCombinedResponseHandler(responseHandler) + .withMetricCollector(apiCallMetricCollector).withInput(operationWithNoneAuthTypeRequest) + .putExecutionAttribute(SdkInternalExecutionAttribute.IS_NONE_AUTH_TYPE_REQUEST, false) + .withMarshaller(new OperationWithNoneAuthTypeRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + /** * Invokes the PutOperationWithChecksum operation. * diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java index 5c0f2e8bd761..fa5e565dc187 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java @@ -20,6 +20,7 @@ import java.time.Duration; import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; import software.amazon.awssdk.auth.credentials.AwsCredentials; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute; @@ -107,13 +108,18 @@ private AwsExecutionContextBuilder() { .requestBody(executionParams.getRequestBody()) .build(); interceptorContext = runInitialInterceptors(interceptorContext, executionAttributes, executionInterceptorChain); - Signer signer = resolveSigner(interceptorContext.request(), clientConfig.option(SdkAdvancedClientOption.SIGNER)); + + Signer signer = isAuthenticatedRequest(executionAttributes) ? + resolveSigner(interceptorContext.request(), clientConfig.option(SdkAdvancedClientOption.SIGNER)) : + null; // beforeExecution and modifyRequest interceptors should avoid dependency on credentials, // since they should be resolved after the interceptors run - AwsCredentials credentials = resolveCredentials(clientConfig.option(AwsClientOption.CREDENTIALS_PROVIDER), - originalRequest, - metricCollector); + AwsCredentials credentials = + isAuthenticatedRequest(executionAttributes) ? + resolveCredentials(clientConfig.option(AwsClientOption.CREDENTIALS_PROVIDER), originalRequest, metricCollector) + : AnonymousCredentialsProvider.create().resolveCredentials(); + executionAttributes.putAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS, credentials); executionAttributes.putAttribute(HttpChecksumConstant.SIGNING_METHOD, resolveSigningMethodUsed(signer, executionAttributes, credentials)); @@ -203,4 +209,9 @@ private static MetricCollector resolveMetricCollector(ClientExecutionParams SDK_HTTP_EXECUTION_ATTRIBUTES = new ExecutionAttribute<>("SdkHttpExecutionAttributes"); + public static final ExecutionAttribute IS_NONE_AUTH_TYPE_REQUEST = + new ExecutionAttribute<>("IsNoneAuthTypeRequest"); + + private SdkInternalExecutionAttribute() { } } diff --git a/test/codegen-generated-classes-test/src/main/resources/codegen-resources/customresponsemetadata/service-2.json b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/customresponsemetadata/service-2.json index 755782dae916..fdc92f62ea14 100644 --- a/test/codegen-generated-classes-test/src/main/resources/codegen-resources/customresponsemetadata/service-2.json +++ b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/customresponsemetadata/service-2.json @@ -185,6 +185,16 @@ "output":{"shape":"AllTypesStructure"}, "httpChecksumRequired": true }, + "OperationWithNoneAuthType":{ + "name":"OperationWithNoneAuthType", + "http":{ + "method":"POST", + "requestUri":"/2016-03-11/allTypes" + }, + "input":{"shape":"AllTypesStructure"}, + "output":{"shape":"AllTypesStructure"}, + "authtype": "none" + }, "OperationWithRequestChecksumRequired":{ "name":"OperationWithRequestChecksumRequired", "http":{ diff --git a/test/codegen-generated-classes-test/src/main/resources/codegen-resources/xml/service-2.json b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/xml/service-2.json index 869a5ff3b741..1b5850b715b5 100644 --- a/test/codegen-generated-classes-test/src/main/resources/codegen-resources/xml/service-2.json +++ b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/xml/service-2.json @@ -171,6 +171,16 @@ "output":{"shape":"AllTypesStructure"}, "httpChecksumRequired": true }, + "OperationWithNoneAuthType":{ + "name":"OperationWithNoneAuthType", + "http":{ + "method":"POST", + "requestUri":"/2016-03-11/allTypes" + }, + "input":{"shape":"AllTypesStructure"}, + "output":{"shape":"AllTypesStructure"}, + "authtype": "none" + }, "StreamingInputOperation":{ "name":"StreamingInputOperation", "http":{ diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/NoneAuthTypeRequestTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/NoneAuthTypeRequestTest.java new file mode 100644 index 000000000000..e914d348ad2e --- /dev/null +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/NoneAuthTypeRequestTest.java @@ -0,0 +1,160 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.services; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; + +import io.reactivex.Flowable; +import java.io.IOException; +import java.util.concurrent.CompletableFuture; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.awscore.client.builder.AwsAsyncClientBuilder; +import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder; +import software.amazon.awssdk.awscore.client.builder.AwsSyncClientBuilder; +import software.amazon.awssdk.http.ExecutableHttpRequest; +import software.amazon.awssdk.http.HttpExecuteRequest; +import software.amazon.awssdk.http.HttpExecuteResponse; +import software.amazon.awssdk.http.SdkHttpClient; +import software.amazon.awssdk.http.SdkHttpFullResponse; +import software.amazon.awssdk.http.SdkHttpRequest; +import software.amazon.awssdk.http.SdkHttpResponse; +import software.amazon.awssdk.http.async.AsyncExecuteRequest; +import software.amazon.awssdk.http.async.SdkAsyncHttpClient; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonAsyncClient; +import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonClient; +import software.amazon.awssdk.services.protocolrestxml.ProtocolRestXmlAsyncClient; +import software.amazon.awssdk.services.protocolrestxml.ProtocolRestXmlClient; + +/** + * Verify that the "authtype" C2J trait for request type is honored for each requests. + */ +public class NoneAuthTypeRequestTest { + + private SdkHttpClient httpClient; + private SdkAsyncHttpClient httpAsyncClient; + private ProtocolRestJsonClient jsonClient; + private ProtocolRestJsonAsyncClient jsonAsyncClient; + private ProtocolRestXmlClient xmlClient; + private ProtocolRestXmlAsyncClient xmlAsyncClient; + + + @Before + public void setup() throws IOException { + httpClient = Mockito.mock(SdkHttpClient.class); + httpAsyncClient = Mockito.mock(SdkAsyncHttpClient.class); + jsonClient = initializeSync(ProtocolRestJsonClient.builder()).build(); + jsonAsyncClient = initializeAsync(ProtocolRestJsonAsyncClient.builder()).build(); + xmlClient = initializeSync(ProtocolRestXmlClient.builder()).build(); + xmlAsyncClient = initializeAsync(ProtocolRestXmlAsyncClient.builder()).build(); + + SdkHttpFullResponse successfulHttpResponse = SdkHttpResponse.builder() + .statusCode(200) + .putHeader("Content-Length", "0") + .build(); + + ExecutableHttpRequest request = Mockito.mock(ExecutableHttpRequest.class); + + Mockito.when(request.call()).thenReturn(HttpExecuteResponse.builder() + .response(successfulHttpResponse) + .build()); + Mockito.when(httpClient.prepareRequest(any())).thenReturn(request); + Mockito.when(httpAsyncClient.execute(any())).thenAnswer(invocation -> { + AsyncExecuteRequest asyncExecuteRequest = invocation.getArgument(0, AsyncExecuteRequest.class); + asyncExecuteRequest.responseHandler().onHeaders(successfulHttpResponse); + asyncExecuteRequest.responseHandler().onStream(Flowable.empty()); + return CompletableFuture.completedFuture(null); + }); + } + + @Test + public void sync_json_authorization_is_absent_for_noneAuthType() { + jsonClient.operationWithNoneAuthType(o -> o.booleanMember(true)); + assertThat(getSyncRequest().firstMatchingHeader("Authorization")).isNotPresent(); + } + + @Test + public void sync_json_authorization_is_present_for_defaultAuth() { + jsonClient.jsonValuesOperation(); + assertThat(getSyncRequest().firstMatchingHeader("Authorization")).isPresent(); + } + + @Test + public void async_json_authorization_is_absent_for_noneAuthType() { + jsonAsyncClient.operationWithNoneAuthType(o -> o.booleanMember(true)); + assertThat(getAsyncRequest().firstMatchingHeader("Authorization")).isNotPresent(); + } + + @Test + public void async_json_authorization_is_present_for_defaultAuth() { + jsonAsyncClient.jsonValuesOperation(); + assertThat(getAsyncRequest().firstMatchingHeader("Authorization")).isPresent(); + } + + @Test + public void sync_xml_authorization_is_absent_for_noneAuthType() { + xmlClient.operationWithNoneAuthType(o -> o.booleanMember(true)); + assertThat(getSyncRequest().firstMatchingHeader("Authorization")).isNotPresent(); + } + + @Test + public void sync_xml_authorization_is_present_for_defaultAuth() { + xmlClient.jsonValuesOperation(json -> json.jsonValueMember("one")); + assertThat(getSyncRequest().firstMatchingHeader("Authorization")).isPresent(); + } + + @Test + public void async_xml_authorization_is_absent_for_noneAuthType() { + xmlAsyncClient.operationWithNoneAuthType(o -> o.booleanMember(true)); + assertThat(getAsyncRequest().firstMatchingHeader("Authorization")).isNotPresent(); + } + + @Test + public void async_xml_authorization_is_present_for_defaultAuth() { + xmlAsyncClient.jsonValuesOperation(json -> json.jsonValueMember("one")); + assertThat(getAsyncRequest().firstMatchingHeader("Authorization")).isPresent(); + } + + private SdkHttpRequest getSyncRequest() { + ArgumentCaptor captor = ArgumentCaptor.forClass(HttpExecuteRequest.class); + Mockito.verify(httpClient).prepareRequest(captor.capture()); + return captor.getValue().httpRequest(); + } + + private SdkHttpRequest getAsyncRequest() { + ArgumentCaptor captor = ArgumentCaptor.forClass(AsyncExecuteRequest.class); + Mockito.verify(httpAsyncClient).execute(captor.capture()); + return captor.getValue().request(); + } + + private & AwsClientBuilder> T initializeSync(T syncClientBuilder) { + return initialize(syncClientBuilder.httpClient(httpClient).credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("123", "12344")))); + } + + private & AwsClientBuilder> T initializeAsync(T asyncClientBuilder) { + return initialize(asyncClientBuilder.httpClient(httpAsyncClient)); + } + + private > T initialize(T clientBuilder) { + return clientBuilder.region(Region.US_WEST_2); + } +} \ No newline at end of file