#[derive(Debug, Clone, PartialEq, Eq)]
enum ValidationMode {
Any,
All,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScopesValidator {
mode: ValidationMode,
required_scopes: Vec<String>,
}
impl ScopesValidator {
pub fn any(required_scopes: Vec<String>) -> Self {
Self {
mode: ValidationMode::Any,
required_scopes,
}
}
pub fn all(required_scopes: Vec<String>) -> Self {
Self {
mode: ValidationMode::All,
required_scopes,
}
}
pub fn valid_scopes(&self, token_scopes: &[String]) -> bool {
match self.mode {
ValidationMode::Any => {
token_scopes
.iter()
.any(|scope| self.required_scopes.contains(scope))
|| self.required_scopes.is_empty()
}
ValidationMode::All => self
.required_scopes
.iter()
.all(|scope| token_scopes.contains(scope)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn scopes(s: &[&str]) -> Vec<String> {
s.iter().map(|x| x.to_string()).collect()
}
#[test]
fn all_validator_requires_all_scopes() {
let validator = ScopesValidator::all(scopes(&["read", "write"]));
assert!(validator.valid_scopes(&scopes(&["read", "write", "delete"])));
assert!(validator.valid_scopes(&scopes(&["read", "write"])));
assert!(!validator.valid_scopes(&scopes(&["read"])));
assert!(!validator.valid_scopes(&scopes(&["write"])));
assert!(!validator.valid_scopes(&scopes(&[])));
}
#[test]
fn any_validator_requires_any_scope() {
let validator = ScopesValidator::any(scopes(&["read", "write"]));
assert!(validator.valid_scopes(&scopes(&["read"])));
assert!(validator.valid_scopes(&scopes(&["write"])));
assert!(validator.valid_scopes(&scopes(&["read", "other"])));
assert!(!validator.valid_scopes(&scopes(&["delete"])));
assert!(!validator.valid_scopes(&scopes(&["other", "another"])));
}
#[test]
fn empty_required_scopes_behavior() {
let any_validator = ScopesValidator::any(vec![]);
assert!(any_validator.valid_scopes(&scopes(&[])));
assert!(any_validator.valid_scopes(&scopes(&["any"])));
let all_validator = ScopesValidator::all(vec![]);
assert!(all_validator.valid_scopes(&scopes(&[])));
assert!(all_validator.valid_scopes(&scopes(&["any"])));
let non_empty = ScopesValidator::all(scopes(&["required"]));
assert!(!non_empty.valid_scopes(&scopes(&[])));
}
}