Skip to content

Commit

Permalink
Merge pull request #125 from bulwark-security/maliz-add-outcome-to-he…
Browse files Browse the repository at this point in the history
…ader

add outcome to header
  • Loading branch information
maliz-bulwark authored Aug 22, 2023
2 parents 238aa2f + 3d24f6f commit 690797d
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 29 deletions.
69 changes: 44 additions & 25 deletions crates/ext-processor/src/headers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use bulwark_wasm_sdk::Decision;
use bulwark_wasm_sdk::{Decision, Outcome};
use sfv::{BareItem, Decimal, Dictionary, FromPrimitive, Item, List, ListEntry, SerializeValue};

// TODO: capture the entire outcome: accepted/suspicious/restricted + threshold values
Expand All @@ -7,6 +7,7 @@ use sfv::{BareItem, Decimal, Dictionary, FromPrimitive, Item, List, ListEntry, S
/// Serialize a combined [`Decision`] into a [SFV](sfv) header value to be sent with the request to the interior service.
pub(crate) fn serialize_decision_sfv(
decision: Decision,
outcome: Outcome,
) -> std::result::Result<String, &'static str> {
let accept_value = Item::new(BareItem::Decimal(
Decimal::from_f64(decision.accept).unwrap(),
Expand All @@ -17,11 +18,17 @@ pub(crate) fn serialize_decision_sfv(
let unknown_value = Item::new(BareItem::Decimal(
Decimal::from_f64(decision.unknown).unwrap(),
));
let score_value = Item::new(BareItem::Decimal(
Decimal::from_f64(decision.pignistic().restrict).unwrap(),
));
let outcome_value = Item::new(BareItem::String(outcome.to_string()));

let mut dict = Dictionary::new();
dict.insert("accept".into(), accept_value.into());
dict.insert("restrict".into(), restrict_value.into());
dict.insert("unknown".into(), unknown_value.into());
dict.insert("score".into(), score_value.into());
dict.insert("outcome".into(), outcome_value.into());

dict.serialize_value()
}
Expand All @@ -43,36 +50,48 @@ mod tests {
#[test]
fn test_serialize_decision_sfv() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(
serialize_decision_sfv(Decision {
accept: 0.0,
restrict: 0.0,
unknown: 1.0
})?,
"accept=0.0, restrict=0.0, unknown=1.0"
serialize_decision_sfv(
Decision {
accept: 0.0,
restrict: 0.0,
unknown: 1.0
},
Outcome::Accepted
)?,
"accept=0.0, restrict=0.0, unknown=1.0, score=0.5, outcome=\"accepted\""
);
assert_eq!(
serialize_decision_sfv(Decision {
accept: 0.0,
restrict: 1.0,
unknown: 0.0
})?,
"accept=0.0, restrict=1.0, unknown=0.0"
serialize_decision_sfv(
Decision {
accept: 0.0,
restrict: 1.0,
unknown: 0.0
},
Outcome::Restricted
)?,
"accept=0.0, restrict=1.0, unknown=0.0, score=1.0, outcome=\"restricted\""
);
assert_eq!(
serialize_decision_sfv(Decision {
accept: 1.0,
restrict: 0.0,
unknown: 0.0
})?,
"accept=1.0, restrict=0.0, unknown=0.0"
serialize_decision_sfv(
Decision {
accept: 1.0,
restrict: 0.0,
unknown: 0.0
},
Outcome::Trusted
)?,
"accept=1.0, restrict=0.0, unknown=0.0, score=0.0, outcome=\"trusted\""
);
assert_eq!(
serialize_decision_sfv(Decision {
accept: 0.333,
restrict: 0.333,
unknown: 0.333
})?,
"accept=0.333, restrict=0.333, unknown=0.333"
serialize_decision_sfv(
Decision {
accept: 0.333,
restrict: 0.333,
unknown: 0.333
},
Outcome::Accepted
)?,
"accept=0.333, restrict=0.333, unknown=0.333, score=0.500, outcome=\"accepted\""
);

Ok(())
Expand Down
9 changes: 5 additions & 4 deletions crates/ext-processor/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use {
DecisionComponents, ForwardedIP, Plugin, PluginExecutionError, PluginInstance,
PluginLoadError, RedisInfo, RequestContext, ScriptRegistry,
},
bulwark_wasm_sdk::{BodyChunk, Decision},
bulwark_wasm_sdk::{BodyChunk, Decision, Outcome},
envoy_control_plane::envoy::{
config::core::v3::{HeaderMap, HeaderValue, HeaderValueOption},
extensions::filters::http::ext_proc::v3::{processing_mode, ProcessingMode},
Expand Down Expand Up @@ -1023,7 +1023,7 @@ impl BulwarkProcessor {
| bulwark_wasm_sdk::Outcome::Accepted
// suspected requests are monitored but not rejected
| bulwark_wasm_sdk::Outcome::Suspected => {
let result = Self::allow_request(&sender, &decision_components, receive_request_body).await;
let result = Self::allow_request(&sender, &decision_components, &outcome, receive_request_body).await;
// TODO: must perform proper error handling on sender results, sending can fail
if let Err(err) = result {
debug!(message = format!("send error: {}", err));
Expand Down Expand Up @@ -1051,7 +1051,7 @@ impl BulwarkProcessor {
return;
} else {
// Don't receive a body when we would have otherwise blocked if we weren't in monitor-only mode
let result = Self::allow_request(&sender, &decision_components, false).await;
let result = Self::allow_request(&sender, &decision_components, &outcome, false).await;
// TODO: must perform proper error handling on sender results, sending can fail
if let Err(err) = result {
debug!(message = format!("send error: {}", err));
Expand Down Expand Up @@ -1486,14 +1486,15 @@ impl BulwarkProcessor {
async fn allow_request(
mut sender: &UnboundedSender<Result<ProcessingResponse, tonic::Status>>,
decision_components: &DecisionComponents,
decision_outcome: &Outcome,
receive_request_body: bool,
) -> Result<(), ProcessingMessageError> {
// Send back a response that changes the request header for the HTTP target.
let mut req_headers_cr = CommonResponse::default();
Self::add_set_header(
&mut req_headers_cr,
"Bulwark-Decision",
&serialize_decision_sfv(decision_components.decision)
&serialize_decision_sfv(decision_components.decision, decision_outcome.to_owned())
.map_err(|err| SfvError::Serialization(err.to_string()))?,
);
if !decision_components.tags.is_empty() {
Expand Down

0 comments on commit 690797d

Please sign in to comment.