225 lines
8.1 KiB
Rust
225 lines
8.1 KiB
Rust
|
use std::sync::Arc;
|
||
|
use casbin::CoreApi;
|
||
|
use axum::{
|
||
|
extract::{Request,ConnectInfo},
|
||
|
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,
|
||
|
TraceData,
|
||
|
TraceContent,
|
||
|
ReqHeaderMap,
|
||
|
AppConnectInfo,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
/* // OLD get_cookie from Request
|
||
|
pub fn get_cookie(req: &Request) -> Option<u128> {
|
||
|
req
|
||
|
.headers()
|
||
|
.get_all("Cookie")
|
||
|
.iter()
|
||
|
.filter_map(|cookie| {
|
||
|
cookie
|
||
|
.to_str()
|
||
|
.ok()
|
||
|
.and_then(|cookie| cookie.parse::<Cookie>().ok())
|
||
|
})
|
||
|
.find_map(|cookie| {
|
||
|
(cookie.name() == SESSION_COOKIE_NAME).then(move || cookie.value().to_owned())
|
||
|
})
|
||
|
.and_then(|cookie_value| cookie_value.parse::<u128>().ok())
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
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())
|
||
|
// .domain(domain)
|
||
|
.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 {
|
||
|
// eprintln!("get_auth_state: No SESSION COOKIE found ");
|
||
|
AuthState::default()
|
||
|
}
|
||
|
}
|
||
|
pub fn trace_req(uri_path: &str, user_id: String, sid: String, info: String, context: String, role: String, req_header: ReqHeaderMap, app_dbs: &AppDBs) -> std::io::Result<()> {
|
||
|
let timestamp = chrono::Utc::now().timestamp().to_string();
|
||
|
let trace_content = TraceContent{
|
||
|
when: timestamp.to_owned(),
|
||
|
sid,
|
||
|
origin: uri_path.to_owned(),
|
||
|
trigger: String::from("req_handler"),
|
||
|
id: user_id.to_owned(),
|
||
|
info: info.to_owned(),
|
||
|
context,
|
||
|
role,
|
||
|
req: req_header.req_info(),
|
||
|
};
|
||
|
let trace_data = TraceData{
|
||
|
user_id,
|
||
|
timestamp,
|
||
|
contents: vec![trace_content]
|
||
|
};
|
||
|
trace_data.save(&app_dbs.config,false)
|
||
|
}
|
||
|
|
||
|
pub async fn rewrite_request_uri(
|
||
|
Extension(app_dbs): Extension<Arc<AppDBs>>,
|
||
|
Extension(cookies): Extension<Cookies>,
|
||
|
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
|
||
|
req: Request, next: Next,
|
||
|
) -> Result<impl IntoResponse, Response> {
|
||
|
// TODO Trace acccess to log or user session file !!!
|
||
|
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);
|
||
|
}
|
||
|
// For long path is better than:
|
||
|
// let arr_root_path: Vec<String> = uri_path.split("/").map(|s| s.to_string()).collect();
|
||
|
// let root_path = arr_root_path[1].to_owned();
|
||
|
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();
|
||
|
// Only on First one
|
||
|
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());
|
||
|
let _ = trace_req(&uri_path, auth_state.user_id(),auth_state.id(),
|
||
|
format!("user no name found in session"), String::from("rewrite_request_uri"),
|
||
|
auth_state.user_roles(),
|
||
|
ReqHeaderMap::new(req.headers().to_owned(), &uri_path, &app_connect_info),
|
||
|
&app_dbs);
|
||
|
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.to_owned(),target_path.to_owned(), req_method.to_owned()]
|
||
|
).unwrap_or_else(|e|{
|
||
|
println!("Error enforce: {}",e);
|
||
|
false
|
||
|
});
|
||
|
drop(lock);
|
||
|
if result {
|
||
|
if uri_path.ends_with(".html") || app_dbs.config.trace_level > 1 {
|
||
|
let _ = trace_req(&uri_path,auth_state.user_id(),auth_state.id(),
|
||
|
format!("user in session with role {}",role),
|
||
|
String::from("rewrite_request_uri"),
|
||
|
auth_state.user_roles(),
|
||
|
ReqHeaderMap::new(req.headers().to_owned(), &uri_path, &app_connect_info),
|
||
|
&app_dbs);
|
||
|
}
|
||
|
return Ok(next.run(req).await);
|
||
|
}
|
||
|
}
|
||
|
// try with email
|
||
|
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 uri_path.ends_with(".html") || app_dbs.config.trace_level > 1 {
|
||
|
let _ = trace_req(&uri_path,auth_state.user_id(),auth_state.id(),
|
||
|
format!("user found in session"),
|
||
|
String::from("rewrite_request_uri"),
|
||
|
auth_state.user_roles(),
|
||
|
ReqHeaderMap::new(req.headers().to_owned(), &uri_path, &app_connect_info),
|
||
|
&app_dbs);
|
||
|
}
|
||
|
if agent.contains("curl") {
|
||
|
return Ok(
|
||
|
format!("Got to {}",&new_uri).into_response()
|
||
|
);
|
||
|
} else {
|
||
|
return Err(
|
||
|
Redirect::temporary(&new_uri).into_response()
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
if uri_path.ends_with(".html") || app_dbs.config.trace_level > 1 {
|
||
|
let _ = trace_req(&uri_path,auth_state.user_id(),auth_state.id(),
|
||
|
format!("user in session"),
|
||
|
String::from("rewrite_request_uri"),
|
||
|
auth_state.user_roles(),
|
||
|
ReqHeaderMap::new(req.headers().to_owned(), &uri_path, &app_connect_info),
|
||
|
&app_dbs);
|
||
|
}
|
||
|
Ok(next.run(req).await)
|
||
|
}
|
||
|
pub async fn handle_404(_req: Request) -> (StatusCode, &'static str) {
|
||
|
(StatusCode::NOT_FOUND, "Not found")
|
||
|
}
|
||
|
|