fix: token validation
This commit is contained in:
parent
37f244e46b
commit
844677cc27
2 changed files with 37 additions and 11 deletions
39
src/auth.rs
39
src/auth.rs
|
|
@ -10,10 +10,17 @@ pub struct Claims {
|
||||||
pub exp: usize,
|
pub exp: usize,
|
||||||
pub iat: usize,
|
pub iat: usize,
|
||||||
pub iss: String,
|
pub iss: String,
|
||||||
pub aud: String,
|
pub aud: Audience,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum Audience {
|
||||||
|
Single(String),
|
||||||
|
Multiple(Vec<String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
struct Jwk {
|
struct Jwk {
|
||||||
#[serde(rename = "kty")]
|
#[serde(rename = "kty")]
|
||||||
_kty: String,
|
_kty: String,
|
||||||
|
|
@ -31,13 +38,17 @@ struct Jwks {
|
||||||
|
|
||||||
pub struct JwksVerifier {
|
pub struct JwksVerifier {
|
||||||
issuer: String,
|
issuer: String,
|
||||||
|
audience: String,
|
||||||
jwks_uri: String,
|
jwks_uri: String,
|
||||||
keys: Arc<RwLock<Vec<Jwk>>>,
|
keys: Arc<RwLock<Vec<Jwk>>>,
|
||||||
client: Client,
|
client: Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JwksVerifier {
|
impl JwksVerifier {
|
||||||
pub async fn new(issuer: String) -> Result<Self, Box<dyn std::error::Error>> {
|
pub async fn new(
|
||||||
|
issuer: String,
|
||||||
|
audience: String,
|
||||||
|
) -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
// Authentik OIDC discovery
|
// Authentik OIDC discovery
|
||||||
let discovery_url = format!(
|
let discovery_url = format!(
|
||||||
|
|
@ -53,6 +64,7 @@ impl JwksVerifier {
|
||||||
|
|
||||||
let verifier = Self {
|
let verifier = Self {
|
||||||
issuer,
|
issuer,
|
||||||
|
audience,
|
||||||
jwks_uri,
|
jwks_uri,
|
||||||
keys: Arc::new(RwLock::new(Vec::new())),
|
keys: Arc::new(RwLock::new(Vec::new())),
|
||||||
client,
|
client,
|
||||||
|
|
@ -73,18 +85,29 @@ impl JwksVerifier {
|
||||||
let header = decode_header(token)?;
|
let header = decode_header(token)?;
|
||||||
let kid = header.kid.ok_or("Missing kid in token header")?;
|
let kid = header.kid.ok_or("Missing kid in token header")?;
|
||||||
|
|
||||||
|
let jwk = {
|
||||||
let keys = self.keys.read().await;
|
let keys = self.keys.read().await;
|
||||||
let jwk = keys
|
keys.iter().find(|k| k.kid == kid).cloned()
|
||||||
.iter()
|
};
|
||||||
|
|
||||||
|
let jwk = match jwk {
|
||||||
|
Some(key) => key,
|
||||||
|
None => {
|
||||||
|
self.refresh_keys().await?;
|
||||||
|
let keys = self.keys.read().await;
|
||||||
|
keys.iter()
|
||||||
.find(|k| k.kid == kid)
|
.find(|k| k.kid == kid)
|
||||||
.ok_or("Key not found in JWKS")?;
|
.cloned()
|
||||||
|
.ok_or("Key not found in JWKS")?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let decoding_key = DecodingKey::from_rsa_components(&jwk.n, &jwk.e)?;
|
let decoding_key = DecodingKey::from_rsa_components(&jwk.n, &jwk.e)?;
|
||||||
|
|
||||||
let mut validation = Validation::new(Algorithm::RS256);
|
let mut validation = Validation::new(Algorithm::RS256);
|
||||||
validation.set_issuer(&[self.issuer.clone()]);
|
validation.set_issuer(&[self.issuer.clone()]);
|
||||||
// Aud validation might need careful config, usually it's the client_id
|
validation.set_audience(&[self.audience.clone()]);
|
||||||
validation.validate_aud = false;
|
validation.validate_aud = true;
|
||||||
|
|
||||||
let token_data = decode::<Claims>(token, &decoding_key, &validation)?;
|
let token_data = decode::<Claims>(token, &decoding_key, &validation)?;
|
||||||
Ok(token_data.claims)
|
Ok(token_data.claims)
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,10 @@ pub async fn start(db_url: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let authentik_client_secret =
|
let authentik_client_secret =
|
||||||
std::env::var("AUTHENTIK_CLIENT_SECRET").map_err(|_| "AUTHENTIK_CLIENT_SECRET not set")?;
|
std::env::var("AUTHENTIK_CLIENT_SECRET").map_err(|_| "AUTHENTIK_CLIENT_SECRET not set")?;
|
||||||
|
|
||||||
let verifier = Arc::new(crate::auth::JwksVerifier::new(authentik_issuer.clone()).await?);
|
let verifier = Arc::new(
|
||||||
|
crate::auth::JwksVerifier::new(authentik_issuer.clone(), authentik_client_id.clone())
|
||||||
|
.await?,
|
||||||
|
);
|
||||||
let authenticator = Arc::new(
|
let authenticator = Arc::new(
|
||||||
crate::auth::Authenticator::new(
|
crate::auth::Authenticator::new(
|
||||||
authentik_issuer,
|
authentik_issuer,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue