From c4229509d93e0e1c0df3a586b2b7425b21f2b9a5 Mon Sep 17 00:00:00 2001 From: lafleur Date: Tue, 12 Aug 2025 02:31:40 +0200 Subject: [PATCH] add services::oidc::user_and_device_from_token(), use in auth --- src/api/client/oidc/authorize.rs | 2 +- src/service/oidc/mod.rs | 41 +++++++++++++++++++++++++++++--- src/service/users/mod.rs | 10 ++++++-- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/api/client/oidc/authorize.rs b/src/api/client/oidc/authorize.rs index 21d3bad6..a0743fc1 100644 --- a/src/api/client/oidc/authorize.rs +++ b/src/api/client/oidc/authorize.rs @@ -46,7 +46,7 @@ pub(crate) async fn authorize( tracing::debug!("submitting OIDC authorisation for token : {token:#?}"); // Get the user id from the token and add it to the query. - let (owner_id, _) = services.oidc.get_user_for_token(token)?; + let (owner_id, _) = services.oidc.user_and_device_from_token(token)?; let mut query_with_user_id = query.clone(); query_with_user_id.username = Some(owner_id.localpart().to_string()); diff --git a/src/service/oidc/mod.rs b/src/service/oidc/mod.rs index 7cee2026..14b8ac0e 100644 --- a/src/service/oidc/mod.rs +++ b/src/service/oidc/mod.rs @@ -12,10 +12,11 @@ pub mod registrar; use std::sync::{Arc, Mutex}; use async_trait::async_trait; -use conduwuit::Result; +use conduwuit::{Result, err}; use oxide_auth::{ frontends::simple::endpoint::{Generic, Vacant}, primitives::{ + grant::Grant, prelude::{ AuthMap, Authorizer, Client, Issuer, RandomGenerator, Registrar, TokenMap, }, @@ -23,16 +24,24 @@ use oxide_auth::{ }, }; use registrar::ClientMap; +use ruma::{OwnedDeviceId, OwnedUserId, UserId}; + +use crate::{globals, Dep}; + +struct Services { + globals: Dep, +} pub struct Service { registrar: Mutex, authorizer: Mutex>, issuer: Mutex>, + services: Services, } #[async_trait] impl crate::Service for Service { - fn build(_args: crate::Args<'_>) -> Result> { Ok(Arc::new(Self::preconfigured())) } + fn build(args: crate::Args<'_>) -> Result> { Ok(Arc::new(Self::preconfigured(args))) } fn name(&self) -> &str { crate::service::make_name(std::module_path!()) } } @@ -48,7 +57,7 @@ impl Service { } #[must_use] - pub fn preconfigured() -> Self { + pub(crate) fn preconfigured(args: crate::Args<'_>) -> Self { Self { registrar: Mutex::new( vec![Client::public( @@ -70,9 +79,35 @@ impl Service { // be read and parsed by anyone, but not maliciously created. However, they can not be // revoked and thus don't offer even longer lived refresh tokens. issuer: Mutex::new(TokenMap::new(RandomGenerator::new(16))), + services: Services { + globals: args.depend::("globals"), + }, } } + fn grant_from_token(&self, token: &str) -> Option { + let issuer = self.issuer.lock().expect("lockable issuer"); + + issuer.recover_token(token).expect("infallible recover_token implementation") + } + + pub fn user_and_device_from_token(&self, token: &str) -> Result<(OwnedUserId, OwnedDeviceId)> { + let Some(Grant { owner_id, client_id, .. }) = self.grant_from_token(token) else { + return Err(err!(Request(MissingToken("unknown token: {token:?}")))); + }; + let server_name = self.services.globals.server_name(); + let owner_id = UserId::parse_with_server_name(owner_id.clone(), server_name) + .map_err(|err| + err!(Request(InvalidUsername("invalid username {owner_id:?}: {err}"))) + )?; + let device_id = OwnedDeviceId::try_from(client_id.clone()) + .map_err(|err| + err!(Request(InvalidParam("invalid client_id {client_id:?}: {err}"))) + )?; + + Ok((owner_id, device_id)) + } + /// The oxide-auth carry-all endpoint. pub fn endpoint( &self, diff --git a/src/service/users/mod.rs b/src/service/users/mod.rs index d2dfccd9..3a545d39 100644 --- a/src/service/users/mod.rs +++ b/src/service/users/mod.rs @@ -19,7 +19,7 @@ use ruma::{ use serde::{Deserialize, Serialize}; use serde_json::json; -use crate::{Dep, account_data, admin, globals, rooms}; +use crate::{account_data, admin, globals, oidc, rooms, Dep}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct UserSuspension { @@ -40,6 +40,7 @@ struct Services { server: Arc, account_data: Dep, admin: Dep, + oidc: Dep, globals: Dep, state_accessor: Dep, state_cache: Dep, @@ -76,6 +77,7 @@ impl crate::Service for Service { server: args.server.clone(), account_data: args.depend::("account_data"), admin: args.depend::("admin"), + oidc: args.depend::("oidc"), globals: args.depend::("globals"), state_accessor: args .depend::("rooms::state_accessor"), @@ -224,7 +226,11 @@ impl Service { /// Find out which user an access token belongs to. pub async fn find_from_token(&self, token: &str) -> Result<(OwnedUserId, OwnedDeviceId)> { - self.db.token_userdeviceid.get(token).await.deserialized() + if self.services.server.config.auth.as_ref().is_some_and(|auth| auth.enable_oidc_login) { + self.services.oidc.user_and_device_from_token(token) + } else { + self.db.token_userdeviceid.get(token).await.deserialized() + } } /// Returns an iterator over all users on this homeserver (offered for