chore: signin authz routes from config
This commit is contained in:
		
							parent
							
								
									814021eeac
								
							
						
					
					
						commit
						70956706f6
					
				| @ -6,4 +6,5 @@ | ||||
| pub mod jwt; | ||||
| pub mod sessions; | ||||
| pub mod router; | ||||
| pub mod kratos; | ||||
| pub mod kratos; | ||||
| pub mod extauthz; | ||||
							
								
								
									
										132
									
								
								src/handlers/extauthz.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								src/handlers/extauthz.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,132 @@ | ||||
| //
 | ||||
| /*! libresignin
 | ||||
| */ | ||||
| // Copyright 2022, Jesús Pérez Lorenzo
 | ||||
| //
 | ||||
| use axum::{ | ||||
| //	response::Html,
 | ||||
| //	routing::get,
 | ||||
| //	routing::post,
 | ||||
| //	Router,
 | ||||
| 	// extract::{self,Extension,Path,Query},
 | ||||
| //	extract::{Extension,Path},
 | ||||
| 	http::{ | ||||
| 		header::{HeaderMap,HeaderName,HeaderValue}, | ||||
| 		// Request, StatusCode,
 | ||||
| 	}, | ||||
|   // body::{Bytes, Body},
 | ||||
| 	response::{IntoResponse, Headers}, | ||||
| }; | ||||
| 
 | ||||
| // use crate::defs::{DataDBs}; 
 | ||||
| // use crate::utils::reqenv::ReqEnv;
 | ||||
| 
 | ||||
| const CHECK_HEADER: &'static str = "x-ext-authz"; | ||||
| const	ALLOWED_VALUE: &'static str  = "allow"; | ||||
| const	RESULT_HEADER: &'static str = "x-ext-authz-check-result"; | ||||
| const	RECEIVED_HEADER: &'static str = "x-ext-authz-check-received"; | ||||
| const	OVERRIDE_HEADER: &'static str = "x-ext-authz-additional-header-override"; | ||||
| // const	OVERRIDE_GRPC_VALUE: &'static str = "grpc-additional-header-override-value";
 | ||||
| const	RESULT_ALLOWED: &'static str = "allowed"; 
 | ||||
| const	RESULT_DENIED: &'static str = "denied"; | ||||
| 
 | ||||
| // pub fn create_headers(is_allowed: bool, str_head: &str, id: &str,token: &str,csrf_token: &str, cookie: &str) -> HeaderMap {
 | ||||
| // 	let mut headers = HeaderMap::new();
 | ||||
| // 	if is_allowed {
 | ||||
| // 		headers.insert(RESULT_HEADER,
 | ||||
| // 	    HeaderValue::from_str(RESULT_ALLOWED).unwrap_or(HeaderValue::from_static(""))
 | ||||
| // 	  );
 | ||||
| // 	} else {
 | ||||
| // 		headers.insert(RESULT_HEADER,
 | ||||
| // 	    HeaderValue::from_str(RESULT_DENIED).unwrap_or(HeaderValue::from_static(""))
 | ||||
| // 	  );
 | ||||
| // 	}
 | ||||
| // 	headers.insert(OVERRIDE_HEADER,
 | ||||
| // 	  HeaderValue::from_str(OVERRIDE_HEADER).unwrap_or(HeaderValue::from_static(""))
 | ||||
| // 	);
 | ||||
| // 	headers.insert(RECEIVED_HEADER,
 | ||||
| // 	  HeaderValue::from_str(str_head).unwrap_or(HeaderValue::from_static(""))
 | ||||
| // 	);
 | ||||
|   // headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
 | ||||
|   // headers.insert(ACCEPT, HeaderValue::from_static("application/json"));
 | ||||
| 	// if cookie != "" {
 | ||||
|   //   headers.insert(COOKIE, HeaderValue::from_str(cookie)
 | ||||
| 	// 		.unwrap_or(HeaderValue::from_static(""))
 | ||||
| 	// 	);
 | ||||
|   //   // headers.insert(SET_COOKIE, HeaderValue::from_str(cookie)
 | ||||
| 	// 	// 	.unwrap_or(HeaderValue::from_static(""))
 | ||||
| 	// 	// );
 | ||||
| 	// }
 | ||||
| 	// if token != "" {
 | ||||
| 	// 	headers.insert(AUTHORIZATION, HeaderValue::from_str(&format!("Bearer {}",token))
 | ||||
