pub fn verify_destination(
destination: Option<&str>,
expected_url: &str,
is_signed: bool,
) -> Result<(), String> {
match destination {
Some(dest) => {
if urls_match(dest, expected_url) {
Ok(())
} else {
Err(format!(
"Destination '{}' does not match expected URL '{}'",
dest, expected_url
))
}
}
None => {
if is_signed {
Err("Destination is required when message is signed, but was absent".to_string())
} else {
Ok(())
}
}
}
}
fn urls_match(url_a: &str, url_b: &str) -> bool {
let a = url_a.trim_end_matches('/');
let b = url_b.trim_end_matches('/');
a == b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_matching_destination() {
assert!(verify_destination(
Some("https://sp.example.com/acs"),
"https://sp.example.com/acs",
true,
)
.is_ok());
}
#[test]
fn test_mismatching_destination() {
let result = verify_destination(
Some("https://sp.example.com/acs"),
"https://evil.example.com/acs",
true,
);
assert!(result.is_err());
assert!(result.unwrap_err().contains("does not match"));
}
#[test]
fn test_absent_destination_signed() {
let result = verify_destination(None, "https://sp.example.com/acs", true);
assert!(result.is_err());
assert!(result
.unwrap_err()
.contains("required when message is signed"));
}
#[test]
fn test_absent_destination_unsigned() {
assert!(verify_destination(None, "https://sp.example.com/acs", false).is_ok());
}
#[test]
fn test_trailing_slash_normalization() {
assert!(verify_destination(
Some("https://sp.example.com/acs/"),
"https://sp.example.com/acs",
true,
)
.is_ok());
}
#[test]
fn test_case_sensitive_path() {
let result = verify_destination(
Some("https://sp.example.com/ACS"),
"https://sp.example.com/acs",
true,
);
assert!(result.is_err());
}
#[test]
fn test_present_destination_matches_unsigned() {
assert!(verify_destination(
Some("https://sp.example.com/acs"),
"https://sp.example.com/acs",
false,
)
.is_ok());
}
#[test]
fn test_present_destination_mismatch_unsigned() {
let result = verify_destination(
Some("https://evil.com/acs"),
"https://sp.example.com/acs",
false,
);
assert!(result.is_err());
}
}