fix: custom http routes auth (#4835)

This commit is contained in:
HugoCasa
2024-12-02 22:16:58 +01:00
committed by GitHub
parent f373394bb2
commit a00345f111
2 changed files with 57 additions and 13 deletions

View File

@@ -6,7 +6,7 @@ use crate::{
run_flow_by_path_inner, run_script_by_path_inner, run_wait_result_flow_by_path_internal,
run_wait_result_script_by_path_internal, RunJobQuery,
},
users::{fetch_api_authed, OptAuthed},
users::{fetch_api_authed, AuthCache, OptTokened},
};
use axum::{
extract::{Path, Query},
@@ -20,7 +20,7 @@ use http::{HeaderMap, StatusCode};
use serde::{Deserialize, Serialize};
use sql_builder::{bind::Bind, SqlBuilder};
use sqlx::prelude::FromRow;
use std::collections::HashMap;
use std::{collections::HashMap, sync::Arc};
use tower_http::cors::CorsLayer;
use windmill_audit::{audit_ee::audit_log, ActionKind};
#[cfg(feature = "parquet")]
@@ -422,7 +422,8 @@ struct TriggerRoute {
async fn get_http_route_trigger(
route_path: &str,
opt_authed: Option<ApiAuthed>,
auth_cache: &Arc<AuthCache>,
token: Option<&String>,
db: &DB,
user_db: UserDB,
) -> error::Result<(TriggerRoute, String, HashMap<String, String>, ApiAuthed)> {
@@ -476,6 +477,13 @@ async fn get_http_route_trigger(
.collect();
let username_override = if trigger.requires_auth {
let opt_authed = if let Some(token) = token {
auth_cache
.get_authed(Some(trigger.workspace_id.clone()), token)
.await
} else {
None
};
if let Some(authed) = opt_authed {
// check that the user has access to the trigger
let mut tx = user_db.begin(&authed).await?;
@@ -517,19 +525,27 @@ async fn get_http_route_trigger(
async fn route_job(
Extension(db): Extension<DB>,
Extension(user_db): Extension<UserDB>,
Extension(auth_cache): Extension<Arc<AuthCache>>,
OptTokened { token }: OptTokened,
Path(route_path): Path<StripPath>,
OptAuthed(opt_authed): OptAuthed,
Query(query): Query<HashMap<String, String>>,
method: http::Method,
headers: HeaderMap,
mut args: PushArgsOwned,
) -> impl IntoResponse {
let route_path = route_path.to_path();
let (trigger, called_path, params, authed) =
match get_http_route_trigger(route_path, opt_authed, &db, user_db.clone()).await {
Ok(trigger) => trigger,
Err(e) => return e.into_response(),
};
let (trigger, called_path, params, authed) = match get_http_route_trigger(
route_path,
&auth_cache,
token.as_ref(),
&db,
user_db.clone(),
)
.await
{
Ok(trigger) => trigger,
Err(e) => return e.into_response(),
};
#[cfg(not(feature = "parquet"))]
if trigger.static_asset_config.is_some() {
@@ -653,7 +669,7 @@ async fn route_job(
authed,
db,
user_db,
trigger.workspace_id.clone(),
trigger.workspace_id.clone(),
StripPath(trigger.script_path.to_owned()),
run_query,
args,
@@ -667,7 +683,7 @@ async fn route_job(
run_query,
StripPath(trigger.script_path.to_owned()),
authed,
user_db,
user_db,
args,
trigger.workspace_id.clone(),
label_prefix,
@@ -681,7 +697,7 @@ async fn route_job(
authed,
db,
user_db,
trigger.workspace_id.clone(),
trigger.workspace_id.clone(),
StripPath(trigger.script_path.to_owned()),
run_query,
args,
@@ -695,7 +711,7 @@ async fn route_job(
run_query,
StripPath(trigger.script_path.to_owned()),
authed,
user_db,
user_db,
trigger.workspace_id.clone(),
args,
label_prefix,

View File

@@ -513,6 +513,10 @@ pub struct Tokened {
pub token: String,
}
pub struct OptTokened {
pub token: Option<String>,
}
struct BruteForceCounter {
counter: AtomicU64,
last_reset: AtomicI64,
@@ -570,6 +574,30 @@ where
}
}
#[async_trait]
impl<S> FromRequestParts<S> for OptTokened
where
S: Send + Sync,
{
type Rejection = (StatusCode, String);
async fn from_request_parts(
parts: &mut Parts,
state: &S,
) -> std::result::Result<Self, Self::Rejection> {
if parts.method == http::Method::OPTIONS {
return Ok(OptTokened { token: None });
};
let already_tokened = parts.extensions.get::<Tokened>();
if let Some(tokened) = already_tokened {
Ok(OptTokened { token: Some(tokened.token.clone()) })
} else {
let token_o = extract_token(parts, state).await;
Ok(OptTokened { token: token_o })
}
}
}
pub async fn maybe_refresh_folders(
path: &str,
w_id: &str,