| 	// 		.unwrap_or(HeaderValue::from_static(""))
 | ||||
| 	// 	);
 | ||||
| 	// }
 | ||||
| 	// if csrf_token != "" {
 | ||||
|   //   headers.insert("X-CSRF-Token", 
 | ||||
| 	//     HeaderValue::from_str(csrf_token).unwrap_or(HeaderValue::from_static(""))
 | ||||
| 	//   );
 | ||||
| 	// }
 | ||||
| 	// if id != "" {
 | ||||
|   //   headers.insert("x-kratos-authenticated-identity-id", 
 | ||||
| 	//     HeaderValue::from_str(id).unwrap_or(HeaderValue::from_static(""))
 | ||||
| 	//   );
 | ||||
| 	// }
 | ||||
| 	// dbg!("{:#?}",&headers);
 | ||||
| 	// dbg!("{:#?}",&headers);
 | ||||
| // 	headers
 | ||||
| // }
 | ||||
| // pub async fn authz_handler(header: HeaderMap, req: Request<()> ) -> impl IntoResponse {
 | ||||
| pub async fn authz_handler(header: HeaderMap) -> impl IntoResponse { | ||||
| 	dbg!("{:#?}",&header); | ||||
| 	let result: &str; | ||||
| 	if let Some(check) = &header.get(CHECK_HEADER) { | ||||
| 	  match check.to_str() { | ||||
| 			Ok(check_val) => 
 | ||||
| 				if ALLOWED_VALUE == check_val { | ||||
| 					result = RESULT_ALLOWED; | ||||
| 				} else { | ||||
| 					result = RESULT_DENIED; | ||||
| 				}, | ||||
| 	    Err(_) => result = RESULT_DENIED, | ||||
| 		} | ||||
| 	} else { | ||||
| 		result = RESULT_DENIED; | ||||
| 	} | ||||
| 	//let headers = create_headers("",token,csrf_token,cookie);
 | ||||
| 	// body, err := io.ReadAll(request.Body)
 | ||||
| 	// if err != nil {
 | ||||
| 	// 	log.Printf("[HTTP] read body failed: %v", err)
 | ||||
| 	// }
 | ||||
| 	// format!("%s %s%s, headers: %v, body: [%s]\n", request.Method, request.Host, request.URL, request.Header, body);
 | ||||
| 	let str_head = format!("head"); | ||||
| 	// let headers = create_headers(is_allowed,&str_head,"","","","");
 | ||||
| 	let res_headers: Vec<(HeaderName, HeaderValue)> = vec![ | ||||
| 		(HeaderName::from_static(RESULT_HEADER), HeaderValue::from_static(result)), | ||||
| 		(HeaderName::from_static(OVERRIDE_HEADER), HeaderValue::from_static(OVERRIDE_HEADER)), | ||||
| 		(HeaderName::from_static(RECEIVED_HEADER), HeaderValue::from_str(&str_head).unwrap_or(HeaderValue::from_static(""))), | ||||
| 	]; | ||||
| 	// if is_allowed {
 | ||||
| 	// 	response.WriteHeader(StatusCode::OK)
 | ||||
| 	// } else {
 | ||||
| 	// 	response.WriteHeader(http.StatusForbidden)
 | ||||
| 	// 	response.Write([]byte(denyBody))
 | ||||
| 	// }
 | ||||
| 	dbg!("{:#?}",&res_headers); | ||||
|   Headers(res_headers) | ||||
| 	// let html = format!(
 | ||||
| 	// 	r#"
 | ||||
| 	//     <div>Done: {} </div>
 | ||||
| 	// 	"#,RESULT_ALLOWED);
 | ||||
| 	// Html(html)
 | ||||
| } | ||||
| // pub async fn alive_handler() -> Html<&'static str> {
 | ||||
| //     Html("ok")
 | ||||
| // }
 | ||||
| // pub async fn ready_handler() -> Html<&'static str> {
 | ||||
| //     Html("ok")
 | ||||
| // }
 | ||||
| // pub fn router_handlers(web_router: Router) -> Router {
 | ||||
| // 	web_router
 | ||||
| //   .route("/authz", get(authz_handler))
 | ||||
| // }
 | ||||
