From 8ab88ae4e1a6f3c6aef7912ab00d2914efc23799 Mon Sep 17 00:00:00 2001 From: Philippe Loctaux Date: Sun, 26 Mar 2023 23:36:36 +0200 Subject: [PATCH] ezidam: admin settings: added security page: logout everyone --- crates/ezidam/src/menu/items/admin.rs | 14 ++- crates/ezidam/src/page.rs | 5 ++ crates/ezidam/src/routes/admin.rs | 15 +++- crates/ezidam/src/routes/admin/settings.rs | 88 +++++++++++++++++++ .../pages/admin/settings_security.html.tera | 60 +++++++++++++ 5 files changed, 177 insertions(+), 5 deletions(-) create mode 100644 crates/ezidam/templates/pages/admin/settings_security.html.tera diff --git a/crates/ezidam/src/menu/items/admin.rs b/crates/ezidam/src/menu/items/admin.rs index 45ef654..f0311b2 100644 --- a/crates/ezidam/src/menu/items/admin.rs +++ b/crates/ezidam/src/menu/items/admin.rs @@ -37,10 +37,16 @@ impl AdminMenu { label: "Server settings", link: uri!(routes::admin::settings::settings_branding).to_string(), icon: icons::SETTINGS, - sub: Some(vec![SubItem { - label: "Branding", - link: uri!(routes::admin::settings::settings_branding).to_string(), - }]), + sub: Some(vec![ + SubItem { + label: "Branding", + link: uri!(routes::admin::settings::settings_branding).to_string(), + }, + SubItem { + label: "Security", + link: uri!(routes::admin::settings::settings_security).to_string(), + }, + ]), }, ] } diff --git a/crates/ezidam/src/page.rs b/crates/ezidam/src/page.rs index 6b729fe..df9badf 100644 --- a/crates/ezidam/src/page.rs +++ b/crates/ezidam/src/page.rs @@ -16,6 +16,7 @@ pub enum Page { Redirect(Redirect), AdminDashboard(AdminDashboard), AdminSettingsBranding(AdminSettingsBranding), + AdminSettingsSecurity(AdminSettingsSecurity), } impl Page { @@ -29,6 +30,7 @@ impl Page { Page::Redirect(_) => "pages/oauth/redirect", Page::AdminDashboard(_) => "pages/admin/dashboard", Page::AdminSettingsBranding(_) => "pages/admin/settings_branding", + Page::AdminSettingsSecurity(_) => "pages/admin/settings_security", } } @@ -42,6 +44,7 @@ impl Page { Page::Redirect(_) => "Redirecting", Page::AdminDashboard(_) => "Admin dashboard", Page::AdminSettingsBranding(_) => "Server branding", + Page::AdminSettingsSecurity(_) => "Server security", } } @@ -57,6 +60,7 @@ impl Page { Page::Redirect(_) => None, Page::AdminDashboard(_) => Some(AdminMenu::Dashboard.into()), Page::AdminSettingsBranding(_) => Some(AdminMenu::Settings.into()), + Page::AdminSettingsSecurity(_) => Some(AdminMenu::Settings.into()), } } @@ -70,6 +74,7 @@ impl Page { Page::Redirect(redirect) => Box::new(redirect), Page::AdminDashboard(dashboard) => Box::new(dashboard), Page::AdminSettingsBranding(branding) => Box::new(branding), + Page::AdminSettingsSecurity(security) => Box::new(security), } } } diff --git a/crates/ezidam/src/routes/admin.rs b/crates/ezidam/src/routes/admin.rs index 3ceac96..25c9c5f 100644 --- a/crates/ezidam/src/routes/admin.rs +++ b/crates/ezidam/src/routes/admin.rs @@ -6,7 +6,13 @@ pub mod dashboard; pub mod settings; pub fn routes() -> Vec { - routes![admin_dashboard, settings_branding, settings_update_branding] + routes![ + admin_dashboard, + settings_branding, + settings_update_branding, + settings_security, + settings_security_form, + ] } pub mod content { @@ -27,4 +33,11 @@ pub mod content { pub user: JwtClaims, pub business_name: String, } + + #[derive(Serialize)] + #[serde(crate = "rocket::serde")] + #[derive(Clone)] + pub struct AdminSettingsSecurity { + pub user: JwtClaims, + } } diff --git a/crates/ezidam/src/routes/admin/settings.rs b/crates/ezidam/src/routes/admin/settings.rs index b17228b..105d644 100644 --- a/crates/ezidam/src/routes/admin/settings.rs +++ b/crates/ezidam/src/routes/admin/settings.rs @@ -1,7 +1,13 @@ use crate::routes::prelude::*; +use crate::tokens::{generate_jwt, generate_refresh_token}; +use apps::App; +use refresh_tokens::RefreshToken; use rocket::fs::TempFile; +use rocket::http::CookieJar; use rocket::{get, post}; use settings::Settings; +use std::net::IpAddr; +use users::User; #[get("/admin/settings/branding")] pub async fn settings_branding(mut db: Connection, admin: JwtAdmin) -> Result { @@ -59,3 +65,85 @@ pub async fn settings_update_branding( Ok(Redirect::to(uri!(settings_branding))) } + +#[get("/admin/settings/security")] +pub async fn settings_security(admin: JwtAdmin) -> Result { + Ok(Page::AdminSettingsSecurity( + super::content::AdminSettingsSecurity { user: admin.0 }, + )) +} + +#[derive(Debug, FromForm)] +pub struct SecurityForm { + pub logout_everyone: Option, +} + +#[post("/admin/settings/security", data = "
")] +pub async fn settings_security_form( + mut db: Connection, + admin: JwtAdmin, + form: Form, + ip_address: IpAddr, + cookie_jar: &CookieJar<'_>, +) -> Result { + let mut transaction = db.begin().await?; + + if let Some(logout_everyone) = form.logout_everyone { + if logout_everyone { + // Generate key id + let key_id = task::spawn_blocking(id::KeyID::default).await?; + + // Generate key + let key_id_for_generation = key_id.clone(); + let (private_key, public_key) = + task::spawn_blocking(move || jwt::generate(&key_id_for_generation)).await??; + + // Insert keys in database + jwt::database::save_new_keys(&mut transaction, &key_id, &private_key, &public_key) + .await?; + + // Revoke all keys except new one + jwt::database::revoke_all_except_one(&mut transaction, &key_id).await?; + + // Get app + let app = App::get_one_by_id(&mut transaction, "ezidam") + .await? + .ok_or_else(|| Error::not_found("Could not find application"))?; + + // Get user info + let user = User::get_by_login(&mut transaction, &admin.0.subject) + .await? + .ok_or_else(|| Error::not_found("Could not find user"))?; + + // Revoke all refresh tokens + RefreshToken::revoke_all(&mut transaction).await?; + + // Generate refresh token + generate_refresh_token(&mut transaction, ip_address, user.id(), cookie_jar) + .await + .map_err(Error::internal_server_error)?; + + // Get base url + let settings = Settings::get(&mut transaction).await?; + let home_page = settings + .url() + .map(String::from) + .ok_or_else(|| Error::bad_request("Server url is not set"))?; + + // Generate jwt + generate_jwt( + &mut transaction, + &private_key, + &home_page, + &app.id().0, + &user, + cookie_jar, + ) + .await + .map_err(Error::internal_server_error)?; + } + } + transaction.commit().await?; + + Ok(Redirect::to(uri!(settings_security))) +} diff --git a/crates/ezidam/templates/pages/admin/settings_security.html.tera b/crates/ezidam/templates/pages/admin/settings_security.html.tera new file mode 100644 index 0000000..44d3681 --- /dev/null +++ b/crates/ezidam/templates/pages/admin/settings_security.html.tera @@ -0,0 +1,60 @@ +{% extends "shell" %} + +{% block content %} + + + +
+
+
+
+
+
+ +
+
+
+
+

Security

+ +

Logout everyone

+

+ This will force all logged-in users to log in again.
+ This action will become effective immediately. +

+

This might take some time, but should not be long.

+ +
+ + +
+ + + +
+ +
+
+
+
+
+
+
+{% endblock content %}