server: Send an email for password resets

This commit is contained in:
Valentin Tolmer 2021-11-21 18:56:16 +01:00 committed by nitnelave
parent db2b5cbae0
commit 789c8f367e
3 changed files with 75 additions and 7 deletions

View File

@ -23,6 +23,7 @@ use futures_util::{FutureExt, TryFutureExt};
use hmac::Hmac;
use jwt::{SignWithKey, VerifyWithKey};
use lldap_auth::{login, registration, JWTClaims};
use log::*;
use sha2::Sha512;
use std::collections::{hash_map::DefaultHasher, HashSet};
use std::hash::{Hash, Hasher};
@ -123,12 +124,27 @@ where
None => return HttpResponse::BadRequest().body("Missing user ID"),
Some(id) => id,
};
let _token = match data.backend_handler.start_password_reset(user_id).await {
let token = match data.backend_handler.start_password_reset(user_id).await {
Err(e) => return HttpResponse::InternalServerError().body(e.to_string()),
Ok(None) => return HttpResponse::Ok().finish(),
Ok(Some(token)) => token,
};
// TODO: Send email.
let user = match data.backend_handler.get_user_details(user_id).await {
Err(e) => {
warn!("Error getting used details: {:#?}", e);
return HttpResponse::Ok().finish();
}
Ok(u) => u,
};
if let Err(e) = super::mail::send_password_reset_email(
&user.display_name,
&user.email,
&token,
&data.server_url,
&data.mail_options,
) {
warn!("Error sending email: {:#?}", e);
}
HttpResponse::Ok().finish()
}

View File

@ -6,7 +6,7 @@ use lettre::{
};
use log::debug;
pub fn send_test_email(to: Mailbox, options: &MailOptions) -> Result<()> {
fn send_email(to: Mailbox, subject: &str, body: String, options: &MailOptions) -> Result<()> {
let from = options
.from
.clone()
@ -20,8 +20,8 @@ pub fn send_test_email(to: Mailbox, options: &MailOptions) -> Result<()> {
.from(from)
.reply_to(reply_to)
.to(to)
.subject("LLDAP test email")
.body("The test is successful! You can send emails from LLDAP".to_string())?;
.subject(subject)
.body(body)?;
let creds = Credentials::new(
options.user.clone(),
options.password.unsecure().to_string(),
@ -32,3 +32,34 @@ pub fn send_test_email(to: Mailbox, options: &MailOptions) -> Result<()> {
mailer.send(&email)?;
Ok(())
}
pub fn send_password_reset_email(
username: &str,
to: &str,
token: &str,
domain: &str,
options: &MailOptions,
) -> Result<()> {
let to = to.parse()?;
let body = format!(
"Hello {},
This email has been sent to you in order to validate your identity.
If you did not initiate the process your credentials might have been
compromised. You should reset your password and contact an administrator.
To reset your password please visit the following URL: {}/reset-password/step2/{}
Please contact an administrator if you did not initiate the process.",
username, domain, token
);
send_email(to, "[LLDAP] Password reset requested", body, options)
}
pub fn send_test_email(to: Mailbox, options: &MailOptions) -> Result<()> {
send_email(
to,
"LLDAP test email",
"The test is successful! You can send emails from LLDAP".to_string(),
options,
)
}

View File

@ -4,7 +4,11 @@ use crate::{
handler::{BackendHandler, LoginHandler},
opaque_handler::OpaqueHandler,
},
infra::{auth_service, configuration::Configuration, tcp_backend_handler::*},
infra::{
auth_service,
configuration::{Configuration, MailOptions},
tcp_backend_handler::*,
},
};
use actix_files::{Files, NamedFile};
use actix_http::HttpServiceBuilder;
@ -46,6 +50,8 @@ fn http_config<Backend>(
backend_handler: Backend,
jwt_secret: secstr::SecUtf8,
jwt_blacklist: HashSet<u64>,
server_url: String,
mail_options: MailOptions,
) where
Backend: TcpBackendHandler + BackendHandler + LoginHandler + OpaqueHandler + Sync + 'static,
{
@ -53,6 +59,8 @@ fn http_config<Backend>(
backend_handler,
jwt_key: Hmac::new_varkey(jwt_secret.unsecure().as_bytes()).unwrap(),
jwt_blacklist: RwLock::new(jwt_blacklist),
server_url,
mail_options,
}))
// Serve index.html and main.js, and default to index.html.
.route(
@ -76,6 +84,8 @@ pub(crate) struct AppState<Backend> {
pub backend_handler: Backend,
pub jwt_key: Hmac<Sha512>,
pub jwt_blacklist: RwLock<HashSet<u64>>,
pub server_url: String,
pub mail_options: MailOptions,
}
pub async fn build_tcp_server<Backend>(
@ -91,15 +101,26 @@ where
.get_jwt_blacklist()
.await
.context("while getting the jwt blacklist")?;
let server_url = config.http_url.clone();
let mail_options = config.smtp_options.clone();
server_builder
.bind("http", ("0.0.0.0", config.http_port), move || {
let backend_handler = backend_handler.clone();
let jwt_secret = jwt_secret.clone();
let jwt_blacklist = jwt_blacklist.clone();
let server_url = server_url.clone();
let mail_options = mail_options.clone();
HttpServiceBuilder::new()
.finish(map_config(
App::new().configure(move |cfg| {
http_config(cfg, backend_handler, jwt_secret, jwt_blacklist)
http_config(
cfg,
backend_handler,
jwt_secret,
jwt_blacklist,
server_url,
mail_options,
)
}),
|_| AppConfig::default(),
))