use std::sync::Arc;
use casbin::CoreApi;
use axum::{
extract::Request,
http::{
StatusCode,
},
Extension,
response::{IntoResponse,Response,Redirect},
middleware::Next,
};
use tower_cookies::{Cookie, Cookies};
use crate::{
USER_AGENT,
SESSION_COOKIE_NAME,
defs::{
AppDBs,
ServPath,
AuthState,
SessionStoreDB,
},
};
pub async fn add_session_cookie(make: bool, cookies: &Cookies, session_token: &str, user_data: &str, expire: u64, app_dbs: &AppDBs, cookie_path: &str) -> String {
if make {
cookies.remove(Cookie::new(SESSION_COOKIE_NAME, ""));
}
let result_store = SessionStoreDB::store_session_data(&session_token,&user_data, expire, &app_dbs).await;
if result_store.is_empty() {
eprintln!("Unable to store session {}", &app_dbs.config.session_store_uri);
} else {
let cookie = Cookie::build(SESSION_COOKIE_NAME, result_store.to_owned())
.path(format!("{}",cookie_path))
.secure(true)
.http_only(true)
.finish();
if make {
cookies.add(cookie);
}
}
result_store
}
pub async fn get_auth_state(update: bool, cookies: &Cookies, app_dbs: &AppDBs) -> AuthState {
if let Some(s_cookie) = cookies.get(SESSION_COOKIE_NAME) {
let session_cookie = s_cookie.to_string().replace(&format!("{}=",SESSION_COOKIE_NAME),"");
let mut auth_state = AuthState::from_cookie(session_cookie.to_string(), app_dbs).await;
if update {
let _ = auth_state.expire_in(app_dbs.config.session_expire, &app_dbs).await;
}
auth_state
} else {
AuthState::default()
}
}
pub async fn rewrite_request_uri(
Extension(app_dbs): Extension<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
req: Request, next: Next,
) -> Result<impl IntoResponse, Response> {
let auth_state = get_auth_state(true, &cookies, &app_dbs).await;
let uri_path = req.uri().path().to_owned();
if uri_path == "/" {
return Ok(next.run(req).await);
}
let mut root_path = String::from("/");
for it in uri_path.split("/") {
if ! it.is_empty() {
root_path = format!("/{}",it.to_owned());
break;
}
}
let serv_paths: Vec<ServPath> = app_dbs.config.serv_paths.clone().into_iter().filter(
|it| it.is_restricted && it.url_path == root_path
).collect();
if serv_paths.len() > 0 {
let serv_path = serv_paths[0].to_owned();
let name = auth_state.user_name();
if name.is_empty() {
let uri_path = req.uri().path().to_string();
if uri_path.ends_with(".html") {
eprintln!("rewrite_request_uri: No user found in session for {}", &uri_path);
let new_uri = format!("{}?o={}",&serv_path.not_auth.as_str(),req.uri().path().to_string());
return Err(
Redirect::temporary( &new_uri).into_response()
);
} else {
return Ok(next.run(req).await);
}
}
let arr_roles: Vec<String> = auth_state.user_roles().split(",").map(|s| s.replace(" ", "").to_string()).collect();
let req_method = req.method().to_string();
let target_path = serv_path.url_path.to_owned();
let enforcer = app_dbs.enforcer.clone();
for role in arr_roles {
let mut lock = enforcer.write().await;
let result = lock.enforce_mut(
vec![role,target_path.to_owned(), req_method.to_owned()]
).unwrap_or_else(|e|{
println!("Error enforce: {}",e);
false
});
drop(lock);
if result { return Ok(next.run(req).await); }
}
let mut lock = enforcer.write().await;
let result = lock.enforce_mut(
vec![
name,
target_path.to_owned(),
req_method.to_owned()
]
).unwrap_or_else(|e|{
println!("Error enforce: {}",e);
false
});
drop(lock);
if result { return Ok(next.run(req).await); }
let new_uri = format!("{}",serv_path.not_auth);
let agent = if let Some(user_agent) = req.headers().get(USER_AGENT) {
user_agent.to_str().unwrap_or("").to_owned()
} else {
String::from("")
};
if agent.contains("curl") {
return Ok(
format!("Got to {}",&new_uri).into_response()
);
} else {
return Err(
Redirect::temporary(&new_uri).into_response()
);
}
}
Ok(next.run(req).await)
}
pub async fn handle_404(_req: Request) -> (StatusCode, &'static str) {
(StatusCode::NOT_FOUND, "Not found")
}