diff --git a/backend/windmill-api/src/http_triggers.rs b/backend/windmill-api/src/http_triggers.rs index 685319e05a..ca03d5803c 100644 --- a/backend/windmill-api/src/http_triggers.rs +++ b/backend/windmill-api/src/http_triggers.rs @@ -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, + auth_cache: &Arc, + token: Option<&String>, db: &DB, user_db: UserDB, ) -> error::Result<(TriggerRoute, String, HashMap, 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, Extension(user_db): Extension, + Extension(auth_cache): Extension>, + OptTokened { token }: OptTokened, Path(route_path): Path, - OptAuthed(opt_authed): OptAuthed, Query(query): Query>, 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, diff --git a/backend/windmill-api/src/users.rs b/backend/windmill-api/src/users.rs index 0b12ddef27..8ea93f1073 100644 --- a/backend/windmill-api/src/users.rs +++ b/backend/windmill-api/src/users.rs @@ -513,6 +513,10 @@ pub struct Tokened { pub token: String, } +pub struct OptTokened { + pub token: Option, +} + struct BruteForceCounter { counter: AtomicU64, last_reset: AtomicI64, @@ -570,6 +574,30 @@ where } } +#[async_trait] +impl FromRequestParts for OptTokened +where + S: Send + Sync, +{ + type Rejection = (StatusCode, String); + + async fn from_request_parts( + parts: &mut Parts, + state: &S, + ) -> std::result::Result { + if parts.method == http::Method::OPTIONS { + return Ok(OptTokened { token: None }); + }; + let already_tokened = parts.extensions.get::(); + 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,