mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2025-09-10 12:35:03 +02:00
fix(auth): prevent token collisions and optimise lookups
Ensures access tokens are unique across both user and appservice tables to prevent authentication ambiguity and potential security issues. Changes: - On startup, automatically logout any user devices using tokens that conflict with appservice tokens (resolves in favour of appservices) and log a warning with affected user/device details - When creating new user tokens, check for conflicts with appservice tokens and generate a new token if a collision would occur - When registering new appservices, reject registration if the token is already in use by a user device - Use futures::select_ok to race token lookups concurrently for better performance (adapted from tuwunel commit 066097a8) This fix-forward approach resolves existing token collisions on startup whilst preventing new ones from being created, without breaking existing valid authentications. The find_token optimisation is adapted from tuwunel (matrix-construct/tuwunel) commit 066097a8: "Optimize user and appservice token queries" by Jason Volk.
This commit is contained in:
parent
e820551f62
commit
d1ebcfaf0b
3 changed files with 59 additions and 17 deletions
|
@ -5,6 +5,14 @@ use axum_extra::{
|
|||
typed_header::TypedHeaderRejectionReason,
|
||||
};
|
||||
use conduwuit::{Err, Error, Result, debug_error, err, warn};
|
||||
use futures::{
|
||||
TryFutureExt,
|
||||
future::{
|
||||
Either::{Left, Right},
|
||||
select_ok,
|
||||
},
|
||||
pin_mut,
|
||||
};
|
||||
use ruma::{
|
||||
CanonicalJsonObject, CanonicalJsonValue, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId,
|
||||
api::{
|
||||
|
@ -54,17 +62,7 @@ pub(super) async fn auth(
|
|||
| None => request.query.access_token.as_deref(),
|
||||
};
|
||||
|
||||
let token = if let Some(token) = token {
|
||||
match services.appservice.find_from_token(token).await {
|
||||
| Some(reg_info) => Token::Appservice(Box::new(reg_info)),
|
||||
| _ => match services.users.find_from_token(token).await {
|
||||
| Ok((user_id, device_id)) => Token::User((user_id, device_id)),
|
||||
| _ => Token::Invalid,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
Token::None
|
||||
};
|
||||
let token = find_token(services, token).await?;
|
||||
|
||||
if metadata.authentication == AuthScheme::None {
|
||||
match metadata {
|
||||
|
@ -342,3 +340,24 @@ async fn parse_x_matrix(request: &mut Request) -> Result<XMatrix> {
|
|||
|
||||
Ok(x_matrix)
|
||||
}
|
||||
|
||||
async fn find_token(services: &Services, token: Option<&str>) -> Result<Token> {
|
||||
let Some(token) = token else {
|
||||
return Ok(Token::None);
|
||||
};
|
||||
|
||||
let user_token = services.users.find_from_token(token).map_ok(Token::User);
|
||||
|
||||
let appservice_token = services
|
||||
.appservice
|
||||
.find_from_token(token)
|
||||
.map_ok(Box::new)
|
||||
.map_ok(Token::Appservice);
|
||||
|
||||
pin_mut!(user_token, appservice_token);
|
||||
match select_ok([Left(user_token), Right(appservice_token)]).await {
|
||||
| Err(e) if !e.is_not_found() => Err(e),
|
||||
| Ok((token, _)) => Ok(token),
|
||||
| _ => Ok(Token::Invalid),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue