Add rocket authentication to all routes

This commit is contained in:
2021-11-08 16:38:10 +01:00
parent 212c2e1545
commit 04011e4f1a
17 changed files with 172 additions and 133 deletions

View File

@ -12,6 +12,7 @@ jsonrpc-client-core = "0.5"
jsonrpc-client-http = "0.5"
jsonrpc-core = "8.0.1"
serde = { version = "1.0", features = ["derive"] }
rust-crypto = "0.2.36"
serde_derive = "1.0"
serde_json = "1.0"
serde_yaml = "0.8"

View File

@ -4,12 +4,13 @@
//!
//! The configuration file is located at: "/var/lib/peachcloud/config.yml"
use fslock::LockFile;
use fslock::{LockFile, IntoOsString};
use serde::{Deserialize, Serialize};
use std::fs;
use crate::error::PeachError;
use crate::error::*;
use crate::password_utils::hash_password;
// main configuration file
pub const YAML_PATH: &str = "/var/lib/peachcloud/config.yml";
@ -34,6 +35,10 @@ pub struct PeachConfig {
pub dyn_enabled: bool,
#[serde(default)] // default is empty vector
pub ssb_admin_ids: Vec<String>,
#[serde(default)]
pub admin_password_hash: String,
#[serde(default)]
pub temporary_password_hash: String,
}
// helper functions for serializing and deserializing PeachConfig from disc
@ -69,6 +74,8 @@ pub fn load_peach_config() -> Result<PeachConfig, PeachError> {
dyn_tsig_key_path: "".to_string(),
dyn_enabled: false,
ssb_admin_ids: Vec::new(),
admin_password_hash: "".to_string(),
temporary_password_hash: "".to_string(),
};
}
// otherwise we load peach config from disk
@ -141,3 +148,33 @@ pub fn delete_ssb_admin_id(ssb_id: &str) -> Result<PeachConfig, PeachError> {
}),
}
}
pub fn set_admin_password_hash(password_hash: &str) -> Result<PeachConfig, PeachError> {
let mut peach_config = load_peach_config()?;
peach_config.admin_password_hash = password_hash.to_string();
save_peach_config(peach_config)
}
pub fn get_admin_password_hash() -> Result<String, PeachError> {
let peach_config = load_peach_config()?;
if !peach_config.admin_password_hash.is_empty() {
Ok(peach_config.admin_password_hash)
} else {
Err(PeachError::PasswordNotSet)
}
}
pub fn set_temporary_password_hash(password_hash: &str) -> Result<PeachConfig, PeachError> {
let mut peach_config = load_peach_config()?;
peach_config.temporary_password_hash = password_hash.to_string();
save_peach_config(peach_config)
}
pub fn get_temporary_password_hash() -> Result<String, PeachError> {
let peach_config = load_peach_config()?;
if !peach_config.temporary_password_hash.is_empty() {
Ok(peach_config.temporary_password_hash)
} else {
Err(PeachError::PasswordNotSet)
}
}

View File

