Fixed query parameters and dynamic Client ID

This commit is contained in:
Evann Regnault 2024-07-16 19:20:30 +02:00
parent d6d73d74fe
commit bf92aea1bb

View file

@ -1,4 +1,4 @@
use std::{convert::Infallible, env, error::Error, net::SocketAddr, str::FromStr};
use std::{collections::HashMap, convert::Infallible, env, error::Error, net::SocketAddr, str::FromStr};
use redis::Commands;
use base64::prelude::*;
use hmac::{digest::generic_array::functional::FunctionalSequence, Hmac, Mac};
@ -31,18 +31,12 @@ struct KeycloakToken {
#[serde(rename_all = "camelCase")]
pub struct DecodedJWT {
#[serde(rename = "resource_access")]
pub resource_access: Option<ResourceAccess>,
pub resource_access: HashMap<String, Roles>,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ResourceAccess {
pub couchdb: Option<Couchdb>,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Couchdb {
pub struct Roles {
pub roles: Vec<String>,
}
@ -80,7 +74,7 @@ impl KeycloakToken {
}
fn decode_token(&self) -> Result<DecodedJWT, Box<dyn Error>> {
let data = self.access_token.split(".").skip(1).next();
let data = self.access_token.split('.').nth(1);
if data.is_none() {
return Err("Invalid JWT".into());
}
@ -92,13 +86,10 @@ impl KeycloakToken {
impl DecodedJWT {
/// Creates the user struct from the JWT Token
fn get_user(self, name: String) -> User {
let roles = match self.resource_access {
let roles = match self.resource_access.get(&env::var("KEYCLOAK_CLIENT_ID").unwrap()) {
None => vec![],
Some(ra) => {
match ra.couchdb {
None => vec![],
Some(cdb) => cdb.roles
}
Some(roles) => {
roles.roles.clone()
}
};
User {
@ -191,9 +182,9 @@ async fn authenticate_keycloak(username: String, password: String) -> Result<Use
/// Retrieves the username and password from a Basic Auth
fn extract_creds_from_request(req: &Request<Body>) -> Option<(String, String)> {
let auth_value = req.headers().get("authorization")?;
let b64_auth = auth_value.to_str().unwrap_or("").split(" ").skip(1).next()?;
let b64_auth = auth_value.to_str().unwrap_or("").split(' ').nth(1)?;
let decoded_auth = String::from_utf8(BASE64_STANDARD.decode(b64_auth.as_bytes()).unwrap_or(vec![])).unwrap();
if let [username, password] = &decoded_auth.split(":").map(String::from).collect::<Vec<String>>()[..] {
if let [username, password] = &decoded_auth.split(':').map(String::from).collect::<Vec<String>>()[..] {
Some((username.to_string(), password.to_string()))
} else {
None
@ -215,14 +206,13 @@ fn error_response((status_code, msg) : (u16, String)) -> Response<Body> {
.unwrap()
}
async fn handle(old_req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
async fn handle(mut req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
let client = Client::new();
// Build proxied Request
let mut req = Request::from(old_req);
let path = req.uri().path();
let path = req.uri().path_and_query();
*req.uri_mut() =
Uri::from_str(format!("http://{}:{}{}", env::var("COUCHDB_HOST").unwrap(), env::var("COUCHDB_PORT").unwrap(), path.to_string()).as_str()).unwrap();
Uri::from_str(format!("http://{}:{}{}", env::var("COUCHDB_HOST").unwrap(), env::var("COUCHDB_PORT").unwrap(), path.unwrap()).as_str()).unwrap();
if req.method() == Method::OPTIONS {
return client.request(req).await
@ -257,7 +247,6 @@ async fn handle(old_req: Request<Body>) -> Result<Response<Body>, hyper::Error>
Err(x) => Err(x),
}
}
#[tokio::main]
async fn main() {
let make_service = make_service_fn(|_| async { Ok::<_, Infallible>(service_fn(handle)) });