BasicOIDC/src/controllers/admin_controller.rs

227 lines
6.7 KiB
Rust
Raw Normal View History

2022-04-07 15:04:05 +00:00
use std::ops::Deref;
2022-04-06 16:03:00 +00:00
use actix::Addr;
2022-11-11 11:26:02 +00:00
use actix_web::{web, HttpResponse, Responder};
2022-04-06 15:18:06 +00:00
use askama::Template;
2022-04-06 16:03:00 +00:00
use crate::actors::users_actor;
use crate::actors::users_actor::UsersActor;
2022-04-07 16:59:48 +00:00
use crate::constants::TEMPORARY_PASSWORDS_LEN;
2022-04-06 15:18:06 +00:00
use crate::controllers::settings_controller::BaseSettingsPage;
2022-11-19 12:38:24 +00:00
use crate::data::action_logger::{Action, ActionLogger};
2022-04-07 16:59:48 +00:00
use crate::data::client::{Client, ClientID, ClientManager};
2022-04-06 15:18:06 +00:00
use crate::data::current_user::CurrentUser;
2022-04-07 16:59:48 +00:00
use crate::data::user::{hash_password, User, UserID};
use crate::utils::string_utils::rand_str;
2022-04-06 15:18:06 +00:00
#[derive(Template)]
#[template(path = "settings/clients_list.html")]
struct ClientsListTemplate {
2022-04-18 15:13:41 +00:00
_p: BaseSettingsPage,
2022-04-06 15:18:06 +00:00
clients: Vec<Client>,
}
2022-04-06 16:03:00 +00:00
#[derive(Template)]
#[template(path = "settings/users_list.html")]
struct UsersListTemplate {
2022-04-18 15:13:41 +00:00
_p: BaseSettingsPage,
2022-04-06 16:03:00 +00:00
users: Vec<User>,
}
2022-04-07 15:04:05 +00:00
#[derive(Template)]
#[template(path = "settings/edit_user.html")]
struct EditUserTemplate {
2022-04-18 15:13:41 +00:00
_p: BaseSettingsPage,
2022-04-07 15:04:05 +00:00
u: User,
clients: Vec<Client>,
}
2022-04-06 15:18:06 +00:00
pub async fn clients_route(user: CurrentUser, clients: web::Data<ClientManager>) -> impl Responder {
2022-11-11 11:26:02 +00:00
HttpResponse::Ok().body(
ClientsListTemplate {
_p: BaseSettingsPage::get("Clients list", &user, None, None),
clients: clients.cloned(),
}
.render()
.unwrap(),
)
2022-04-06 16:03:00 +00:00
}
2022-04-07 16:59:48 +00:00
#[derive(serde::Deserialize, Debug)]
pub struct UpdateUserQuery {
uid: UserID,
username: String,
first_name: String,
last_name: String,
email: String,
gen_new_password: Option<String>,
enabled: Option<String>,
two_factor_exemption_after_successful_login: Option<String>,
2022-04-07 16:59:48 +00:00
admin: Option<String>,
grant_type: String,
granted_clients: String,
two_factor: String,
clear_2fa_history: Option<String>,
2022-04-07 16:59:48 +00:00
}
2022-11-11 11:26:02 +00:00
pub async fn users_route(
user: CurrentUser,
users: web::Data<Addr<UsersActor>>,
update_query: Option<web::Form<UpdateUserQuery>>,
2022-11-19 12:38:24 +00:00
logger: ActionLogger,
2022-11-11 11:26:02 +00:00
) -> impl Responder {
2022-04-07 16:59:48 +00:00
let mut danger = None;
let mut success = None;
if let Some(update) = update_query {
2022-11-11 11:26:02 +00:00
let current_user: Option<User> = users
.send(users_actor::FindUserByUsername(update.username.to_string()))
.await
.unwrap()
.0;
2022-04-07 16:59:48 +00:00
let is_creating = current_user.is_none();
let mut user = current_user.unwrap_or_default();
user.uid = update.0.uid;
user.username = update.0.username;
user.first_name = update.0.first_name;
user.last_name = update.0.last_name;
user.email = update.0.email;
user.enabled = update.0.enabled.is_some();
user.two_factor_exemption_after_successful_login = update
.0
.two_factor_exemption_after_successful_login
.is_some();
2022-04-07 16:59:48 +00:00
user.admin = update.0.admin.is_some();
let factors_to_keep = update.0.two_factor.split(';').collect::<Vec<_>>();
2022-11-11 11:26:02 +00:00
user.two_factor
.retain(|f| factors_to_keep.contains(&f.id.0.as_str()));
2022-04-07 16:59:48 +00:00
user.authorized_clients = match update.0.grant_type.as_str() {
"all_clients" => None,
2022-11-11 11:26:02 +00:00
"custom_clients" => Some(
update
.0
.granted_clients
.split(',')
.map(|c| ClientID(c.to_string()))
.collect::<Vec<_>>(),
),
_ => Some(Vec::new()),
2022-04-07 16:59:48 +00:00
};
let new_password = match update.0.gen_new_password.is_some() {
false => None,
true => {
2022-11-19 12:38:24 +00:00
logger.log(Action::AdminResetUserPassword(&user));
2022-04-07 16:59:48 +00:00
let temp_pass = rand_str(TEMPORARY_PASSWORDS_LEN);
2022-11-11 11:26:02 +00:00
user.password = hash_password(&temp_pass).expect("Failed to hash password");
2022-04-07 16:59:48 +00:00
user.need_reset_password = true;
user.last_successful_2fa = Default::default();
2022-04-07 16:59:48 +00:00
Some(temp_pass)
}
};
if update.0.clear_2fa_history.is_some() {
2022-11-19 12:38:24 +00:00
logger.log(Action::AdminClear2FAHistory(&user));
user.last_successful_2fa = Default::default();
}
2022-11-11 11:26:02 +00:00
let res = users
.send(users_actor::UpdateUserRequest(user.clone()))
.await
.unwrap()
.0;
2022-04-07 16:59:48 +00:00
if !res {
2022-11-11 11:26:02 +00:00
danger = Some(
match is_creating {
true => "Failed to create user!",
false => "Failed to update user!",
}
.to_string(),
)
2022-04-07 16:59:48 +00:00
} else {
success = Some(match is_creating {
2022-11-19 12:38:24 +00:00
true => {
logger.log(Action::AdminCreateUser(&user));
format!("User {} was successfully created!", user.full_name())
}
false => {
logger.log(Action::AdminUpdateUser(&user));
format!("User {} was successfully updated!", user.full_name())
}
2022-04-07 17:00:36 +00:00
});
2022-04-07 16:59:48 +00:00
if let Some(pass) = new_password {
2022-11-11 11:26:02 +00:00
danger = Some(format!(
"{}'s temporary password is {}",
user.full_name(),
pass
));
2022-04-07 16:59:48 +00:00
}
}
}
2022-04-06 16:03:00 +00:00
let users = users.send(users_actor::GetAllUsersRequest).await.unwrap().0;
2022-11-11 11:26:02 +00:00
HttpResponse::Ok().body(
UsersListTemplate {
_p: BaseSettingsPage::get("Users list", &user, danger, success),
users,
}
.render()
.unwrap(),
)
2022-04-07 15:04:05 +00:00
}
pub async fn create_user(user: CurrentUser, clients: web::Data<ClientManager>) -> impl Responder {
2022-11-11 11:26:02 +00:00
HttpResponse::Ok().body(
EditUserTemplate {
_p: BaseSettingsPage::get("Create a new user", user.deref(), None, None),
u: Default::default(),
clients: clients.cloned(),
}
.render()
.unwrap(),
)
2022-04-08 14:28:19 +00:00
}
#[derive(serde::Deserialize)]
pub struct EditUserQuery {
id: UserID,
}
2022-11-11 11:26:02 +00:00
pub async fn edit_user(
user: CurrentUser,
clients: web::Data<ClientManager>,
users: web::Data<Addr<UsersActor>>,
query: web::Query<EditUserQuery>,
2022-04-08 14:28:19 +00:00
) -> impl Responder {
2022-11-11 11:26:02 +00:00
let edited_account = users
.send(users_actor::GetUserRequest(query.0.id))
.await
.unwrap()
.0;
HttpResponse::Ok().body(
EditUserTemplate {
_p: BaseSettingsPage::get(
"Edit user account",
user.deref(),
match edited_account.is_none() {
true => Some("Could not find requested user!".to_string()),
false => None,
},
None,
),
u: edited_account.unwrap_or_default(),
clients: clients.cloned(),
}
.render()
.unwrap(),
)
2022-04-08 14:28:19 +00:00
}