| 451 | } |
| 452 | |
| 453 | pub async fn validate_token( |
| 454 | &self, |
| 455 | token: &str, |
| 456 | expected_user: Option<&str>, |
| 457 | ) -> Result<ValidatedClaims, OidcError> { |
| 458 | // Fetch current OIDC configuration from system variables |
| 459 | let system_vars = self.adapter_client.get_system_vars().await; |
| 460 | let Some(issuer) = OIDC_ISSUER.get(system_vars.dyncfgs()) else { |
| 461 | return Err(OidcError::MissingIssuer); |
| 462 | }; |
| 463 | |
| 464 | let authentication_claim = OIDC_AUTHENTICATION_CLAIM.get(system_vars.dyncfgs()); |
| 465 | |
| 466 | let expected_audiences: Vec<String> = { |
| 467 | let audiences: Vec<String> = |
| 468 | serde_json::from_value(OIDC_AUDIENCE.get(system_vars.dyncfgs())) |
| 469 | .map_err(|_| OidcError::AudienceParseError)?; |
| 470 | |
| 471 | if audiences.is_empty() { |
| 472 | warn!( |
| 473 | "Audience validation skipped. It is discouraged \ |
| 474 | to skip audience validation since it allows anyone \ |
| 475 | with a JWT issued by the same issuer to authenticate." |
| 476 | ); |
| 477 | } |
| 478 | audiences |
| 479 | }; |
| 480 | |
| 481 | // Decode header to get key ID (kid) and the |
| 482 | // decoding algorithm |
| 483 | let header = jsonwebtoken::decode_header(token).map_err(|e| { |
| 484 | debug!("Failed to decode JWT header: {:?}", e); |
| 485 | OidcError::Jwt |
| 486 | })?; |
| 487 | |
| 488 | let kid = header.kid.ok_or(OidcError::MissingKid)?; |
| 489 | // Find the matching key from our set of cached keys. If not found, |
| 490 | // fetch the JWKS from the provider and cache the keys |
| 491 | let decoding_key = self.find_key(&kid, &issuer).await?; |
| 492 | |
| 493 | // Set up audience and issuer validation |
| 494 | let mut validation = jsonwebtoken::Validation::new(header.alg); |
| 495 | validation.set_issuer(&[&issuer]); |
| 496 | if !expected_audiences.is_empty() { |
| 497 | validation.set_audience(&expected_audiences); |
| 498 | } else { |
| 499 | validation.validate_aud = false; |
| 500 | } |
| 501 | |
| 502 | // Decode and validate the token |
| 503 | let token_data = jsonwebtoken::decode::<OidcClaims>(token, &(decoding_key.0), &validation) |
| 504 | .map_err(|e| match e.kind() { |
| 505 | jsonwebtoken::errors::ErrorKind::InvalidAudience => { |
| 506 | if !expected_audiences.is_empty() { |
| 507 | OidcError::InvalidAudience { |
| 508 | expected_audiences |
| 509 | } |
| 510 | } else { |