OIDC directory: Fetch name and group claims from userinfo endpoint when missing from the JWT token

This commit is contained in:
Maurus Decimus
2026-07-05 11:02:35 +02:00
parent eb42a8272d
commit 448a0c1b08
2 changed files with 37 additions and 8 deletions

View File

@@ -13,15 +13,17 @@ If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If
## Fixed ## Fixed
- DANE: Treat DNSSEC `bogus` as a temporary failures to prevent downgrade attacks. - DANE: Treat DNSSEC `bogus` as a temporary failures to prevent downgrade attacks.
- OIDC: - OIDC provider:
- `ECDSA` private key support for `SEC1` format. - `ECDSA` private key support for `SEC1` format.
- Allow ports in `redirect_uri` for loopback addresses. - Allow ports in `redirect_uri` for loopback addresses.
- OIDC directory:
- Removing a user from all groups does not sync the changes correctly.
- Fetch `name` and `group` claims from userinfo endpoint when missing from the JWT token.
- PostgreSQL: Include error chain in error messages. - PostgreSQL: Include error chain in error messages.
- Prometheus: event counters are exported with incorrect metric names. - Prometheus: event counters are exported with incorrect metric names.
- Registry: Changing the type of an existing account from `user` to `group` panics. - Registry: Changing the type of an existing account from `user` to `group` panics.
- Masked emails: Return `UnknownRecipient` only for disabled or expired masked emails. - Masked emails: Return `UnknownRecipient` only for disabled or expired masked emails.
- IDN: `sanitize_email` rejects valid Punycode domains. - IDN: `sanitize_email` rejects valid Punycode domains.
- Directory: Removing a user from all groups does not sync the changes correctly.
- Auto-ban: IP block expiration ignores per-reason ban durations. - Auto-ban: IP block expiration ignores per-reason ban durations.
## [0.16.11] - 2026-06-25 ## [0.16.11] - 2026-06-25

View File

@@ -14,6 +14,7 @@ use jsonwebtoken::{
jwk::{self, JwkSet}, jwk::{self, JwkSet},
}; };
use reqwest::Client; use reqwest::Client;
use serde_json::Value;
use std::time::Instant; use std::time::Instant;
use std::{sync::Arc, time::Duration}; use std::{sync::Arc, time::Duration};
use trc::AuthEvent; use trc::AuthEvent;
@@ -77,12 +78,38 @@ impl OpenIdDirectory {
self.validate_scopes(&token_data.claims)?; self.validate_scopes(&token_data.claims)?;
let (email, claims) = if let Ok(email) = self.resolve_email(&token_data.claims) let mut claims = token_data.claims;
{ let jwt_email = self.resolve_email(&claims).ok();
(email, token_data.claims) let missing_profile = self
} else { .config
let claims = self.fetch_userinfo(token).await?; .claim_name
(self.resolve_email(&claims)?, claims) .as_ref()
.is_some_and(|claim| claims.get(claim).is_none())
|| self
.config
.claim_groups
.as_ref()
.is_some_and(|claim| claims.get(claim).is_none());
if jwt_email.is_none() || missing_profile {
match self.fetch_userinfo(token).await {
Ok(userinfo) => {
if let (Some(base), Value::Object(extra)) =
(claims.as_object_mut(), userinfo)
{
for (key, value) in extra {
base.entry(key).or_insert_with(|| value);
}
}
}
Err(err) if jwt_email.is_none() => return Err(err),
Err(_) => {}
}
}
let email = match jwt_email {
Some(email) => email,
None => self.resolve_email(&claims)?,
}; };
return self.build_account(email, &claims); return self.build_account(email, &claims);
} }