diff --git a/app/src/api.rs b/app/src/api.rs index 67f1e04..8709483 100644 --- a/app/src/api.rs +++ b/app/src/api.rs @@ -123,7 +123,7 @@ impl HostService { pub fn login_finish( request: login::ClientLoginFinishRequest, - callback: Callback>, + callback: Callback>, ) -> Result { call_server( "/auth/opaque/login/finish", @@ -134,8 +134,12 @@ impl HostService { get_claims_from_jwt(&data) .map_err(|e| anyhow!("Could not parse response: {}", e)) .and_then(|jwt_claims| { + let is_admin = jwt_claims.groups.contains("lldap_admin"); set_cookie("user_id", &jwt_claims.user, &jwt_claims.exp) - .map(|_| jwt_claims.user.clone()) + .map(|_| { + set_cookie("is_admin", &is_admin.to_string(), &jwt_claims.exp) + }) + .map(|_| (jwt_claims.user.clone(), is_admin)) .map_err(|e| anyhow!("Error clearing cookie: {}", e)) }) } else { diff --git a/app/src/app.rs b/app/src/app.rs index c3f633c..4e33964 100644 --- a/app/src/app.rs +++ b/app/src/app.rs @@ -15,13 +15,13 @@ use yew_router::{ pub struct App { link: ComponentLink, - user_name: Option, - redirect_to: String, + user_info: Option<(String, bool)>, + redirect_to: Option, route_dispatcher: RouteAgentDispatcher, } pub enum Msg { - Login(String), + Login((String, bool)), Logout, } @@ -33,6 +33,8 @@ pub enum AppRoute { ListUsers, #[to = "/create_user"] CreateUser, + #[to = "/details/{user_id}"] + UserDetails(String), #[to = "/"] Index, } @@ -46,35 +48,47 @@ impl Component for App { fn create(_: Self::Properties, link: ComponentLink) -> Self { let mut app = Self { link, - user_name: get_cookie("user_id").unwrap_or_else(|e| { - ConsoleService::error(&e.to_string()); - None - }), + user_info: get_cookie("user_id") + .unwrap_or_else(|e| { + ConsoleService::error(&e.to_string()); + None + }) + .and_then(|u| { + get_cookie("is_admin") + .map(|so| so.map(|s| (u, s == "true"))) + .unwrap_or_else(|e| { + ConsoleService::error(&e.to_string()); + None + }) + }), redirect_to: Self::get_redirect_route(), route_dispatcher: RouteAgentDispatcher::new(), }; - if app.user_name.is_none() { - ConsoleService::info("Redirecting to login"); - app.route_dispatcher - .send(RouteRequest::ReplaceRoute(Route::new_no_state("/login"))); - }; + app.apply_initial_redirections(); app } fn update(&mut self, msg: Self::Message) -> ShouldRender { match msg { - Msg::Login(user_name) => { - self.user_name = Some(user_name); + Msg::Login((user_name, is_admin)) => { + self.user_info = Some((user_name.clone(), is_admin)); + let user_route = "/details/".to_string() + &user_name; self.route_dispatcher .send(RouteRequest::ChangeRoute(Route::new_no_state( - &self.redirect_to, + self.redirect_to.as_deref().unwrap_or_else(|| { + if is_admin { + "/users" + } else { + &user_route + } + }), ))); } Msg::Logout => { - self.user_name = None; + self.user_info = None; } } - if self.user_name.is_none() { + if self.user_info.is_none() { self.route_dispatcher .send(RouteRequest::ReplaceRoute(Route::new_no_state("/login"))); } @@ -108,7 +122,12 @@ impl Component for App { {"Create a user"} - } + }, + AppRoute::UserDetails(username) => html! { +
+ {"details about "} {&username} +
+ }, } }) /> @@ -118,13 +137,42 @@ impl Component for App { } impl App { - fn get_redirect_route() -> String { + fn get_redirect_route() -> Option { let route_service = RouteService::<()>::new(); let current_route = route_service.get_path(); if current_route.is_empty() || current_route.contains("login") { - String::from("/") + None } else { - current_route + Some(current_route) + } + } + + fn apply_initial_redirections(&mut self) { + match &self.user_info { + None => { + ConsoleService::info("Redirecting to login"); + self.route_dispatcher + .send(RouteRequest::ReplaceRoute(Route::new_no_state("/login"))); + } + Some((user_name, is_admin)) => match &self.redirect_to { + Some(url) => { + ConsoleService::info(&format!("Redirecting to specified url: {}", url)); + self.route_dispatcher + .send(RouteRequest::ReplaceRoute(Route::new_no_state(url))); + } + None => { + if *is_admin { + ConsoleService::info("Redirecting to user list"); + self.route_dispatcher + .send(RouteRequest::ReplaceRoute(Route::new_no_state("/users"))); + } else { + ConsoleService::info("Redirecting to user view"); + self.route_dispatcher.send(RouteRequest::ReplaceRoute( + Route::new_no_state(&("/details/".to_string() + user_name)), + )); + } + } + }, } } } diff --git a/app/src/cookies.rs b/app/src/cookies.rs index d79984a..e3b394e 100644 --- a/app/src/cookies.rs +++ b/app/src/cookies.rs @@ -38,7 +38,7 @@ pub fn get_cookie(cookie_name: &str) -> Result> { .split(';') .filter_map(|c| c.split_once('=')) .find_map(|(name, value)| { - if name == cookie_name { + if name.trim() == cookie_name { if value.is_empty() { None } else { diff --git a/app/src/login.rs b/app/src/login.rs index 33ae52c..7391a45 100644 --- a/app/src/login.rs +++ b/app/src/login.rs @@ -8,7 +8,7 @@ use yew::FocusEvent; pub struct LoginForm { link: ComponentLink, - on_logged_in: Callback, + on_logged_in: Callback<(String, bool)>, error: Option, node_ref: NodeRef, login_start: Option, @@ -18,13 +18,13 @@ pub struct LoginForm { #[derive(Clone, PartialEq, Properties)] pub struct Props { - pub on_logged_in: Callback, + pub on_logged_in: Callback<(String, bool)>, } pub enum Msg { Submit, AuthenticationStartResponse(Result>), - AuthenticationFinishResponse(Result), + AuthenticationFinishResponse(Result<(String, bool)>), } fn get_form_field(field_id: &str) -> Option { @@ -106,8 +106,8 @@ impl LoginForm { "Could not log in (invalid response to login start): {}", e )), - Msg::AuthenticationFinishResponse(Ok(user_id)) => { - self.on_logged_in.emit(user_id); + Msg::AuthenticationFinishResponse(Ok(user_info)) => { + self.on_logged_in.emit(user_info); Ok(()) } Msg::AuthenticationFinishResponse(Err(e)) => Err(anyhow!("Could not log in: {}", e)),