This commit is contained in:
2025-11-11 15:18:06 +01:00
parent 7f371b2ab6
commit 1ee3d1cc5e
4 changed files with 27 additions and 11 deletions
+22 -5
View File
@@ -11,6 +11,7 @@ use axum::{
extract::FromRequestParts, extract::FromRequestParts,
http::{request::Parts, StatusCode}, http::{request::Parts, StatusCode},
}; };
use diesel::{pg::PgConnection, prelude::*};
use axum_extra::headers::{authorization::Bearer, Authorization}; use axum_extra::headers::{authorization::Bearer, Authorization};
use axum_extra::TypedHeader; use axum_extra::TypedHeader;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -20,6 +21,7 @@ use crate::{
auth::capability_sets::{load_capabilities_for_set, load_capability_set}, auth::capability_sets::{load_capabilities_for_set, load_capability_set},
error::{AppError, AppResult}, error::{AppError, AppResult},
models::{ApiCapability, TenantStatus}, models::{ApiCapability, TenantStatus},
schema::tenants::dsl as tenant_dsl,
state::{AppState, PgPooledConnection}, state::{AppState, PgPooledConnection},
}; };
use uuid::Uuid; use uuid::Uuid;
@@ -136,9 +138,7 @@ impl FromRequestParts<AppState> for TenantScopedConn {
async move { async move {
let user = AuthenticatedUser::from_request_parts(parts, &state).await?; let user = AuthenticatedUser::from_request_parts(parts, &state).await?;
let tenant_id = user.tenant_id; let tenant_id = user.tenant_id;
ensure_active_tenant(&state, tenant_id)?; let mut conn = if let Some(holder) = parts.extensions.remove::<TenantConnectionHolder>() {
let conn = if let Some(holder) = parts.extensions.remove::<TenantConnectionHolder>() {
holder holder
.into_conn() .into_conn()
.ok_or_else(|| AppError::internal("tenant connection unavailable"))? .ok_or_else(|| AppError::internal("tenant connection unavailable"))?
@@ -146,6 +146,8 @@ impl FromRequestParts<AppState> for TenantScopedConn {
state.db_for_tenant(tenant_id)? state.db_for_tenant(tenant_id)?
}; };
ensure_active_tenant_with_conn(&mut conn, tenant_id)?;
Ok(Self { Ok(Self {
conn, conn,
tenant_id, tenant_id,
@@ -157,9 +159,24 @@ impl FromRequestParts<AppState> for TenantScopedConn {
} }
pub(crate) fn ensure_active_tenant(state: &AppState, tenant_id: Uuid) -> AppResult<()> { pub(crate) fn ensure_active_tenant(state: &AppState, tenant_id: Uuid) -> AppResult<()> {
let tenant = state.tenants.get_by_id(tenant_id)?; let mut conn = state.db_unscoped()?;
if tenant.status != TenantStatus::Active { ensure_active_tenant_with_conn(&mut conn, tenant_id)
}
pub(crate) fn ensure_active_tenant_with_conn(
conn: &mut PgConnection,
tenant_id: Uuid,
) -> AppResult<()> {
use tenant_dsl::tenants;
let status: TenantStatus = tenants
.find(tenant_id)
.select(tenant_dsl::status)
.first(conn)?;
if status != TenantStatus::Active {
return Err(AppError::new(StatusCode::FORBIDDEN, "tenant is not active")); return Err(AppError::new(StatusCode::FORBIDDEN, "tenant is not active"));
} }
Ok(()) Ok(())
} }
+2 -3
View File
@@ -14,7 +14,7 @@ use tracing::{error, info};
use utoipa::{IntoParams, ToSchema}; use utoipa::{IntoParams, ToSchema};
use uuid::Uuid; use uuid::Uuid;
use crate::auth::{ensure_active_tenant, jwt::DownloadSubject, TenantScopedConn}; use crate::auth::{ensure_active_tenant_with_conn, jwt::DownloadSubject, TenantScopedConn};
use crate::documents::asset::{ use crate::documents::asset::{
asset_object_disposition, DocumentAssetDetailResponse, DocumentAssetResponse, asset_object_disposition, DocumentAssetDetailResponse, DocumentAssetResponse,
DocumentVersionDetailResponse, DocumentVersionResponse, DocumentVersionDetailResponse, DocumentVersionResponse,
@@ -575,9 +575,8 @@ pub async fn download_with_token(
.verify_download_token(&token) .verify_download_token(&token)
.map_err(|_| AppError::unauthorized())?; .map_err(|_| AppError::unauthorized())?;
ensure_active_tenant(&state, claims.tenant_id)?;
let mut conn = state.db_for_tenant(claims.tenant_id)?; let mut conn = state.db_for_tenant(claims.tenant_id)?;
ensure_active_tenant_with_conn(&mut conn, claims.tenant_id)?;
let now = Utc::now().naive_utc(); let now = Utc::now().naive_utc();
let has_active_refresh: bool = select(exists( let has_active_refresh: bool = select(exists(
+2 -2
View File
@@ -18,7 +18,7 @@ use uuid::Uuid;
use crate::auth::{ use crate::auth::{
api_tokens::{find_active_token_by_secret, touch_api_token}, api_tokens::{find_active_token_by_secret, touch_api_token},
ensure_active_tenant, ensure_active_tenant_with_conn,
}; };
use crate::error::{AppError, AppResult}; use crate::error::{AppError, AppResult};
use crate::models::{ApiCapability, Document, DocumentVersion, Folder, User}; use crate::models::{ApiCapability, Document, DocumentVersion, Folder, User};
@@ -486,7 +486,7 @@ fn authenticate(state: &AppState, headers: &HeaderMap) -> Result<Option<WebDavCo
} }
}; };
if let Err(err) = ensure_active_tenant(state, tenant_id) { if let Err(err) = ensure_active_tenant_with_conn(&mut conn, tenant_id) {
tracing::warn!(tenant_id = %tenant_id, error = ?err, "webdav tenant not active"); tracing::warn!(tenant_id = %tenant_id, error = ?err, "webdav tenant not active");
return Ok(None); return Ok(None);
} }
+1 -1
View File
@@ -689,7 +689,7 @@ impl<'a> AuthService<'a> {
user: &User, user: &User,
tenant_id: Uuid, tenant_id: Uuid,
) -> AppResult<Response> { ) -> AppResult<Response> {
crate::auth::ensure_active_tenant(&self.state, tenant_id)?; crate::auth::ensure_active_tenant_with_conn(conn, tenant_id)?;
apply_tenant_guc(conn, tenant_id)?; apply_tenant_guc(conn, tenant_id)?;
clear_user_guc(conn)?; clear_user_guc(conn)?;
clear_user_session_hash(conn)?; clear_user_session_hash(conn)?;