Skip to content

Commit 4a3dbc9

Browse files
authored
fix: support string or string slices when deserializing IamPolicyStatement (#854)
`Action` and `Resource` allow both `string` and `[string]` as values. Support deserializing `IamPolicyStatement` with either of these values. fixes: #853
1 parent 5b1de1d commit 4a3dbc9

File tree

4 files changed

+83
-2
lines changed

4 files changed

+83
-2
lines changed

lambda-events/src/custom_serde/mod.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,27 @@ where
9292
Ok(opt.unwrap_or_default())
9393
}
9494

95+
/// Deserializes `Vec<String>`, from a JSON `string` or `[string]`.
96+
#[cfg(any(feature = "apigw", test))]
97+
pub(crate) fn deserialize_string_or_slice<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
98+
where
99+
D: Deserializer<'de>,
100+
{
101+
#[derive(serde::Deserialize)]
102+
#[serde(untagged)]
103+
enum StringOrSlice {
104+
String(String),
105+
Slice(Vec<String>),
106+
}
107+
108+
let string_or_slice = StringOrSlice::deserialize(deserializer)?;
109+
110+
match string_or_slice {
111+
StringOrSlice::Slice(slice) => Ok(slice),
112+
StringOrSlice::String(s) => Ok(vec![s]),
113+
}
114+
}
115+
95116
#[cfg(test)]
96117
#[allow(deprecated)]
97118
mod test {

lambda-events/src/event/apigw/mod.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::custom_serde::{
2-
deserialize_headers, deserialize_lambda_map, deserialize_nullish_boolean, http_method, serialize_headers,
3-
serialize_multi_value_headers,
2+
deserialize_headers, deserialize_lambda_map, deserialize_nullish_boolean, deserialize_string_or_slice, http_method,
3+
serialize_headers, serialize_multi_value_headers,
44
};
55
use crate::encodings::Body;
66
use http::{HeaderMap, Method};
@@ -737,11 +737,13 @@ pub struct ApiGatewayCustomAuthorizerPolicy {
737737
#[serde(rename_all = "camelCase")]
738738
pub struct IamPolicyStatement {
739739
#[serde(rename = "Action")]
740+
#[serde(deserialize_with = "deserialize_string_or_slice")]
740741
pub action: Vec<String>,
741742
#[serde(default)]
742743
#[serde(rename = "Effect")]
743744
pub effect: Option<String>,
744745
#[serde(rename = "Resource")]
746+
#[serde(deserialize_with = "deserialize_string_or_slice")]
745747
pub resource: Vec<String>,
746748
}
747749

@@ -832,6 +834,26 @@ mod test {
832834
assert_eq!(parsed, reparsed);
833835
}
834836

837+
#[test]
838+
#[cfg(feature = "apigw")]
839+
fn example_apigw_custom_auth_response_with_single_value_action() {
840+
let data = include_bytes!("../../fixtures/example-apigw-custom-auth-response-with-single-value-action.json");
841+
let parsed: ApiGatewayCustomAuthorizerResponse = serde_json::from_slice(data).unwrap();
842+
let output: String = serde_json::to_string(&parsed).unwrap();
843+
let reparsed: ApiGatewayCustomAuthorizerResponse = serde_json::from_slice(output.as_bytes()).unwrap();
844+
assert_eq!(parsed, reparsed);
845+
}
846+
847+
#[test]
848+
#[cfg(feature = "apigw")]
849+
fn example_apigw_custom_auth_response_with_single_value_resource() {
850+
let data = include_bytes!("../../fixtures/example-apigw-custom-auth-response-with-single-value-resource.json");
851+
let parsed: ApiGatewayCustomAuthorizerResponse = serde_json::from_slice(data).unwrap();
852+
let output: String = serde_json::to_string(&parsed).unwrap();
853+
let reparsed: ApiGatewayCustomAuthorizerResponse = serde_json::from_slice(output.as_bytes()).unwrap();
854+
assert_eq!(parsed, reparsed);
855+
}
856+
835857
#[test]
836858
#[cfg(feature = "apigw")]
837859
fn example_apigw_request() {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"principalId": "yyyyyyyy",
3+
"policyDocument": {
4+
"Version": "2012-10-17",
5+
"Statement": [
6+
{
7+
"Action": "execute-api:Invoke",
8+
"Effect": "Allow",
9+
"Resource": ["arn:aws:execute-api:{regionId}:{accountId}:{appId}/{stage}/{httpVerb}/[{resource}/[child-resources]]"]
10+
}
11+
]
12+
},
13+
"context": {
14+
"stringKey": "value",
15+
"numberKey": "1",
16+
"booleanKey": "true"
17+
},
18+
"usageIdentifierKey": "{api-key}"
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"principalId": "yyyyyyyy",
3+
"policyDocument": {
4+
"Version": "2012-10-17",
5+
"Statement": [
6+
{
7+
"Action": ["execute-api:Invoke"],
8+
"Effect": "Allow",
9+
"Resource": "arn:aws:execute-api:{regionId}:{accountId}:{appId}/{stage}/{httpVerb}/[{resource}/[child-resources]]"
10+
}
11+
]
12+
},
13+
"context": {
14+
"stringKey": "value",
15+
"numberKey": "1",
16+
"booleanKey": "true"
17+
},
18+
"usageIdentifierKey": "{api-key}"
19+
}

0 commit comments

Comments
 (0)