Skip to content

Commit

Permalink
fix: support string or string slices when deserializing `IamPolicySta…
Browse files Browse the repository at this point in the history
…tement` (#854)

`Action` and `Resource` allow both `string` and `[string]` as values.
Support deserializing `IamPolicyStatement` with either of these values.

fixes: #853
  • Loading branch information
aesterline authored Apr 3, 2024
1 parent 5b1de1d commit 4a3dbc9
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 2 deletions.
21 changes: 21 additions & 0 deletions lambda-events/src/custom_serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,27 @@ where
Ok(opt.unwrap_or_default())
}

/// Deserializes `Vec<String>`, from a JSON `string` or `[string]`.
#[cfg(any(feature = "apigw", test))]
pub(crate) fn deserialize_string_or_slice<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(serde::Deserialize)]
#[serde(untagged)]
enum StringOrSlice {
String(String),
Slice(Vec<String>),
}

let string_or_slice = StringOrSlice::deserialize(deserializer)?;

match string_or_slice {
StringOrSlice::Slice(slice) => Ok(slice),
StringOrSlice::String(s) => Ok(vec![s]),
}
}

#[cfg(test)]
#[allow(deprecated)]
mod test {
Expand Down
26 changes: 24 additions & 2 deletions lambda-events/src/event/apigw/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::custom_serde::{
deserialize_headers, deserialize_lambda_map, deserialize_nullish_boolean, http_method, serialize_headers,
serialize_multi_value_headers,
deserialize_headers, deserialize_lambda_map, deserialize_nullish_boolean, deserialize_string_or_slice, http_method,
serialize_headers, serialize_multi_value_headers,
};
use crate::encodings::Body;
use http::{HeaderMap, Method};
Expand Down Expand Up @@ -737,11 +737,13 @@ pub struct ApiGatewayCustomAuthorizerPolicy {
#[serde(rename_all = "camelCase")]
pub struct IamPolicyStatement {
#[serde(rename = "Action")]
#[serde(deserialize_with = "deserialize_string_or_slice")]
pub action: Vec<String>,
#[serde(default)]
#[serde(rename = "Effect")]
pub effect: Option<String>,
#[serde(rename = "Resource")]
#[serde(deserialize_with = "deserialize_string_or_slice")]
pub resource: Vec<String>,
}

Expand Down Expand Up @@ -832,6 +834,26 @@ mod test {
assert_eq!(parsed, reparsed);
}

#[test]
#[cfg(feature = "apigw")]
fn example_apigw_custom_auth_response_with_single_value_action() {
let data = include_bytes!("../../fixtures/example-apigw-custom-auth-response-with-single-value-action.json");
let parsed: ApiGatewayCustomAuthorizerResponse = serde_json::from_slice(data).unwrap();
let output: String = serde_json::to_string(&parsed).unwrap();
let reparsed: ApiGatewayCustomAuthorizerResponse = serde_json::from_slice(output.as_bytes()).unwrap();
assert_eq!(parsed, reparsed);
}

#[test]
#[cfg(feature = "apigw")]
fn example_apigw_custom_auth_response_with_single_value_resource() {
let data = include_bytes!("../../fixtures/example-apigw-custom-auth-response-with-single-value-resource.json");
let parsed: ApiGatewayCustomAuthorizerResponse = serde_json::from_slice(data).unwrap();
let output: String = serde_json::to_string(&parsed).unwrap();
let reparsed: ApiGatewayCustomAuthorizerResponse = serde_json::from_slice(output.as_bytes()).unwrap();
assert_eq!(parsed, reparsed);
}

#[test]
#[cfg(feature = "apigw")]
fn example_apigw_request() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"principalId": "yyyyyyyy",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": ["arn:aws:execute-api:{regionId}:{accountId}:{appId}/{stage}/{httpVerb}/[{resource}/[child-resources]]"]
}
]
},
"context": {
"stringKey": "value",
"numberKey": "1",
"booleanKey": "true"
},
"usageIdentifierKey": "{api-key}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"principalId": "yyyyyyyy",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": ["execute-api:Invoke"],
"Effect": "Allow",
"Resource": "arn:aws:execute-api:{regionId}:{accountId}:{appId}/{stage}/{httpVerb}/[{resource}/[child-resources]]"
}
]
},
"context": {
"stringKey": "value",
"numberKey": "1",
"booleanKey": "true"
},
"usageIdentifierKey": "{api-key}"
}

0 comments on commit 4a3dbc9

Please sign in to comment.