use opensaml::binding::{base64_decode, deflate_raw_decode, deflate_raw_encode};
use opensaml::context::is_valid_xml;
use opensaml::xml::{extract, ExtractorField};
fn lcg(seed: &mut u64) -> u8 {
*seed = seed
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
(*seed >> 33) as u8
}
#[test]
fn malformed_xml_inputs_never_panic() {
let nasty = [
"",
" ",
"<",
"<a",
"<a>",
"<a></b>",
"<!DOCTYPE x [<!ENTITY e \"x\">]><x/>",
"<a>&undefined;</a>",
"<a><a><a></a></a>",
"not xml at all",
"<?xml?>",
"<a x=>",
"<a x=\"unclosed>",
"<a><![CDATA[unterminated",
"<a><!-- unterminated",
"<a:b xmlns:a=\"urn:x\"/>",
"<\u{0}\u{0}/>",
"<삼성>x</삼성>",
"<a>\u{1}\u{2}\u{3}</a>",
];
let fields = [
ExtractorField::new("x", &["a"]),
ExtractorField::new("r", &["Response", "Assertion"]).with_context(),
];
for input in nasty {
let _ = is_valid_xml(input);
let _ = extract(input, &fields);
}
}
#[test]
fn pseudo_random_inputs_never_panic() {
let mut seed = 0x0123_4567_89ab_cdefu64;
let fields = [ExtractorField::new(
"x",
&["Response", "Assertion", "Subject"],
)];
for _ in 0..1000 {
let len = (lcg(&mut seed) % 128) as usize;
let mut s = String::with_capacity(len);
for _ in 0..len {
let b = match lcg(&mut seed) % 8 {
0 => b'<',
1 => b'>',
2 => b'/',
3 => b'"',
4 => b'&',
_ => b'!' + (lcg(&mut seed) % 90),
};
s.push(b as char);
}
let _ = is_valid_xml(&s);
let _ = extract(&s, &fields);
}
}
#[test]
fn moderately_deep_nesting_does_not_overflow() {
let deep = format!("{}{}", "<a>".repeat(800), "</a>".repeat(800));
let _ = is_valid_xml(&deep);
let _ = extract(&deep, &[ExtractorField::new("a", &["a"])]);
}
#[test]
fn malformed_base64_errors() {
assert!(base64_decode("@@@ not base64 @@@").is_err());
}
#[test]
fn deflate_roundtrips_for_arbitrary_bytes() -> Result<(), Box<dyn std::error::Error>> {
let mut seed = 0xdead_beef_u64;
for len in [0usize, 1, 7, 64, 1000, 4096] {
let data: Vec<u8> = (0..len).map(|_| lcg(&mut seed)).collect();
let restored = deflate_raw_decode(&deflate_raw_encode(&data)?)?;
assert_eq!(restored, data);
}
Ok(())
}