You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-11-20 12:02:22 +03:00
storage: Load with less joins
This is done to simplify some queries, to avoid loading more data than necessary, and in preparation of a proper cache layer
This commit is contained in:
@@ -26,7 +26,8 @@ use mas_storage::{
|
||||
oauth2::{
|
||||
access_token::lookup_active_access_token, refresh_token::lookup_active_refresh_token,
|
||||
},
|
||||
Clock,
|
||||
user::{BrowserSessionRepository, UserRepository},
|
||||
Clock, Repository,
|
||||
};
|
||||
use oauth2_types::{
|
||||
errors::{ClientError, ClientErrorCode},
|
||||
@@ -171,16 +172,23 @@ pub(crate) async fn post(
|
||||
.await?
|
||||
.ok_or(RouteError::UnknownToken)?;
|
||||
|
||||
let browser_session = conn
|
||||
.browser_session()
|
||||
.lookup(session.user_session_id)
|
||||
.await?
|
||||
// XXX: is that the right error to bubble up?
|
||||
.ok_or(RouteError::UnknownToken)?;
|
||||
|
||||
IntrospectionResponse {
|
||||
active: true,
|
||||
scope: Some(session.scope),
|
||||
client_id: Some(session.client.client_id),
|
||||
username: Some(session.browser_session.user.username),
|
||||
client_id: Some(session.client_id.to_string()),
|
||||
username: Some(browser_session.user.username),
|
||||
token_type: Some(OAuthTokenTypeHint::AccessToken),
|
||||
exp: Some(token.expires_at),
|
||||
iat: Some(token.created_at),
|
||||
nbf: Some(token.created_at),
|
||||
sub: Some(session.browser_session.user.sub),
|
||||
sub: Some(browser_session.user.sub),
|
||||
aud: None,
|
||||
iss: None,
|
||||
jti: None,
|
||||
@@ -191,16 +199,23 @@ pub(crate) async fn post(
|
||||
.await?
|
||||
.ok_or(RouteError::UnknownToken)?;
|
||||
|
||||
let browser_session = conn
|
||||
.browser_session()
|
||||
.lookup(session.user_session_id)
|
||||
.await?
|
||||
// XXX: is that the right error to bubble up?
|
||||
.ok_or(RouteError::UnknownToken)?;
|
||||
|
||||
IntrospectionResponse {
|
||||
active: true,
|
||||
scope: Some(session.scope),
|
||||
client_id: Some(session.client.client_id),
|
||||
username: Some(session.browser_session.user.username),
|
||||
client_id: Some(session.client_id.to_string()),
|
||||
username: Some(browser_session.user.username),
|
||||
token_type: Some(OAuthTokenTypeHint::RefreshToken),
|
||||
exp: None,
|
||||
iat: Some(token.created_at),
|
||||
nbf: Some(token.created_at),
|
||||
sub: Some(session.browser_session.user.sub),
|
||||
sub: Some(browser_session.user.sub),
|
||||
aud: None,
|
||||
iss: None,
|
||||
jti: None,
|
||||
@@ -211,6 +226,13 @@ pub(crate) async fn post(
|
||||
.await?
|
||||
.ok_or(RouteError::UnknownToken)?;
|
||||
|
||||
let user = conn
|
||||
.user()
|
||||
.lookup(session.user_id)
|
||||
.await?
|
||||
// XXX: is that the right error to bubble up?
|
||||
.ok_or(RouteError::UnknownToken)?;
|
||||
|
||||
let device_scope = session.device.to_scope_token();
|
||||
let scope = [API_SCOPE, device_scope].into_iter().collect();
|
||||
|
||||
@@ -218,12 +240,12 @@ pub(crate) async fn post(
|
||||
active: true,
|
||||
scope: Some(scope),
|
||||
client_id: Some("legacy".into()),
|
||||
username: Some(session.user.username),
|
||||
username: Some(user.username),
|
||||
token_type: Some(OAuthTokenTypeHint::AccessToken),
|
||||
exp: token.expires_at,
|
||||
iat: Some(token.created_at),
|
||||
nbf: Some(token.created_at),
|
||||
sub: Some(session.user.sub),
|
||||
sub: Some(user.sub),
|
||||
aud: None,
|
||||
iss: None,
|
||||
jti: None,
|
||||
@@ -235,6 +257,13 @@ pub(crate) async fn post(
|
||||
.await?
|
||||
.ok_or(RouteError::UnknownToken)?;
|
||||
|
||||
let user = conn
|
||||
.user()
|
||||
.lookup(session.user_id)
|
||||
.await?
|
||||
// XXX: is that the right error to bubble up?
|
||||
.ok_or(RouteError::UnknownToken)?;
|
||||
|
||||
let device_scope = session.device.to_scope_token();
|
||||
let scope = [API_SCOPE, device_scope].into_iter().collect();
|
||||
|
||||
@@ -242,12 +271,12 @@ pub(crate) async fn post(
|
||||
active: true,
|
||||
scope: Some(scope),
|
||||
client_id: Some("legacy".into()),
|
||||
username: Some(session.user.username),
|
||||
username: Some(user.username),
|
||||
token_type: Some(OAuthTokenTypeHint::RefreshToken),
|
||||
exp: None,
|
||||
iat: Some(refresh_token.created_at),
|
||||
nbf: Some(refresh_token.created_at),
|
||||
sub: Some(session.user.sub),
|
||||
sub: Some(user.sub),
|
||||
aud: None,
|
||||
iss: None,
|
||||
jti: None,
|
||||
|
||||
@@ -31,11 +31,15 @@ use mas_jose::{
|
||||
};
|
||||
use mas_keystore::{Encrypter, Keystore};
|
||||
use mas_router::UrlBuilder;
|
||||
use mas_storage::oauth2::{
|
||||
access_token::{add_access_token, revoke_access_token},
|
||||
authorization_grant::{exchange_grant, lookup_grant_by_code},
|
||||
end_oauth_session,
|
||||
refresh_token::{add_refresh_token, consume_refresh_token, lookup_active_refresh_token},
|
||||
use mas_storage::{
|
||||
oauth2::{
|
||||
access_token::{add_access_token, revoke_access_token},
|
||||
authorization_grant::{exchange_grant, lookup_grant_by_code},
|
||||
end_oauth_session,
|
||||
refresh_token::{add_refresh_token, consume_refresh_token, lookup_active_refresh_token},
|
||||
},
|
||||
user::BrowserSessionRepository,
|
||||
Repository,
|
||||
};
|
||||
use oauth2_types::{
|
||||
errors::{ClientError, ClientErrorCode},
|
||||
@@ -102,12 +106,15 @@ pub(crate) enum RouteError {
|
||||
|
||||
#[error("no suitable key found for signing")]
|
||||
InvalidSigningKey,
|
||||
|
||||
#[error("failed to load browser session")]
|
||||
NoSuchBrowserSession,
|
||||
}
|
||||
|
||||
impl IntoResponse for RouteError {
|
||||
fn into_response(self) -> axum::response::Response {
|
||||
match self {
|
||||
Self::Internal(_) | Self::InvalidSigningKey => (
|
||||
Self::Internal(_) | Self::InvalidSigningKey | Self::NoSuchBrowserSession => (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(ClientError::from(ClientErrorCode::ServerError)),
|
||||
),
|
||||
@@ -253,7 +260,7 @@ async fn authorization_code_grant(
|
||||
// This should never happen, since we looked up in the database using the code
|
||||
let code = authz_grant.code.as_ref().ok_or(RouteError::InvalidGrant)?;
|
||||
|
||||
if client.client_id != session.client.client_id {
|
||||
if client.id != session.client_id {
|
||||
return Err(RouteError::UnauthorizedClient);
|
||||
}
|
||||
|
||||
@@ -267,7 +274,11 @@ async fn authorization_code_grant(
|
||||
}
|
||||
};
|
||||
|
||||
let browser_session = &session.browser_session;
|
||||
let browser_session = txn
|
||||
.browser_session()
|
||||
.lookup(session.user_session_id)
|
||||
.await?
|
||||
.ok_or(RouteError::NoSuchBrowserSession)?;
|
||||
|
||||
let ttl = Duration::minutes(5);
|
||||
let access_token_str = TokenType::AccessToken.generate(&mut rng);
|
||||
@@ -357,7 +368,7 @@ async fn refresh_token_grant(
|
||||
.await?
|
||||
.ok_or(RouteError::InvalidGrant)?;
|
||||
|
||||
if client.client_id != session.client.client_id {
|
||||
if client.id != session.client_id {
|
||||
// As per https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
|
||||
return Err(RouteError::InvalidGrant);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,11 @@ use mas_jose::{
|
||||
};
|
||||
use mas_keystore::Keystore;
|
||||
use mas_router::UrlBuilder;
|
||||
use mas_storage::{user::UserEmailRepository, Repository};
|
||||
use mas_storage::{
|
||||
oauth2::client::OAuth2ClientRepository,
|
||||
user::{BrowserSessionRepository, UserEmailRepository},
|
||||
Repository,
|
||||
};
|
||||
use oauth2_types::scope;
|
||||
use serde::Serialize;
|
||||
use serde_with::skip_serializing_none;
|
||||
@@ -64,6 +68,12 @@ pub enum RouteError {
|
||||
|
||||
#[error("no suitable key found for signing")]
|
||||
InvalidSigningKey,
|
||||
|
||||
#[error("failed to load client")]
|
||||
NoSuchClient,
|
||||
|
||||
#[error("failed to load browser session")]
|
||||
NoSuchBrowserSession,
|
||||
}
|
||||
|
||||
impl_from_error_for_route!(sqlx::Error);
|
||||
@@ -74,7 +84,10 @@ impl_from_error_for_route!(mas_jose::jwt::JwtSignatureError);
|
||||
impl IntoResponse for RouteError {
|
||||
fn into_response(self) -> axum::response::Response {
|
||||
match self {
|
||||
Self::Internal(_) | Self::InvalidSigningKey => {
|
||||
Self::Internal(_)
|
||||
| Self::InvalidSigningKey
|
||||
| Self::NoSuchClient
|
||||
| Self::NoSuchBrowserSession => {
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, self.to_string()).into_response()
|
||||
}
|
||||
Self::AuthorizationVerificationError(_e) => StatusCode::UNAUTHORIZED.into_response(),
|
||||
@@ -93,7 +106,13 @@ pub async fn get(
|
||||
|
||||
let session = user_authorization.protected(&mut conn).await?;
|
||||
|
||||
let user = session.browser_session.user;
|
||||
let browser_session = conn
|
||||
.browser_session()
|
||||
.lookup(session.user_session_id)
|
||||
.await?
|
||||
.ok_or(RouteError::NoSuchBrowserSession)?;
|
||||
|
||||
let user = browser_session.user;
|
||||
|
||||
let user_email = if session.scope.contains(&scope::EMAIL) {
|
||||
conn.user_email().get_primary(&user).await?
|
||||
@@ -108,7 +127,13 @@ pub async fn get(
|
||||
email: user_email.map(|u| u.email),
|
||||
};
|
||||
|
||||
if let Some(alg) = session.client.userinfo_signed_response_alg {
|
||||
let client = conn
|
||||
.oauth2_client()
|
||||
.lookup(session.client_id)
|
||||
.await?
|
||||
.ok_or(RouteError::NoSuchClient)?;
|
||||
|
||||
if let Some(alg) = client.userinfo_signed_response_alg {
|
||||
let key = key_store
|
||||
.signing_key_for_algorithm(&alg)
|
||||
.ok_or(RouteError::InvalidSigningKey)?;
|
||||
@@ -119,7 +144,7 @@ pub async fn get(
|
||||
|
||||
let user_info = SignedUserInfo {
|
||||
iss: url_builder.oidc_issuer().to_string(),
|
||||
aud: session.client.client_id,
|
||||
aud: client.client_id,
|
||||
user_info,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user