#![cfg(feature = "biometric")]
use secure_identity::biometric::{
BiometricAuthResult, BiometricClass, BiometricPolicy, BiometricRejection, BiometricValidation,
CryptoBinding,
};
use security_events::event::EventOutcome;
use security_events::kind::EventKind;
#[test]
fn given_class3_biometric_with_crypto_binding_when_validated_then_accepted() {
let result = BiometricAuthResult {
biometric_class: BiometricClass::Class3,
crypto_binding: Some(CryptoBinding {
key_id: "key-001".to_string(),
enrollment_id: "enroll-abc".to_string(),
}),
device_credential_fallback: false,
};
let policy = BiometricPolicy::default();
let validation = policy.validate(&result, None);
assert_eq!(validation, BiometricValidation::Accepted);
}
#[test]
fn given_class1_biometric_when_policy_requires_class3_then_rejected_weak() {
let result = BiometricAuthResult {
biometric_class: BiometricClass::Class1,
crypto_binding: Some(CryptoBinding {
key_id: "key-001".to_string(),
enrollment_id: "enroll-abc".to_string(),
}),
device_credential_fallback: false,
};
let policy = BiometricPolicy::default();
let validation = policy.validate(&result, None);
assert_eq!(
validation,
BiometricValidation::Rejected(BiometricRejection::WeakBiometric)
);
let events = policy.validate_with_events(&result, None);
assert!(!events.is_empty());
assert_eq!(events[0].kind, EventKind::BiometricAuthFailure);
assert_eq!(events[0].outcome, EventOutcome::Blocked);
}
#[test]
fn given_biometric_without_crypto_binding_when_policy_requires_it_then_rejected() {
let result = BiometricAuthResult {
biometric_class: BiometricClass::Class3,
crypto_binding: None,
device_credential_fallback: false,
};
let policy = BiometricPolicy::default();
let validation = policy.validate(&result, None);
assert_eq!(
validation,
BiometricValidation::Rejected(BiometricRejection::NoCryptoBinding)
);
}
#[test]
fn given_stale_enrollment_id_when_enrollment_changed_then_rejected() {
let result = BiometricAuthResult {
biometric_class: BiometricClass::Class3,
crypto_binding: Some(CryptoBinding {
key_id: "key-001".to_string(),
enrollment_id: "enroll-old".to_string(),
}),
device_credential_fallback: false,
};
let policy = BiometricPolicy::default();
let validation = policy.validate(&result, Some("enroll-current"));
assert_eq!(
validation,
BiometricValidation::Rejected(BiometricRejection::EnrollmentChanged)
);
}
#[test]
fn given_device_credential_fallback_when_policy_allows_it_then_accepted() {
let result = BiometricAuthResult {
biometric_class: BiometricClass::Class3,
crypto_binding: Some(CryptoBinding {
key_id: "key-001".to_string(),
enrollment_id: "enroll-abc".to_string(),
}),
device_credential_fallback: true,
};
let policy = BiometricPolicy {
allow_device_credential: true,
..BiometricPolicy::default()
};
let validation = policy.validate(&result, None);
assert_eq!(validation, BiometricValidation::Accepted);
}
#[test]
fn given_device_credential_fallback_when_policy_disallows_it_then_rejected() {
let result = BiometricAuthResult {
biometric_class: BiometricClass::Class3,
crypto_binding: Some(CryptoBinding {
key_id: "key-001".to_string(),
enrollment_id: "enroll-abc".to_string(),
}),
device_credential_fallback: true,
};
let policy = BiometricPolicy {
allow_device_credential: false,
..BiometricPolicy::default()
};
let validation = policy.validate(&result, None);
assert_eq!(
validation,
BiometricValidation::Rejected(BiometricRejection::DeviceCredentialNotAllowed)
);
}
#[test]
fn given_class2_biometric_when_policy_allows_class2_then_accepted() {
let result = BiometricAuthResult {
biometric_class: BiometricClass::Class2,
crypto_binding: Some(CryptoBinding {
key_id: "key-001".to_string(),
enrollment_id: "enroll-abc".to_string(),
}),
device_credential_fallback: false,
};
let policy = BiometricPolicy {
minimum_class: BiometricClass::Class2,
..BiometricPolicy::default()
};
let validation = policy.validate(&result, None);
assert_eq!(validation, BiometricValidation::Accepted);
}
#[test]
fn given_matching_enrollment_id_when_validated_then_accepted() {
let result = BiometricAuthResult {
biometric_class: BiometricClass::Class3,
crypto_binding: Some(CryptoBinding {
key_id: "key-001".to_string(),
enrollment_id: "enroll-current".to_string(),
}),
device_credential_fallback: false,
};
let policy = BiometricPolicy::default();
let validation = policy.validate(&result, Some("enroll-current"));
assert_eq!(validation, BiometricValidation::Accepted);
}