From 26c8e38c862ba14c8d7fc0075781a61adfc1ae7e Mon Sep 17 00:00:00 2001 From: trivernis Date: Fri, 13 Nov 2020 18:25:40 +0100 Subject: [PATCH] Add method to delete users Signed-off-by: trivernis --- src/database/permissions.rs | 2 ++ src/database/users.rs | 12 +++++++++++ src/server/http_server.rs | 43 +++++++++++++++++++++++++++++++++---- src/server/messages.rs | 12 +++++++++++ 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/database/permissions.rs b/src/database/permissions.rs index fc00d67..b9df05f 100644 --- a/src/database/permissions.rs +++ b/src/database/permissions.rs @@ -15,6 +15,7 @@ pub(crate) const ROLE_DELETE_PERM: &str = "ROLE_DELETE"; pub(crate) const USER_UPDATE_PERM: &str = "USER_UPDATE"; pub(crate) const USER_VIEW_PERM: &str = "USER_VIEW"; pub(crate) const USER_CREATE_PERM: &str = "USER_CREATE"; +pub(crate) const USER_DELETE_PERM: &str = "USER_DELETE"; pub(crate) const USER_MANAGEMENT_PERMISSIONS: &[(&'static str, &'static str)] = &[ (ROLE_CREATE_PERM, "Allows the user to create roles"), @@ -27,6 +28,7 @@ pub(crate) const USER_MANAGEMENT_PERMISSIONS: &[(&'static str, &'static str)] = ), (USER_VIEW_PERM, "Allows to see information of users"), (USER_CREATE_PERM, "Allows the creation of new users"), + (USER_DELETE_PERM, "Allows the deletion of users"), ]; /// The permissions table that stores defined diff --git a/src/database/users.rs b/src/database/users.rs index 3278029..59e0548 100644 --- a/src/database/users.rs +++ b/src/database/users.rs @@ -165,6 +165,18 @@ impl Users { Ok(users) } + pub fn delete_user(&self, email: &String) -> DatabaseResult<()> { + log::trace!("Deleting user with email {}", email); + let mut connection = self.pool.get()?; + let exists = connection.query_opt("SELECT id FROM users WHERE email = $1", &[email])?; + if exists.is_none() { + return Err(DBError::RecordDoesNotExist); + } + connection.query("DELETE FROM users WHERE email = $1", &[email])?; + + Ok(()) + } + /// Creates new tokens for a user login that can be used by services /// that need those tokens to verify a user login pub fn create_tokens( diff --git a/src/server/http_server.rs b/src/server/http_server.rs index 44b1c9c..c64b0a8 100644 --- a/src/server/http_server.rs +++ b/src/server/http_server.rs @@ -14,14 +14,15 @@ use serde::Serialize; use crate::database::models::{Role, UserFullInformation, UserInformation}; use crate::database::permissions::{ ROLE_CREATE_PERM, ROLE_DELETE_PERM, ROLE_UPDATE_PERM, ROLE_VIEW_PERM, USER_CREATE_PERM, - USER_UPDATE_PERM, USER_VIEW_PERM, + USER_DELETE_PERM, USER_UPDATE_PERM, USER_VIEW_PERM, }; use crate::database::tokens::SessionTokens; use crate::database::Database; use crate::server::documentation::RESTDocumentation; use crate::server::messages::{ - CreateUserRequest, DeleteRoleResponse, ErrorMessage, FullRoleData, LoginMessage, - LogoutConfirmation, LogoutMessage, ModifyRoleRequest, RefreshMessage, UpdateUserRequest, + CreateUserRequest, DeleteRoleResponse, DeleteUserRequest, DeleteUserResponse, ErrorMessage, + FullRoleData, LoginMessage, LogoutConfirmation, LogoutMessage, ModifyRoleRequest, + RefreshMessage, UpdateUserRequest, }; use crate::utils::error::DBError; use crate::utils::get_user_id_from_token; @@ -141,6 +142,9 @@ impl UserHttpServer { (POST) (/users/{email: String}/update) => { Self::update_user(&database, request, email).unwrap_or_else(HTTPError::into) }, + (POST) (/users/{email: String}/delete) => { + Self::delete_user(&database, request, email).unwrap_or_else(HTTPError::into) + }, _ => if request.method() == "OPTIONS" { Response::empty_204() } else { @@ -230,6 +234,11 @@ impl UserHttpServer { "POST", "Creates a new user", )?; + doc.add_path::( + "/users/{email:String}/delete", + "POST", + "Deletes a user", + )?; Ok(doc) } @@ -399,7 +408,7 @@ impl UserHttpServer { Ok(Response::json(&UserInformation::from(result)).with_status_code(201)) } - /// Updates the information of a user + /// Updates the information of a user. This requires the operating user to revalidate his password fn update_user(database: &Database, request: &Request, email: String) -> HTTPResult { let (_, id) = validate_request_token(request, database)?; let message = deserialize_body::(&request)?; @@ -427,6 +436,32 @@ impl UserHttpServer { Ok(Response::json(&record)) } + + /// Deletes a user completely + fn delete_user(database: &Database, request: &Request, email: String) -> HTTPResult { + let (_, id) = validate_request_token(request, database)?; + let message = deserialize_body::(&request)?; + let logged_in_user = database.users.get_user(id)?; + + if !database + .users + .validate_login(&logged_in_user.email, &message.own_password)? + { + return Err(HTTPError::new( + "Invalid authentication data".to_string(), + 401, + )); + } + if !database.users.has_permission(id, USER_DELETE_PERM)? { + return Err(HTTPError::new("Insufficient permissions".to_string(), 403)); + } + database.users.delete_user(&email)?; + + Ok(Response::json(&DeleteUserResponse { + success: true, + email, + })) + } } /// Parses the body of a http request into a string representation diff --git a/src/server/messages.rs b/src/server/messages.rs index a06192a..85bf895 100644 --- a/src/server/messages.rs +++ b/src/server/messages.rs @@ -136,3 +136,15 @@ pub struct CreateUserRequest { pub email: String, pub password: String, } + +#[derive(Deserialize, JsonSchema, Zeroize)] +#[zeroize(drop)] +pub struct DeleteUserRequest { + pub own_password: String, +} + +#[derive(Serialize, JsonSchema)] +pub struct DeleteUserResponse { + pub email: String, + pub success: bool, +}