diff --git a/src/configuration.rs b/src/configuration.rs index 78a7f8e8..c7fa9b8f 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -466,10 +466,12 @@ impl TryFrom for FilterConfig { for rlp in config.policies.iter() { for rule in &rlp.rules { - for pe in &rule.conditions { - let result = pe.compile(); - if result.is_err() { - return Err(result.err().unwrap()); + for condition in &rule.conditions { + for pe in &condition.all_of { + let result = pe.compile(); + if result.is_err() { + return Err(result.err().unwrap()); + } } } for action in &rule.actions { @@ -636,19 +638,22 @@ mod test { { "conditions": [ { - "selector": "request.path", - "operator": "eq", - "value": "/admin/toy" - }, - { - "selector": "request.method", - "operator": "eq", - "value": "POST" - }, - { - "selector": "request.host", - "operator": "eq", - "value": "cars.toystore.com" + "allOf": [ + { + "selector": "request.path", + "operator": "eq", + "value": "/admin/toy" + }, + { + "selector": "request.method", + "operator": "eq", + "value": "POST" + }, + { + "selector": "request.host", + "operator": "eq", + "value": "cars.toystore.com" + }] }], "actions": [ { @@ -686,7 +691,10 @@ mod test { assert_eq!(rules.len(), 1); let conditions = &rules[0].conditions; - assert_eq!(conditions.len(), 3); + assert_eq!(conditions.len(), 1); + + let all_of_conditions = &conditions[0].all_of; + assert_eq!(all_of_conditions.len(), 3); let actions = &rules[0].actions; assert_eq!(actions.len(), 1); @@ -753,7 +761,6 @@ mod test { "hostnames": ["*.toystore.com", "example.com"], "rules": [ { - "conditions": [], "actions": [ { "extension": "limitador", @@ -818,29 +825,32 @@ mod test { { "conditions": [ { - "selector": "request.path", - "operator": "eq", - "value": "/admin/toy" - }, - { - "selector": "request.method", - "operator": "neq", - "value": "POST" - }, - { - "selector": "request.host", - "operator": "startswith", - "value": "cars." - }, - { - "selector": "request.host", - "operator": "endswith", - "value": ".com" - }, - { - "selector": "request.host", - "operator": "matches", - "value": "*.com" + "allOf": [ + { + "selector": "request.path", + "operator": "eq", + "value": "/admin/toy" + }, + { + "selector": "request.method", + "operator": "neq", + "value": "POST" + }, + { + "selector": "request.host", + "operator": "startswith", + "value": "cars." + }, + { + "selector": "request.host", + "operator": "endswith", + "value": ".com" + }, + { + "selector": "request.host", + "operator": "matches", + "value": "*.com" + }] }], "actions": [ { @@ -864,7 +874,10 @@ mod test { assert_eq!(rules.len(), 1); let conditions = &rules[0].conditions; - assert_eq!(conditions.len(), 5); + assert_eq!(conditions.len(), 1); + + let all_of_conditions = &conditions[0].all_of; + assert_eq!(all_of_conditions.len(), 5); let expected_conditions = [ // selector, value, operator @@ -876,9 +889,9 @@ mod test { ]; for i in 0..expected_conditions.len() { - assert_eq!(conditions[i].selector, expected_conditions[i].0); - assert_eq!(conditions[i].value, expected_conditions[i].1); - assert_eq!(conditions[i].operator, expected_conditions[i].2); + assert_eq!(all_of_conditions[i].selector, expected_conditions[i].0); + assert_eq!(all_of_conditions[i].value, expected_conditions[i].1); + assert_eq!(all_of_conditions[i].operator, expected_conditions[i].2); } } @@ -898,7 +911,6 @@ mod test { "hostnames": ["*.toystore.com", "example.com"], "rules": [ { - "conditions": [], "actions": [ { "extension": "limitador", @@ -1024,9 +1036,12 @@ mod test { { "conditions": [ { - "selector": "request.path", - "operator": "unknown", - "value": "/admin/toy" + "allOf": [ + { + "selector": "request.path", + "operator": "unknown", + "value": "/admin/toy" + }] }], "actions": [ { diff --git a/src/policy.rs b/src/policy.rs index 26bc6dcd..db9ed9fe 100644 --- a/src/policy.rs +++ b/src/policy.rs @@ -3,9 +3,16 @@ use log::debug; use proxy_wasm::hostcalls; use serde::Deserialize; +#[derive(Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Condition { + pub all_of: Vec, +} + #[derive(Deserialize, Debug, Clone)] pub struct Rule { - pub conditions: Vec, + #[serde(default)] + pub conditions: Vec, pub actions: Vec, } @@ -33,7 +40,7 @@ impl Policy { .find(|rule: &&Rule| self.filter_rule_by_conditions(&rule.conditions)) } - fn filter_rule_by_conditions(&self, conditions: &[PatternExpression]) -> bool { + fn filter_rule_by_conditions(&self, conditions: &[Condition]) -> bool { if conditions.is_empty() { // no conditions is equivalent to matching all the requests. return true; @@ -41,7 +48,14 @@ impl Policy { conditions .iter() - .all(|condition| self.pattern_expression_applies(condition)) + .any(|condition| self.condition_applies(condition)) + } + + fn condition_applies(&self, condition: &Condition) -> bool { + condition + .all_of + .iter() + .all(|pattern_expression| self.pattern_expression_applies(pattern_expression)) } fn pattern_expression_applies(&self, p_e: &PatternExpression) -> bool { diff --git a/tests/rate_limited.rs b/tests/rate_limited.rs index bd3acc19..21ba4988 100644 --- a/tests/rate_limited.rs +++ b/tests/rate_limited.rs @@ -104,6 +104,8 @@ fn it_limits() { "rules": [ { "conditions": [ + { + "allOf": [ { "selector": "request.url_path", "operator": "startswith", @@ -118,8 +120,8 @@ fn it_limits() { "selector": "request.method", "operator": "eq", "value": "POST" - } - ], + }] + }], "actions": [ { "extension": "limitador", @@ -257,6 +259,8 @@ fn it_passes_additional_headers() { "rules": [ { "conditions": [ + { + "allOf": [ { "selector": "request.url_path", "operator": "startswith", @@ -271,8 +275,8 @@ fn it_passes_additional_headers() { "selector": "request.method", "operator": "eq", "value": "POST" - } - ], + }] + }], "actions": [ { "extension": "limitador", @@ -423,7 +427,6 @@ fn it_rate_limits_with_empty_conditions() { "hostnames": ["*.com"], "rules": [ { - "conditions": [], "actions": [ { "extension": "limitador", @@ -542,7 +545,6 @@ fn it_does_not_rate_limits_when_selector_does_not_exist_and_misses_default_value "hostnames": ["*.com"], "rules": [ { - "conditions": [], "actions": [ { "extension": "limitador", diff --git a/utils/deploy/envoy-notls.yaml b/utils/deploy/envoy-notls.yaml index e73be330..d116429b 100644 --- a/utils/deploy/envoy-notls.yaml +++ b/utils/deploy/envoy-notls.yaml @@ -157,9 +157,13 @@ data: { "conditions": [ { - "selector": "request.path", - "operator": "eq", - "value": "/get" + "allOf": [ + { + "selector": "request.path", + "operator": "eq", + "value": "/get" + } + ] } ], "actions": [ @@ -179,7 +183,6 @@ data: ], "rules": [ { - "conditions": [], "actions": [ { "extension": "limitador", @@ -205,9 +208,13 @@ data: { "conditions": [ { - "selector": "request.url_path", - "operator": "startswith", - "value": "/unknown-path" + "allOf": [ + { + "selector": "request.url_path", + "operator": "startswith", + "value": "/unknown-path" + } + ] } ], "actions": [ @@ -236,19 +243,23 @@ data: { "conditions": [ { - "selector": "request.url_path", - "operator": "startswith", - "value": "/get" - }, - { - "selector": "request.host", - "operator": "eq", - "value": "test.c.rlp.com" - }, - { - "selector": "request.method", - "operator": "eq", - "value": "GET" + "allOf": [ + { + "selector": "request.url_path", + "operator": "startswith", + "value": "/get" + }, + { + "selector": "request.host", + "operator": "eq", + "value": "test.c.rlp.com" + }, + { + "selector": "request.method", + "operator": "eq", + "value": "GET" + } + ] } ], "actions": [ @@ -293,9 +304,13 @@ data: { "conditions": [ { - "selector": "request.path", - "operator": "eq", - "value": "/get" + "allOf": [ + { + "selector": "request.path", + "operator": "eq", + "value": "/get" + } + ] } ], "actions": [ diff --git a/utils/deploy/envoy-tls.yaml b/utils/deploy/envoy-tls.yaml index 86264f2e..2e46c9b5 100644 --- a/utils/deploy/envoy-tls.yaml +++ b/utils/deploy/envoy-tls.yaml @@ -166,9 +166,13 @@ data: { "conditions": [ { - "selector": "request.path", - "operator": "eq", - "value": "/get" + "allOf": [ + { + "selector": "request.path", + "operator": "eq", + "value": "/get" + } + ] } ], "actions": [ @@ -188,7 +192,6 @@ data: ], "rules": [ { - "conditions": [], "actions": [ { "extension": "limitador", @@ -214,9 +217,13 @@ data: { "conditions": [ { - "selector": "request.url_path", - "operator": "startswith", - "value": "/unknown-path" + "allOf": [ + { + "selector": "request.url_path", + "operator": "startswith", + "value": "/unknown-path" + } + ] } ], "actions": [ @@ -245,19 +252,23 @@ data: { "conditions": [ { - "selector": "request.url_path", - "operator": "startswith", - "value": "/get" - }, - { - "selector": "request.host", - "operator": "eq", - "value": "test.c.rlp.com" - }, - { - "selector": "request.method", - "operator": "eq", - "value": "GET" + "allOf": [ + { + "selector": "request.url_path", + "operator": "startswith", + "value": "/get" + }, + { + "selector": "request.host", + "operator": "eq", + "value": "test.c.rlp.com" + }, + { + "selector": "request.method", + "operator": "eq", + "value": "GET" + } + ] } ], "actions": [ @@ -302,9 +313,13 @@ data: { "conditions": [ { - "selector": "request.path", - "operator": "eq", - "value": "/get" + "allOf": [ + { + "selector": "request.path", + "operator": "eq", + "value": "/get" + } + ] } ], "actions": [