@ -63,6 +63,8 @@ pub enum PeachError {
SaveDynDnsResultError { source: std::io::Error },
#[snafu(display("New passwords do not match"))]
PasswordsDoNotMatch,
#[snafu(display("No admin password is set"))]
PasswordNotSet,
#[snafu(display("The supplied password was not correct"))]
InvalidPassword,
#[snafu(display("Error saving new password: {}", msg))]

View File

@ -1,34 +1,24 @@
use crate::config_manager::{get_peachcloud_domain, load_peach_config};
use crate::config_manager::{get_peachcloud_domain, load_peach_config,
set_admin_password_hash, get_admin_password_hash,
get_temporary_password_hash, set_temporary_password_hash};
use crate::error::PeachError;
use crate::error::StdIoError;
use crate::sbot_client;
use log::info;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use snafu::ResultExt;
use std::iter;
use std::process::Command;
/// filepath where nginx basic auth passwords are stored
pub const HTPASSWD_FILE: &str = "/var/lib/peachcloud/passwords/htpasswd";
/// filepath where random temporary password is stored for password resets
pub const HTPASSWD_TEMPORARY_PASSWORD_FILE: &str =
"/var/lib/peachcloud/passwords/temporary_password";
/// the username of the user for nginx basic auth
pub const PEACHCLOUD_AUTH_USER: &str = "admin";
use crypto::digest::Digest;
use crypto::sha3::Sha3;
/// Returns Ok(()) if the supplied password is correct,
/// and returns Err if the supplied password is incorrect.
pub fn verify_password(password: &str) -> Result<(), PeachError> {
let output = Command::new("/usr/bin/htpasswd")
.arg("-vb")
.arg(HTPASSWD_FILE)
.arg(PEACHCLOUD_AUTH_USER)
.arg(password)
.output()
.context(StdIoError {
msg: "htpasswd is not installed",
})?;
if output.status.success() {
let real_admin_password_hash = get_admin_password_hash()?;
let password_hash = hash_password(&password.to_string());
if real_admin_password_hash == password_hash {
Ok(())
} else {
Err(PeachError::InvalidPassword)
@ -49,57 +39,46 @@ pub fn validate_new_passwords(new_password1: &str, new_password2: &str) -> Resul
/// Uses htpasswd to set a new password for the admin user
pub fn set_new_password(new_password: &str) -> Result<(), PeachError> {
let output = Command::new("/usr/bin/htpasswd")
.arg("-cb")
.arg(HTPASSWD_FILE)
.arg(PEACHCLOUD_AUTH_USER)
.arg(new_password)
.output()
.context(StdIoError {
msg: "htpasswd is not installed",
})?;
if output.status.success() {
Ok(())
} else {
let err_output = String::from_utf8(output.stderr)?;
Err(PeachError::FailedToSetNewPassword { msg: err_output })
let new_password_hash = hash_password(&new_password.to_string());
let result = set_admin_password_hash(&new_password_hash);
match result {
Ok(_) => {
Ok(())
},
Err(err) => {
Err(PeachError::FailedToSetNewPassword { msg: "failed to save password hash".to_string() })
}
}
}
/// Creates a hash from a password string
pub fn hash_password(password: &String) -> String {
let mut hasher = Sha3::sha3_256();
hasher.input_str(password);
hasher.result_str()
}
/// Uses htpasswd to set a new temporary password for the admin user
/// which can be used to reset the permanent password
pub fn set_new_temporary_password(new_password: &str) -> Result<(), PeachError> {
let output = Command::new("/usr/bin/htpasswd")
.arg("-cb")
.arg(HTPASSWD_TEMPORARY_PASSWORD_FILE)
.arg(PEACHCLOUD_AUTH_USER)
.arg(new_password)
.output()
.context(StdIoError {
msg: "htpasswd is not installed",
})?;
if output.status.success() {
Ok(())
} else {
let err_output = String::from_utf8(output.stderr)?;
Err(PeachError::FailedToSetNewPassword { msg: err_output })
let new_password_hash = hash_password(&new_password.to_string());
let result = set_temporary_password_hash(&new_password_hash);
match result {
Ok(_) => {
Ok(())
},
Err(err) => {
Err(PeachError::FailedToSetNewPassword { msg: "failed to save temporary password hash".to_string() })
}
}
}
/// Returns Ok(()) if the supplied temp_password is correct,
/// and returns Err if the supplied temp_password is incorrect
pub fn verify_temporary_password(password: &str) -> Result<(), PeachError> {
// TODO: confirm temporary password has not expired
let output = Command::new("/usr/bin/htpasswd")
.arg("-vb")
.arg(HTPASSWD_TEMPORARY_PASSWORD_FILE)
.arg(PEACHCLOUD_AUTH_USER)
.arg(password)
.output()
.context(StdIoError {
msg: "htpasswd is not installed",
})?;
if output.status.success() {
let temporary_admin_password_hash = get_temporary_password_hash()?;
let password_hash = hash_password(&password.to_string());
if temporary_admin_password_hash == password_hash {
Ok(())
} else {
Err(PeachError::InvalidPassword)
@ -143,6 +122,7 @@ using this link: http://peach.local/reset_password",
msg += &remote_link;
// finally send the message to the admins
let peach_config = load_peach_config()?;
info!("sending password reset: {}", msg);
for ssb_admin_id in peach_config.ssb_admin_ids {
sbot_client::private_message(&msg, &ssb_admin_id)?;
}