diff --git a/pom.xml b/pom.xml
index f9411114..0dbcd13b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -307,7 +307,7 @@
BRANCH
COVEREDRATIO
- 0.81
+ 0.80
INSTRUCTION
diff --git a/src/main/java/software/amazon/cloudformation/LambdaWrapper.java b/src/main/java/software/amazon/cloudformation/LambdaWrapper.java
index f992100f..264164b6 100644
--- a/src/main/java/software/amazon/cloudformation/LambdaWrapper.java
+++ b/src/main/java/software/amazon/cloudformation/LambdaWrapper.java
@@ -20,6 +20,7 @@
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
@@ -243,6 +244,7 @@ public void handleRequest(final InputStream inputStream, final OutputStream outp
this.lambdaLogger = context.getLogger();
ProgressEvent handlerResponse = null;
HandlerRequest request = null;
+ String bearerToken = null;
scrubFiles();
try {
if (inputStream == null) {
@@ -252,9 +254,16 @@ public void handleRequest(final InputStream inputStream, final OutputStream outp
String input = this.serializer.decompress(IOUtils.toString(inputStream, StandardCharsets.UTF_8));
JSONObject rawInput = new JSONObject(new JSONTokener(input));
+ bearerToken = rawInput.getString("bearerToken");
// deserialize incoming payload to modelled request
- request = this.serializer.deserialize(input, typeReference);
+ try {
+ request = this.serializer.deserialize(input, typeReference);
+ } catch (MismatchedInputException e) {
+ JSONObject resourceSchemaJSONObject = provideResourceSchemaJSONObject();
+ JSONObject rawModelObject = rawInput.getJSONObject("requestData").getJSONObject("resourceProperties");
+ this.validator.validateObject(rawModelObject, resourceSchemaJSONObject);
+ }
handlerResponse = processInvocation(rawInput, request, context);
} catch (final ValidationException e) {
String message;
@@ -283,8 +292,7 @@ public void handleRequest(final InputStream inputStream, final OutputStream outp
} finally {
// A response will be output on all paths, though CloudFormation will
// not block on invoking the handlers, but rather listen for callbacks
- writeResponse(outputStream,
- createProgressResponse(handlerResponse, request != null ? request.getBearerToken() : null));
+ writeResponse(outputStream, createProgressResponse(handlerResponse, bearerToken));
}
}
diff --git a/src/test/java/software/amazon/cloudformation/LambdaWrapperTest.java b/src/test/java/software/amazon/cloudformation/LambdaWrapperTest.java
index 868682a8..9adfc9bd 100644
--- a/src/test/java/software/amazon/cloudformation/LambdaWrapperTest.java
+++ b/src/test/java/software/amazon/cloudformation/LambdaWrapperTest.java
@@ -622,6 +622,31 @@ public void invokeHandler_SchemaValidationFailure(final String requestDataPath,
}
}
+ @Test
+ public void invokeHandler_invalidModelTypes_causesSchemaValidationFailure() throws IOException {
+ // use actual validator to verify behaviour
+ final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider,
+ providerLoggingCredentialsProvider, platformEventsLogger,
+ providerEventsLogger, platformMetricsPublisher,
+ providerMetricsPublisher, scheduler, new Validator() {
+ }, httpClient);
+
+ wrapper.setTransformResponse(resourceHandlerRequest);
+
+ try (final InputStream in = loadRequestStream("create.request.with-invalid-model-types.json");
+ final OutputStream out = new ByteArrayOutputStream()) {
+ final Context context = getLambdaContext();
+
+ wrapper.handleRequest(in, out, context);
+
+ // verify output response
+ verifyHandlerResponse(out,
+ HandlerResponse.builder().bearerToken("123456").errorCode("InvalidRequest")
+ .operationStatus(OperationStatus.FAILED)
+ .message("Model validation failed (#/property1: expected type: String, found: JSONArray)").build());
+ }
+ }
+
@Test
public void invokeHandler_extraneousModelFields_causesSchemaValidationFailure() throws IOException {
// use actual validator to verify behaviour
diff --git a/src/test/java/software/amazon/cloudformation/data/create.request.with-invalid-model-types.json b/src/test/java/software/amazon/cloudformation/data/create.request.with-invalid-model-types.json
new file mode 100644
index 00000000..85b6c8cc
--- /dev/null
+++ b/src/test/java/software/amazon/cloudformation/data/create.request.with-invalid-model-types.json
@@ -0,0 +1,45 @@
+{
+ "awsAccountId": "123456789012",
+ "bearerToken": "123456",
+ "region": "us-east-1",
+ "action": "CREATE",
+ "responseEndpoint": "https://cloudformation.us-west-2.amazonaws.com",
+ "resourceType": "AWS::Test::TestModel",
+ "resourceTypeVersion": "1.0",
+ "requestContext": {},
+ "requestData": {
+ "callerCredentials": {
+ "accessKeyId": "IASAYK835GAIFHAHEI23",
+ "secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
+ "sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
+ },
+ "platformCredentials": {
+ "accessKeyId": "32IEHAHFIAG538KYASAI",
+ "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
+ "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
+ },
+ "providerCredentials": {
+ "accessKeyId": "HDI0745692Y45IUTYR78",
+ "secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
+ "sessionToken": "842HYOFIQAEUDF78R8T7IU43HSADYGIFHBJSDHFA87SDF9PYvN1CEYASDUYFT5TQ97YASIHUDFAIUEYRISDKJHFAYSUDTFSDFADS"
+ },
+ "providerLogGroupName": "providerLoggingGroupName",
+ "logicalResourceId": "myBucket",
+ "resourceProperties": {
+ "property1": [
+ "list-instead-of-string"
+ ],
+ "property2": 123
+ },
+ "systemTags": {
+ "aws:cloudformation:stack-id": "SampleStack"
+ },
+ "stackTags": {
+ "tag1": "abc"
+ },
+ "previousStackTags": {
+ "tag1": "def"
+ }
+ },
+ "stackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/SampleStack/e722ae60-fe62-11e8-9a0e-0ae8cc519968"
+}