mirror of
https://github.com/LukeMathWalker/zero-to-production.git
synced 2024-11-22 00:31:01 +00:00
Implement password hashing using Argon2, with PHC string format as storage encoding.
This commit is contained in:
parent
312ee4aa89
commit
7d515138d5
5 changed files with 78 additions and 13 deletions
52
Cargo.lock
generated
52
Cargo.lock
generated
|
@ -250,6 +250,17 @@ version = "1.0.40"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
|
||||
|
||||
[[package]]
|
||||
name = "argon2"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d805bb12b532be9ce066df7913311f43716b41d8d780e9322113e8a6ae7c41ab"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"blake2",
|
||||
"password-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
|
@ -305,6 +316,12 @@ version = "0.13.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
|
@ -323,6 +340,17 @@ dependencies = [
|
|||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake2"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174"
|
||||
dependencies = [
|
||||
"crypto-mac 0.8.0",
|
||||
"digest",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
|
@ -537,6 +565,16 @@ dependencies = [
|
|||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-mac"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-mac"
|
||||
version = "0.10.0"
|
||||
|
@ -930,7 +968,7 @@ version = "0.10.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15"
|
||||
dependencies = [
|
||||
"crypto-mac",
|
||||
"crypto-mac 0.10.0",
|
||||
"digest",
|
||||
]
|
||||
|
||||
|
@ -1380,6 +1418,17 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "password-hash"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ad7268ef9bc463fddde8361d358fbfae1aeeb1fb62eca111cd8c763bf1c5891"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core 0.6.2",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.5"
|
||||
|
@ -2701,6 +2750,7 @@ dependencies = [
|
|||
"actix-rt",
|
||||
"actix-web",
|
||||
"anyhow",
|
||||
"argon2",
|
||||
"base64",
|
||||
"chrono",
|
||||
"claim",
|
||||
|
|
|
@ -36,6 +36,7 @@ tracing-actix-web = "0.4.0-beta.8"
|
|||
anyhow = "1.0.40"
|
||||
base64 = "0.13.0"
|
||||
sha3 = "0.9"
|
||||
argon2 = { version = "0.3", features = ["std"] }
|
||||
|
||||
[dev-dependencies]
|
||||
once_cell = "1.7.2"
|
||||
|
|
1
migrations/20210829175741_add_salt_to_users.sql
Normal file
1
migrations/20210829175741_add_salt_to_users.sql
Normal file
|
@ -0,0 +1 @@
|
|||
ALTER TABLE users ADD COLUMN salt TEXT NOT NULL;
|
1
migrations/20210829200701_remove_salt_from_users.sql
Normal file
1
migrations/20210829200701_remove_salt_from_users.sql
Normal file
|
@ -0,0 +1 @@
|
|||
ALTER TABLE users DROP COLUMN salt;
|
|
@ -4,7 +4,7 @@ use crate::routes::error_chain_fmt;
|
|||
use actix_web::http::{HeaderMap, HeaderValue, StatusCode};
|
||||
use actix_web::{web, HttpResponse, ResponseError};
|
||||
use anyhow::Context;
|
||||
use sha3::Digest;
|
||||
use argon2::{Argon2, PasswordHash, PasswordVerifier};
|
||||
use sqlx::PgPool;
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
|
@ -88,26 +88,38 @@ async fn validate_credentials(
|
|||
credentials: Credentials,
|
||||
pool: &PgPool,
|
||||
) -> Result<uuid::Uuid, PublishError> {
|
||||
let password_hash = sha3::Sha3_256::digest(credentials.password.as_bytes());
|
||||
let password_hash = format!("{:x}", password_hash);
|
||||
let user_id: Option<_> = sqlx::query!(
|
||||
let row: Option<_> = sqlx::query!(
|
||||
r#"
|
||||
SELECT user_id
|
||||
SELECT user_id, password_hash
|
||||
FROM users
|
||||
WHERE username = $1 AND password_hash = $2
|
||||
WHERE username = $1
|
||||
"#,
|
||||
credentials.username,
|
||||
password_hash
|
||||
)
|
||||
.fetch_optional(pool)
|
||||
.await
|
||||
.context("Failed to performed a query to validate auth credentials.")
|
||||
.context("Failed to performed a query to retrieve stored credentials.")
|
||||
.map_err(PublishError::UnexpectedError)?;
|
||||
|
||||
user_id
|
||||
.map(|row| row.user_id)
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid username or password."))
|
||||
.map_err(PublishError::AuthError)
|
||||
let (expected_password_hash, user_id) = match row {
|
||||
Some(row) => (row.password_hash, row.user_id),
|
||||
None => {
|
||||
return Err(PublishError::AuthError(anyhow::anyhow!(
|
||||
"Unknown username."
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
let expected_password_hash = PasswordHash::new(&expected_password_hash)
|
||||
.context("Failed to parse hash in PHC string format.")
|
||||
.map_err(PublishError::UnexpectedError)?;
|
||||
|
||||
Argon2::default()
|
||||
.verify_password(credentials.password.as_bytes(), &expected_password_hash)
|
||||
.context("Invalid password.")
|
||||
.map_err(PublishError::AuthError)?;
|
||||
|
||||
Ok(user_id)
|
||||
}
|
||||
|
||||
#[tracing::instrument(
|
||||
|
|
Loading…
Reference in a new issue