(claims: ClaimsForValidation, options: &Validation)
| 249 | } |
| 250 | |
| 251 | pub(crate) fn validate(claims: ClaimsForValidation, options: &Validation) -> Result<()> { |
| 252 | for required_claim in &options.required_spec_claims { |
| 253 | let present = match required_claim.as_str() { |
| 254 | "exp" => matches!(claims.exp, TryParse::Parsed(_)), |
| 255 | "sub" => matches!(claims.sub, TryParse::Parsed(_)), |
| 256 | "iss" => matches!(claims.iss, TryParse::Parsed(_)), |
| 257 | "aud" => matches!(claims.aud, TryParse::Parsed(_)), |
| 258 | "nbf" => matches!(claims.nbf, TryParse::Parsed(_)), |
| 259 | _ => continue, |
| 260 | }; |
| 261 | |
| 262 | if !present { |
| 263 | return Err(new_error(ErrorKind::MissingRequiredClaim(required_claim.clone()))); |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | if options.validate_exp || options.validate_nbf { |
| 268 | let now = get_current_timestamp(); |
| 269 | |
| 270 | // Reject malformed exp/nbf claim when validation is enabled |
| 271 | if options.validate_exp && matches!(claims.exp, TryParse::FailedToParse) { |
| 272 | return Err(new_error(ErrorKind::InvalidClaimFormat("exp".to_string()))); |
| 273 | } |
| 274 | if options.validate_nbf && matches!(claims.nbf, TryParse::FailedToParse) { |
| 275 | return Err(new_error(ErrorKind::InvalidClaimFormat("nbf".to_string()))); |
| 276 | } |
| 277 | |
| 278 | if matches!(claims.exp, TryParse::Parsed(exp) if exp < options.reject_tokens_expiring_in_less_than) |
| 279 | { |
| 280 | return Err(new_error(ErrorKind::InvalidToken)); |
| 281 | } |
| 282 | |
| 283 | if matches!(claims.exp, TryParse::Parsed(exp) if options.validate_exp |
| 284 | && exp - options.reject_tokens_expiring_in_less_than < now - options.leeway) |
| 285 | { |
| 286 | return Err(new_error(ErrorKind::ExpiredSignature)); |
| 287 | } |
| 288 | |
| 289 | if matches!(claims.nbf, TryParse::Parsed(nbf) if options.validate_nbf && nbf > now + options.leeway) |
| 290 | { |
| 291 | return Err(new_error(ErrorKind::ImmatureSignature)); |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | if let (TryParse::Parsed(sub), Some(correct_sub)) = (claims.sub, options.sub.as_deref()) |
| 296 | && sub != correct_sub |
| 297 | { |
| 298 | return Err(new_error(ErrorKind::InvalidSubject)); |
| 299 | } |
| 300 | |
| 301 | match (claims.iss, options.iss.as_ref()) { |
| 302 | (TryParse::Parsed(Issuer::Single(iss)), Some(correct_iss)) |
| 303 | if !correct_iss.contains(&*iss) => |
| 304 | { |
| 305 | return Err(new_error(ErrorKind::InvalidIssuer)); |
| 306 | } |
| 307 | (TryParse::Parsed(Issuer::Multiple(iss)), Some(correct_iss)) |
| 308 | if !is_subset(correct_iss, &iss) => |
no test coverage detected