mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-23 08:00:45 +00:00
cd02586ba2
* s3 proxy works with get (no auth yet) * nit * support s3:// syntax * Support s3:// syntax and fix vite api proxy normalizing double slashes in URI * s3 checks authed * nit * PUT works * delete file works * Derive the JWT signature from the backend * Authorize s3 correctly (JWT signature is never sent in cleartext) * convert object store error to wmill error for correct status code * stash * fix * POST first request proxy works * s3 put for duckdb * factor out direct proxy code * Fix Issue with backend proxy and wrong signature due to Host header mismatch * Add _default_ syntax to solve URI normalization issues with signing * restricted to user paths toggle * user path restriction works ! * change restriction to allow * fix * factor out code * better permissions UX in object storage settings * Revert to restrict_to_user_paths * check permissions in old s3 api * DuckDB now uses S3 Proxy and no longer needs LFS query * implement todo * fix hardcoded w_id * s3 proxy size limit * s3_proxy is ee * nit * add Google Cloud Storage as option to secondary storage * GCS secret in duckdb * fix toolchain compile * Remove user permissions for v0 * fix ci 2 * fix CI OSS * fix missing feature flag * fix unused warning * integration test fails bc rustc 1.85.0 * ee ref * fix ci ... * update ee ref
78 lines
2.6 KiB
Rust
78 lines
2.6 KiB
Rust
use crate::error::{self, to_anyhow, Error};
|
|
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
|
|
use hmac::{Hmac, Mac};
|
|
use serde::{de::DeserializeOwned, Serialize};
|
|
use sha2::Sha256;
|
|
use std::{collections::HashSet, sync::Arc};
|
|
use tokio::sync::RwLock;
|
|
|
|
lazy_static::lazy_static! {
|
|
pub static ref JWT_SECRET: Arc<RwLock<String>> = Arc::new(RwLock::new("".to_string()));
|
|
}
|
|
|
|
pub async fn encode_with_internal_secret<T: Serialize>(claims: T) -> error::Result<String> {
|
|
let jwt_secret = JWT_SECRET.read().await;
|
|
|
|
if jwt_secret.is_empty() {
|
|
return Err(Error::internal_err("JWT secret is not set".to_string()));
|
|
}
|
|
|
|
let token = jsonwebtoken::encode(
|
|
&jsonwebtoken::Header::new(jsonwebtoken::Algorithm::HS256),
|
|
&claims,
|
|
&jsonwebtoken::EncodingKey::from_secret(jwt_secret.as_bytes()),
|
|
)
|
|
.map_err(to_anyhow)?;
|
|
|
|
Ok(token)
|
|
}
|
|
|
|
pub async fn decode_with_internal_secret<T: DeserializeOwned>(token: &str) -> error::Result<T> {
|
|
let jwt_secret = JWT_SECRET.read().await;
|
|
|
|
if jwt_secret.is_empty() {
|
|
return Err(Error::internal_err("JWT secret is not set".to_string()));
|
|
}
|
|
|
|
let result = jsonwebtoken::decode::<T>(
|
|
token,
|
|
&jsonwebtoken::DecodingKey::from_secret(jwt_secret.as_bytes()),
|
|
&jsonwebtoken::Validation::new(jsonwebtoken::Algorithm::HS256),
|
|
)
|
|
.map_err(to_anyhow)?;
|
|
|
|
Ok(result.claims)
|
|
}
|
|
|
|
pub fn decode_without_verify<T: DeserializeOwned>(token: &str) -> anyhow::Result<T> {
|
|
// Create a validation that skips all checks
|
|
let mut validation = jsonwebtoken::Validation::default();
|
|
validation.insecure_disable_signature_validation();
|
|
validation.validate_exp = false;
|
|
validation.validate_nbf = false;
|
|
validation.required_spec_claims = HashSet::new();
|
|
|
|
// Use an empty key since we're not verifying
|
|
let key = jsonwebtoken::DecodingKey::from_secret(&[]);
|
|
|
|
// Decode the token
|
|
let token_data = jsonwebtoken::decode::<T>(token, &key, &validation)?;
|
|
|
|
Ok(token_data.claims)
|
|
}
|
|
|
|
// header_and_payload: `{header}.{payload}`
|
|
pub async fn generate_signature(header_and_payload: &str) -> anyhow::Result<String> {
|
|
let header_and_payload = header_and_payload.trim_start_matches("jwt_ext_");
|
|
let header_and_payload = header_and_payload.trim_start_matches("jwt_");
|
|
let secret = JWT_SECRET.read().await;
|
|
|
|
// Create HMAC-SHA256
|
|
let mut mac = Hmac::<Sha256>::new_from_slice(secret.as_bytes())?;
|
|
mac.update(header_and_payload.as_bytes());
|
|
|
|
// Finalize and encode
|
|
let result = mac.finalize().into_bytes();
|
|
Ok(URL_SAFE_NO_PAD.encode(result))
|
|
}
|