Logic to resolve mount points

This commit is contained in:
Laurenz 2024-05-02 13:57:01 +02:00
parent 049e8374ab
commit a5d74f0454
4 changed files with 63 additions and 41 deletions

View file

@ -3,6 +3,7 @@ pub mod kv;
use axum::{
body::Body,
extract::{Request, State},
http::Uri,
response::Response,
Router,
};
@ -11,35 +12,46 @@ use log::*;
use crate::storage::DatabaseDriver;
pub fn secrets_router(pool: DatabaseDriver) -> Router<DatabaseDriver> {
Router::new().fallback(map_mount_points).with_state(pool)
Router::new().fallback(engine_handler).with_state(pool)
}
async fn map_mount_points(State(pool): State<DatabaseDriver>, req: Request) -> Response<Body> {
debug!("Mount path: {:?}", req);
let mut mount_path: Vec<&str> = req.uri().path().split("/").collect();
// let a = sqlx::query!("SELECT * FROM secret_engines WHERE path = $1", mount_path.join("/"))
// .fetch_one(&pool)
// .await
// .expect("Failed to fetch secret engine");
let tada = vec!["a/b/c/d".to_string(), "/a/b/c".to_string(), "/kv-v2".into()];
// Find longest matching existing mount path for the request
for _ in 1..mount_path.len() {
if tada.contains(&mount_path.join("/")) {
trace!(
"Mount path {} found for route request: {}",
mount_path.join("/"),
req.uri().path()
);
break;
} else {
mount_path.pop();
async fn engine_handler(State(pool): State<DatabaseDriver>, req: Request) -> Response<Body> {
match map_mount_points(req.uri(), &pool).await {
Some((mount_path, engine_type)) => {
info!("Found mount point {} of type {}", mount_path, engine_type);
todo!()
}
None => todo!(),
}
return Response::new(Body::from(format!("Mount path:")));
// Response::new(Body::from("Mount path:"))
}
async fn map_mount_points(req: &Uri, pool: &DatabaseDriver) -> Option<(String, String)> {
let mut mount_path_fragments: Vec<&str> = req.path().split('/').collect();
// Find longest matching existing mount path for the request
for _ in 1..mount_path_fragments.len() {
let path_str = mount_path_fragments.join("/");
let record = sqlx::query!(
"SELECT engine_type FROM secret_engines WHERE mount_point = $1",
path_str
)
.fetch_optional(pool)
.await;
if let Ok(Some(row)) = record {
trace!(
"Mount path {} found with {:?} engine for route request: {}",
mount_path_fragments.join("/"),
row.engine_type,
req.path()
);
return Some((mount_path_fragments.join("/"), row.engine_type));
} else {
mount_path_fragments.pop();
}
}
None
}

View file

@ -7,9 +7,9 @@ pub mod structs;
#[cfg(test)]
mod tests;
use crate::{engines::kv::logic::body_to_json, storage::DatabaseDriver};
use crate::engines::kv::structs::KvSecret;
use axum::{routing::*, Router, extract::Path};
use crate::{engines::kv::logic::body_to_json, storage::DatabaseDriver};
use axum::{extract::Path, routing::*, Router};
pub fn kv_router(pool: DatabaseDriver) -> Router<DatabaseDriver> {
Router::new()
@ -42,9 +42,12 @@ async fn get_data() -> &'static str {
todo!("not implemented")
}
async fn post_data(Path((mount_path, kv_path)): Path<(String, String)>, body: String) -> &'static str {
async fn post_data(
Path((mount_path, kv_path)): Path<(String, String)>,
body: String,
) -> &'static str {
let mut body_json = body_to_json(body);
let secret: KvSecret = KvSecret {
data: body_json["data"]["password1"].take().to_string(),
version: body_json["data"]["version"].take().as_i64(),
@ -57,12 +60,11 @@ async fn post_data(Path((mount_path, kv_path)): Path<(String, String)>, body: St
mount_path,
);
"RoutingTest foo successful"
// todo!("not implemented")
}
/// TODO soft delete the secret version at path. can be undone with undelete_secret
/// TODO: soft delete the secret version at path. can be undone with undelete_secret
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#delete-latest-version-of-secret
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#delete-secret-versions
async fn delete_data() -> &'static str {

View file

@ -1,6 +1,3 @@
use std::collections::HashMap;
use chrono::{DateTime, Utc};
use serde_json::Value;
use super::structs::*;
@ -14,7 +11,7 @@ pub fn serialize_secret_json(secret: &KvSecret) -> Result<String, serde_json::Er
/// deserialize JSON String to secret
pub fn deserialize_secret_struct(raw: &String) -> Result<KvSecret, serde_json::Error> {
serde_json::from_str(&raw)
serde_json::from_str(raw)
}
/// serialize metadata to JSON String
@ -24,7 +21,7 @@ pub fn serialize_metadata_json(secret: &SecretMeta) -> Result<String, serde_json
/// deserialize JSON String to metadata
pub fn deserialize_metadata_struct(raw: &String) -> Result<SecretMeta, serde_json::Error> {
serde_json::from_str(&raw)
serde_json::from_str(raw)
}
pub fn patch_metadata(
@ -39,10 +36,10 @@ pub fn patch_metadata(
pub fn body_to_json(body: String) -> Value {
match serde_json::from_str::<serde_json::Value>(body.as_str()) {
Ok(val) => return val,
Ok(val) => val,
Err(e) => {
log::debug!("Faulty result from conversion: {:?}", e);
return Into::into("Error converting body");
"Error converting body".into()
}
}
}

View file

@ -1,5 +1,15 @@
use std::collections::HashMap;
use chrono::Utc;
use tests::{
logic::patch_metadata,
structs::{SecretMeta, VersionMeta},
};
use super::*;
#[test]
#[cfg(target_feature = "_disabled")]
fn print_serialized_test() {
let temp_secret = TempSecret {
content: String::from("Hallo"),
@ -14,6 +24,7 @@ fn print_serialized_test() {
)
}
#[test]
#[cfg(target_feature = "_disabled")]
fn test_patching() {
// TODO add more assertions
let mut base = create_mock_meta();
@ -31,7 +42,7 @@ fn test_patching() {
oldest_version: 2,
updated_time: Utc::now(),
created_time: Utc::now(),
custom_metadata: HashMap::new(),
custom_metadata: Some(HashMap::new()),
};
let mut patched: Option<SecretMeta> = None; // Laurenz here
match patch_metadata(&mut base, &overwrite) {