1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
#[cfg(feature = "password_hashing")] use argonautica::{self, Hasher, Verifier}; use crate::ServiceError; /// The `Authenticate` trait of the Aragog library. /// This trait provides the possibility to authenticate a Type with some secret. Its main use /// it to authenticate a user or client [`Record`] model instance. /// /// [`Record`]: trait.Record.html pub trait Authenticate { /// Authenticates the instance with a secret. /// /// # Arguments /// /// * `secret` - the value supposed to validate authentication like a password /// /// # Returns /// /// On success `()` is returned, on failure it will return a [`ServiceError`] according to /// the Authenticate implementation /// /// [`ServiceError`]: enum.ServiceError.html fn authenticate(&self, secret: &str) -> Result<(), ServiceError>; /// Returns a Argon2 encrypted password hash that can be safely stored in database. /// /// # Arguments /// /// * `password` - The actual password to encrypt, should be checked for length and complexity /// * `secret_key` - The key that Argon2 will use to hash the password, this key should be unique /// and set as an environment variable or retrieved from some vault. /// /// # Returns /// /// On success the hashed password is returned, if the hashing fails for some reason /// (password or secret key invalid format) a [`ServiceError`]::[`UnprocessableEntity`] will be returned. /// /// # Features /// /// This function requires the `password_hashing` feature to be enabled. /// /// [`ServiceError`]: enum.ServiceError.html /// [`UnprocessableEntity`]: enum.ServiceError.html#variant.UnprocessableEntity #[cfg(feature = "password_hashing")] fn hash_password(password: &str, secret_key: &str) -> Result<String, ServiceError> { let mut hasher = Hasher::new(); let res = hasher .with_password(password) .with_secret_key(secret_key) .hash(); match res { Ok(value) => Ok(value), // TODO: Use UnprocessableEntity when argonautica supports Error Err(error) => Err(ServiceError::InternalError { message: Some(error.to_string()), }), } } /// Verifies if the given password matches the Argon2 encrypted password hash. /// /// # Arguments /// /// * `password` - The actual password to verify /// * `password_hash` - The Argon2 encrypted hash password that should match the `password` /// * `secret_key` - The key that Argon2 will use to hash the password, this key should be unique /// and set as an environment variable or retrieved from some vault. /// /// # Returns /// /// On failure a [`ServiceError`]::[`Unauthorized`] will be returned. /// /// # Features /// /// This function requires the `password_hashing` feature to be enabled. /// /// [`ServiceError`]: enum.ServiceError.html /// [`Unauthorized`]: enum.ServiceError.html#variant.Unauthorized #[cfg(feature = "password_hashing")] fn verify_password( password: &str, password_hash: &str, secret_key: &str, ) -> Result<(), ServiceError> { let mut verifier = Verifier::new(); match verifier .with_hash(password_hash) .with_password(password) .with_secret_key(secret_key) .verify() { Ok(value) => { if value { Ok(()) } else { Err(ServiceError::Unauthorized) } } // TODO: Use UnprocessableEntity when argonautica supports Error Err(error) => Err(ServiceError::InternalError { message: Some(error.to_string()), }), } } }