| @ -17,7 +17,10 @@ use axum::{ | ||||
| 	response::IntoResponse, | ||||
| 	extract::{Extension,Path,Query}, | ||||
| 	//http::{Request, header::HeaderMap, Method,StatusCode},
 | ||||
| 	http::{header::HeaderMap,StatusCode}, | ||||
| 	http::{ | ||||
| 		header::{HeaderMap,HeaderName,HeaderValue}, | ||||
| 		StatusCode, | ||||
|   }, | ||||
|   // body::{Bytes, Body},
 | ||||
| }; | ||||
| // use serde::{Deserialize, Serialize};
 | ||||
| @ -115,7 +118,7 @@ pub async fn registration_handler(header: HeaderMap, Extension(dbs): Extension<D | ||||
| 					 <h1>Register</h1> | ||||
| 				   <a href='{}/login'>login</a> | ||||
| 					 <div>Status: {} </div> | ||||
| 			   	"#,&reqenv.websrvr_url(),res.status);
 | ||||
| 			   	"#,&reqenv.public_url(),res.status);
 | ||||
| 				}, | ||||
| 				Err(e) => { | ||||
| 	        eprintln!("{}",e); | ||||
| @ -162,6 +165,8 @@ pub async fn login_handler(header: HeaderMap, Extension(dbs): Extension<DataDBs> | ||||
| 	let flow = String::from("self-service/login"); | ||||
| 	let query = String::from("/api?refresh=false&aal=&return_to="); | ||||
| 	let root_url = get_root_url(reqenv.websrvr().signin.protocol,reqenv.websrvr().signin.root,reqenv.websrvr().signin.port); | ||||
| 	let mut headers = HeaderMap::new(); | ||||
| 	let ret_status: StatusCode; | ||||
| 	let mut user_data = HashMap::new(); | ||||
| 	user_data.insert("password".to_string(),"19Ting22".to_string()); | ||||
| 	user_data.insert("password_identifier".to_string(),"jesuspl".to_string()); | ||||
| @ -183,6 +188,11 @@ pub async fn login_handler(header: HeaderMap, Extension(dbs): Extension<DataDBs> | ||||
| 					// 	 res.session_resp.session_token);
 | ||||
|           // return html.to_owned();
 | ||||
| 					if res.status == StatusCode::OK { | ||||
| 						headers.insert( | ||||
| 							HeaderName::from_static("x-authz"), | ||||
| 							HeaderValue::from_str(&format!("{}:tk:{}",res.session_resp.session.identity.id, res.session_resp.session_token)).unwrap_or(HeaderValue::from_static("")), | ||||
| 						); | ||||
| 						ret_status = StatusCode::OK; | ||||
| 						html = format!( | ||||
| 						r#" | ||||
| 						<h1>Login</h1> | ||||
| @ -190,39 +200,46 @@ pub async fn login_handler(header: HeaderMap, Extension(dbs): Extension<DataDBs> | ||||
| 						<div><a href='{}/logout/{}?token={}'>logout</a></div> | ||||
| 						<div>Status: {} </div> | ||||
| 						"#,
 | ||||
| 						&reqenv.websrvr_url(),res.session_resp.session.identity.id, res.session_resp.session_token, | ||||
| 						&reqenv.websrvr_url(),res.session_resp.session.identity.id, res.session_resp.session_token, | ||||
| 						&reqenv.public_url(),res.session_resp.session.identity.id, res.session_resp.session_token, | ||||
| 						&reqenv.public_url(),res.session_resp.session.identity.id, res.session_resp.session_token, | ||||
| 						res.status);	
 | ||||
| 					} else { | ||||
| 						ret_status = StatusCode::OK; | ||||
| 						html = format!( | ||||
| 						r#" | ||||
| 						<h1>Login</h1> | ||||
| 						<div>Status: {} </div> | ||||
| 					  <div><a href='{}/registration'>Registration</a></div> | ||||
| 						"#,res.status,&reqenv.websrvr_url());	
 | ||||
| 						"#,res.status,&reqenv.public_url());	
 | ||||
| 					} | ||||
| 				}, | ||||
| 				Err(e) => { | ||||
| 	        eprintln!("{}",e); | ||||
| 				  // ret_status = StatusCode::FORBIDDEN;
 | ||||
| 				  ret_status = StatusCode::NOT_FOUND; | ||||
| 					html = format!( | ||||
| 					r#" | ||||
| 					 <h1>Login</h1> | ||||
| 					 <div><a href='{}/registration'>Registration</a></div> | ||||
| 					 <div>Error: {} </div> | ||||
| 			   	"#,&reqenv.websrvr_url(),e);
 | ||||
| 			   	"#,&reqenv.public_url(),e);
 | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| 		Err(e) => { | ||||
| 	    eprintln!("{}",e); | ||||
| 		  ret_status = StatusCode::BAD_REQUEST; | ||||
| 		  // ret_status = StatusCode::UNAUTHORIZED;
 | ||||
| 			html = format!( | ||||
| 			r#" | ||||
| 				<h1>Login</h1> | ||||
| 				<div>Error: {} </div> | ||||
| 			"#,e);
 | ||||
| 				<div>Error: No Login Found </div> | ||||
| 			"#);
 | ||||
| 		}, | ||||
| 	}; | ||||
| 	Html(html) | ||||
|   (ret_status, headers, Html(html)) | ||||
| 	// (StatusCode, HeaderMap, &'static str)
 | ||||
| 	//Html(html)
 | ||||
| } | ||||
| pub async fn recovery_handler() -> Html<&'static str> { | ||||
|     Html("<h1>Hello, World!</h1>") | ||||
| @ -255,14 +272,14 @@ pub async fn whoami(id: String, token: String, | ||||
| 						<div>Status: {}</div> | ||||
| 						<div><a href='{}/logout/{}?token={}'>logout</a></div> | ||||
| 						"#,res.status,
 | ||||
| 							&reqenv.websrvr_url(),id,token) | ||||
| 							&reqenv.public_url(),id,token) | ||||
| 					} else { | ||||
| 						html = format!( | ||||
| 						r#" | ||||
| 						<h1>whoami</h1> | ||||
| 						<div>Status: {}</div> | ||||
| 						<div><a href='{}/login'>login</a></div> | ||||
| 						"#,res.status, &reqenv.websrvr_url())
 | ||||
| 						"#,res.status, &reqenv.public_url())
 | ||||
| 					} | ||||
| 				}, | ||||
| 				Err(e) => { | ||||
| @ -272,7 +289,7 @@ pub async fn whoami(id: String, token: String, | ||||
| 						<h1>whoami</h1> | ||||
| 					  <div><a href='{}/login'>Login</a></div> | ||||
| 						<div>Error: {} </div> | ||||
| 					"#,&reqenv.websrvr_url(),e);
 | ||||
| 					"#,&reqenv.public_url(),e);
 | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| @ -308,8 +325,9 @@ pub async fn whoami_handler(Path(id): Path<String>, query: Query<QueryToken>, | ||||
| 		println!("flow: {}",&reqid.flow); | ||||
| 		println!("csrf_token: {}",&reqid.csrf); | ||||
| 		println!("cookie: {}",&reqid.cookie); | ||||
| 	  let flow_logout = String::from("self-service/logout"); | ||||
| 		let query_id = format!("/api?{}&flow={}",&urlquery.token,&reqid.flow); | ||||
| 		let reg_url=format!("{}/{}{}",&root_url,flow,query_id); | ||||
| 		let reg_url=format!("{}/{}{}",&root_url,flow_logout,query_id); | ||||
| 		// match on_kratos_user(reqenv.websrvr().signin,&reqid.csrf,&id,®_url,user).await {
 | ||||
| 		match logout_kratos_user(&id,&urlquery.token.to_string(),reqenv.websrvr().signin,&req_cli,&reqid.csrf,&reqid.cookie,®_url).await { | ||||
| 			Ok(res) => { | ||||
| @ -319,7 +337,7 @@ pub async fn whoami_handler(Path(id): Path<String>, query: Query<QueryToken>, | ||||
| 				<h1>Logout</h1> | ||||
| 				<a href='{}/login'>login</a> | ||||
| 				<div>Status: {}</div> | ||||
| 				"#,reqenv.websrvr_url(),res.status);
 | ||||
| 				"#,reqenv.public_url(),res.status);
 | ||||
| 			}, | ||||
| 			Err(e) => { | ||||
| 				eprintln!("{}",e); | ||||
|  | ||||
| @ -21,6 +21,15 @@ use std::{ | ||||
| use crate::defs::{DataDBs}; 
 | ||||
| use crate::utils::reqenv::ReqEnv; | ||||
| 
 | ||||
| use app_env::{ | ||||
|   // AppStore,
 | ||||
|   // appenv::AppEnv,
 | ||||
|   // appinfo::AppInfo,
 | ||||
|   // appdata::AppData,
 | ||||
|   //config::{WebServer,SigninServer,SigninAuthzRoutes,AuthzMode},
 | ||||
|   config::{SigninAuthzRoute,AuthzMode}, | ||||
| }; | ||||
| 
 | ||||
| // pub async fn html_handler(Path(path): Path<String>,query: Option<Query<String>>, Extension(dbs): Extension<DataDBs>) -> Html<&'static str> {
 | ||||
| // pub async fn html_handler(Path(path): Path<String>,Extension(dbs): Extension<DataDBs>) -> Html<&'static str> {
 | ||||
| pub async fn html_handler(header: HeaderMap, Path(name): Path<String>,Extension(dbs): Extension<DataDBs>) -> Html<&'static str> { | ||||
| @ -66,3 +75,32 @@ pub fn router_handlers(web_router: Router) -> Router { | ||||
| 	.route("/health/alive", get(alive_handler)) | ||||
|   .route("/health/ready", get(ready_handler)) | ||||
| } | ||||
| // These are to implement configuration defined signin authz routes 
 | ||||
| // using authz-route "path" ,"mode"(AuthMode) and "handler"
 | ||||
| // 
 | ||||
| fn add_kratos_handler(web_router: Router,route: SigninAuthzRoute) -> Router { | ||||
| 	let mut webrouter = web_router.to_owned(); | ||||
| 	if route.path.is_empty() { | ||||
|     return webrouter; | ||||
| 	} | ||||
| 	match route.handler.as_str() { | ||||
| 		// TODO Add handlers for Kratos. This should be moved from String to Enum type in SinginAuthRoute
 | ||||
| 	 "headers" => webrouter = webrouter.route(route.path.as_str(), get(crate::handlers::extauthz::authz_handler)), | ||||
| 	  _ => { 
 | ||||
| 			println!("Kratos signin authz route ({}) path ({}) with handler ({}) use authz_handler",route.id,route.path,route.handler); | ||||
| 	    webrouter = webrouter.route(route.path.as_str(), get(crate::handlers::extauthz::authz_handler)); | ||||
| 		}, | ||||
| 	}; | ||||
| 	webrouter | ||||
| } | ||||
| pub fn router_authz_handlers(web_router: Router,signin_auth_routes: Vec<SigninAuthzRoute>) -> Router { | ||||
| 	let mut webrouter = web_router.to_owned(); | ||||
| 	for route in signin_auth_routes { | ||||
| 		match route.mode { | ||||
| 			AuthzMode::Kratos => webrouter = add_kratos_handler(webrouter,route), | ||||
| 		 // TODO Add new AuthMode
 | ||||
| 			_ => eprintln!("Signin authz route {} undefined mode {}",route.id,route.mode), | ||||
| 		} | ||||
| 	} | ||||
| 	webrouter | ||||
| } | ||||
| @ -241,6 +241,7 @@ async fn up_web_server(webpos: usize) -> Result<()> { // WebSettings> { | ||||
|  	  println!("Web services: done {} __________ ",chrono::Utc::now().timestamp()); | ||||
| 	} | ||||
| 	let mut web_router = Router::new(); | ||||
| 	web_router = crate::handlers::router::router_authz_handlers(web_router,config.signin.authz_routes); | ||||
| 	web_router = crate::handlers::router::router_handlers(web_router); | ||||
| 	if !config.html_path.is_empty() { | ||||
| 		web_router = web_router.nest( | ||||
|  | ||||
| @ -114,6 +114,15 @@ impl ReqEnv { | ||||
|     let config=self.req.config().websrvrs[self.req.env().curr_web].to_owned(); | ||||
| 	  format!("{}://{}:{}", config.srv_protocol, config.srv_host, config.srv_port) | ||||
|   } | ||||
| 	#[must_use] | ||||
|   pub fn public_url(&self) -> String { | ||||
|     let config=self.req.config().websrvrs[self.req.env().curr_web].to_owned(); | ||||
| 		if config.public_url.is_empty() { | ||||
| 	    format!("{}://{}:{}", config.srv_protocol, config.srv_host, config.srv_port) | ||||
| 		} else { | ||||
| 			config.public_url | ||||
| 		} | ||||
| 	} | ||||
|   #[must_use] | ||||
|   pub fn module(&self) -> Module { | ||||
|     self.req.module() | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user