Skip to content

Commit a6cae49

Browse files
author
Wenbing Li
authored
Validate resource model if type mismatch (#274)
* Validate resource model if type mismatch * Change branch coverage to 0.80
1 parent 1e499bc commit a6cae49

File tree

4 files changed

+82
-4
lines changed

4 files changed

+82
-4
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@
307307
<limit>
308308
<counter>BRANCH</counter>
309309
<value>COVEREDRATIO</value>
310-
<minimum>0.81</minimum>
310+
<minimum>0.80</minimum>
311311
</limit>
312312
<limit>
313313
<counter>INSTRUCTION</counter>

src/main/java/software/amazon/cloudformation/LambdaWrapper.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.amazonaws.services.lambda.runtime.LambdaLogger;
2121
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
2222
import com.fasterxml.jackson.core.type.TypeReference;
23+
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
2324
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
2425
import com.google.common.annotations.VisibleForTesting;
2526
import java.io.IOException;
@@ -243,6 +244,7 @@ public void handleRequest(final InputStream inputStream, final OutputStream outp
243244
this.lambdaLogger = context.getLogger();
244245
ProgressEvent<ResourceT, CallbackT> handlerResponse = null;
245246
HandlerRequest<ResourceT, CallbackT> request = null;
247+
String bearerToken = null;
246248
scrubFiles();
247249
try {
248250
if (inputStream == null) {
@@ -252,9 +254,16 @@ public void handleRequest(final InputStream inputStream, final OutputStream outp
252254
String input = this.serializer.decompress(IOUtils.toString(inputStream, StandardCharsets.UTF_8));
253255

254256
JSONObject rawInput = new JSONObject(new JSONTokener(input));
257+
bearerToken = rawInput.getString("bearerToken");
255258

256259
// deserialize incoming payload to modelled request
257-
request = this.serializer.deserialize(input, typeReference);
260+
try {
261+
request = this.serializer.deserialize(input, typeReference);
262+
} catch (MismatchedInputException e) {
263+
JSONObject resourceSchemaJSONObject = provideResourceSchemaJSONObject();
264+
JSONObject rawModelObject = rawInput.getJSONObject("requestData").getJSONObject("resourceProperties");
265+
this.validator.validateObject(rawModelObject, resourceSchemaJSONObject);
266+
}
258267
handlerResponse = processInvocation(rawInput, request, context);
259268
} catch (final ValidationException e) {
260269
String message;
@@ -283,8 +292,7 @@ public void handleRequest(final InputStream inputStream, final OutputStream outp
283292
} finally {
284293
// A response will be output on all paths, though CloudFormation will
285294
// not block on invoking the handlers, but rather listen for callbacks
286-
writeResponse(outputStream,
287-
createProgressResponse(handlerResponse, request != null ? request.getBearerToken() : null));
295+
writeResponse(outputStream, createProgressResponse(handlerResponse, bearerToken));
288296
}
289297
}
290298

src/test/java/software/amazon/cloudformation/LambdaWrapperTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,31 @@ public void invokeHandler_SchemaValidationFailure(final String requestDataPath,
622622
}
623623
}
624624

625+
@Test
626+
public void invokeHandler_invalidModelTypes_causesSchemaValidationFailure() throws IOException {
627+
// use actual validator to verify behaviour
628+
final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider,
629+
providerLoggingCredentialsProvider, platformEventsLogger,
630+
providerEventsLogger, platformMetricsPublisher,
631+
providerMetricsPublisher, scheduler, new Validator() {
632+
}, httpClient);
633+
634+
wrapper.setTransformResponse(resourceHandlerRequest);
635+
636+
try (final InputStream in = loadRequestStream("create.request.with-invalid-model-types.json");
637+
final OutputStream out = new ByteArrayOutputStream()) {
638+
final Context context = getLambdaContext();
639+
640+
wrapper.handleRequest(in, out, context);
641+
642+
// verify output response
643+
verifyHandlerResponse(out,
644+
HandlerResponse.<TestModel>builder().bearerToken("123456").errorCode("InvalidRequest")
645+
.operationStatus(OperationStatus.FAILED)
646+
.message("Model validation failed (#/property1: expected type: String, found: JSONArray)").build());
647+
}
648+
}
649+
625650
@Test
626651
public void invokeHandler_extraneousModelFields_causesSchemaValidationFailure() throws IOException {
627652
// use actual validator to verify behaviour
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"awsAccountId": "123456789012",
3+
"bearerToken": "123456",
4+
"region": "us-east-1",
5+
"action": "CREATE",
6+
"responseEndpoint": "https://cloudformation.us-west-2.amazonaws.com",
7+
"resourceType": "AWS::Test::TestModel",
8+
"resourceTypeVersion": "1.0",
9+
"requestContext": {},
10+
"requestData": {
11+
"callerCredentials": {
12+
"accessKeyId": "IASAYK835GAIFHAHEI23",
13+
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
14+
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
15+
},
16+
"platformCredentials": {
17+
"accessKeyId": "32IEHAHFIAG538KYASAI",
18+
"secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
19+
"sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
20+
},
21+
"providerCredentials": {
22+
"accessKeyId": "HDI0745692Y45IUTYR78",
23+
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
24+
"sessionToken": "842HYOFIQAEUDF78R8T7IU43HSADYGIFHBJSDHFA87SDF9PYvN1CEYASDUYFT5TQ97YASIHUDFAIUEYRISDKJHFAYSUDTFSDFADS"
25+
},
26+
"providerLogGroupName": "providerLoggingGroupName",
27+
"logicalResourceId": "myBucket",
28+
"resourceProperties": {
29+
"property1": [
30+
"list-instead-of-string"
31+
],
32+
"property2": 123
33+
},
34+
"systemTags": {
35+
"aws:cloudformation:stack-id": "SampleStack"
36+
},
37+
"stackTags": {
38+
"tag1": "abc"
39+
},
40+
"previousStackTags": {
41+
"tag1": "def"
42+
}
43+
},
44+
"stackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/SampleStack/e722ae60-fe62-11e8-9a0e-0ae8cc519968"
45+
}

0 commit comments

Comments
 (0)