Implement the set password method
This commit is contained in:
parent
f0517ef0b7
commit
1908d0a0d7
|
@ -9,7 +9,7 @@ repository = "https://github.com/panicbit/northstar"
|
|||
documentation = "https://docs.rs/northstar"
|
||||
|
||||
[features]
|
||||
user_management = ["sled", "bincode", "serde/derive", "bcrypt", "crc32fast"]
|
||||
user_management = ["sled", "bincode", "serde/derive", "rust-argon2", "crc32fast", "ring"]
|
||||
default = ["serve_dir"]
|
||||
serve_dir = ["mime_guess", "tokio/fs"]
|
||||
|
||||
|
@ -31,6 +31,7 @@ bincode = { version = "1.3.1", optional = true }
|
|||
serde = { version = "1.0", optional = true }
|
||||
rust-argon2 = { version = "0.8.2", optional = true }
|
||||
crc32fast = { version = "1.2.1", optional = true }
|
||||
ring = { version = "0.16.15", optional = true }
|
||||
|
||||
[[example]]
|
||||
name = "user_management"
|
||||
|
|
|
@ -26,6 +26,22 @@ use crate::user_management::UserManager;
|
|||
use crate::user_management::Result;
|
||||
use crate::user_management::manager::CertificateData;
|
||||
|
||||
const ARGON2_CONFIG: argon2::Config = argon2::Config {
|
||||
ad: &[],
|
||||
hash_length: 32,
|
||||
lanes: 1,
|
||||
mem_cost: 4096,
|
||||
secret: &[],
|
||||
thread_mode: argon2::ThreadMode::Sequential,
|
||||
time_cost: 3,
|
||||
variant: argon2::Variant::Argon2id,
|
||||
version: argon2::Version::Version13,
|
||||
};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref RANDOM: ring::rand::SystemRandom = ring::rand::SystemRandom::new();
|
||||
}
|
||||
|
||||
/// An struct corresponding to the data stored in the user tree
|
||||
///
|
||||
/// In order to generate a full user obj, you need to perform a lookup with a specific
|
||||
|
@ -34,7 +50,7 @@ use crate::user_management::manager::CertificateData;
|
|||
pub struct PartialUser<UserData> {
|
||||
pub data: UserData,
|
||||
pub certificates: Vec<u32>,
|
||||
pub pass_hash: Option<String>,
|
||||
pub pass_hash: Option<(Vec<u8>, [u8; 32])>,
|
||||
}
|
||||
|
||||
impl<UserData> PartialUser<UserData> {
|
||||
|
@ -46,11 +62,6 @@ impl<UserData> PartialUser<UserData> {
|
|||
&self.certificates
|
||||
}
|
||||
|
||||
/// The bcrypt hash of the user's password
|
||||
pub fn pass_hash(&self) -> Option<&str> {
|
||||
self.pass_hash.as_deref()
|
||||
}
|
||||
|
||||
/// Write user data to the database
|
||||
///
|
||||
/// This MUST be called if the user data is modified using the AsMut trait, or else
|
||||
|
@ -258,13 +269,48 @@ impl<UserData: Serialize + DeserializeOwned> SignedInUser<UserData> {
|
|||
&self,
|
||||
try_password: impl AsRef<[u8]>
|
||||
) -> Result<bool> {
|
||||
if let Some(hash) = &self.inner.pass_hash {
|
||||
Ok(argon2::verify_encoded(hash.as_str(), try_password.as_ref())?)
|
||||
if let Some((hash, salt)) = &self.inner.pass_hash {
|
||||
Ok(argon2::verify_raw(
|
||||
try_password.as_ref(),
|
||||
salt,
|
||||
hash.as_ref(),
|
||||
&ARGON2_CONFIG,
|
||||
)?)
|
||||
} else {
|
||||
Err(super::UserManagerError::PasswordNotSet)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set's the password for this user
|
||||
///
|
||||
/// By default, users have no password, meaning the cannot add any certificates beyond
|
||||
/// the one they created their account with. However, by setting their password,
|
||||
/// users are able to add more devices to their account, and recover their account if
|
||||
/// it's lost. Note that this will completely overwrite the users old password.
|
||||
///
|
||||
/// Use [`SignedInUser::check_password()`] and [`NotSignedInUser::attach()`] to check
|
||||
/// the password against another one, or to link a new certificate.
|
||||
///
|
||||
/// Because this method uses a key derivation algorithm, this should be considered a
|
||||
/// very expensive operation.
|
||||
pub fn set_password(
|
||||
&mut self,
|
||||
password: impl AsRef<[u8]>,
|
||||
) -> Result<()> {
|
||||
let salt: [u8; 32] = ring::rand::generate(&*RANDOM)
|
||||
.expect("Error generating random salt")
|
||||
.expose();
|
||||
self.inner.pass_hash = Some((
|
||||
argon2::hash_raw(
|
||||
password.as_ref(),
|
||||
salt.as_ref(),
|
||||
&ARGON2_CONFIG,
|
||||
)?,
|
||||
salt,
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write any updates to the user to the database.
|
||||
///
|
||||
/// Updates caused by calling methods directly on the user do not need to be saved.
|
||||
|
|
Loading…
Reference in a new issue