From 6782fecc0d6da4c079193d166e5b65eaccd04b49 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Sat, 21 Aug 2021 13:46:41 +0200 Subject: [PATCH] Started JWT token generation --- Cargo.lock | 163 +++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 6 +- src/rb/auth.rs | 31 +++++++++ src/rb/models.rs | 9 ++- src/rbs/auth.rs | 3 + 5 files changed, 203 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 54bf4b6..8d50653 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,6 +107,15 @@ dependencies = [ "constant_time_eq", ] +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.7.0" @@ -137,6 +146,19 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time 0.1.44", + "winapi", +] + [[package]] name = "const_fn" version = "0.4.8" @@ -156,10 +178,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d" dependencies = [ "percent-encoding", - "time", + "time 0.2.27", "version_check", ] +[[package]] +name = "cpufeatures" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-utils" version = "0.8.5" @@ -170,6 +201,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "devise" version = "0.3.1" @@ -238,6 +279,15 @@ dependencies = [ "migrations_macros", ] +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "discard" version = "1.0.4" @@ -401,6 +451,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.3" @@ -452,6 +512,16 @@ dependencies = [ "libc", ] +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest", +] + [[package]] name = "http" version = "0.2.4" @@ -542,6 +612,21 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +[[package]] +name = "jwt" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7487a802642fa9b162acacad3ed52c7e47ed4108d5fac6125cc7742dfaf622bf" +dependencies = [ + "base64", + "crypto-mac", + "digest", + "hmac", + "serde", + "serde_json", + "sha2", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -669,6 +754,25 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.13.0" @@ -685,6 +789,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "openssl" version = "0.10.36" @@ -961,7 +1071,7 @@ dependencies = [ "serde_json", "state", "tempfile", - "time", + "time 0.2.27", "tokio", "tokio-stream", "tokio-util", @@ -1009,7 +1119,7 @@ dependencies = [ "smallvec", "stable-pattern", "state", - "time", + "time 0.2.27", "tokio", "uncased", ] @@ -1069,14 +1179,18 @@ checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" name = "rusty-bever" version = "0.1.0" dependencies = [ + "chrono", "diesel", "diesel_migrations", + "hmac", + "jwt", "openssl", "rand", "rocket", "rocket_sync_db_pools", "rust-argon2", "serde", + "sha2", "uuid", ] @@ -1159,6 +1273,19 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" +[[package]] +name = "sha2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -1272,6 +1399,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" version = "1.0.74" @@ -1297,6 +1430,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + [[package]] name = "time" version = "0.2.27" @@ -1441,6 +1585,12 @@ dependencies = [ "unchecked-index", ] +[[package]] +name = "typenum" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" + [[package]] name = "ubyte" version = "0.10.1" @@ -1477,6 +1627,9 @@ name = "uuid" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "serde", +] [[package]] name = "vcpkg" @@ -1502,9 +1655,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" diff --git a/Cargo.toml b/Cargo.toml index fb5cd1f..c669974 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,11 @@ openssl = "0.10.36" # For password hashing & verification rust-argon2 = "0.8.3" rand = "0.8.4" -uuid = "0.8.2" +uuid = { version = "0.8.2", features = ["serde"] } +jwt = "0.14.0" +hmac = "*" +sha2 = "*" +chrono = "0.4.19" # Backend web framework [dependencies.rocket] diff --git a/src/rb/auth.rs b/src/rb/auth.rs index 2c8dbee..645cd08 100644 --- a/src/rb/auth.rs +++ b/src/rb/auth.rs @@ -4,6 +4,16 @@ use crate::schema::users::dsl as users; use argon2::verify_encoded; use diesel::prelude::*; use diesel::PgConnection; +use hmac::{Hmac, NewMac}; +use jwt::SignWithKey; +use sha2::Sha256; +use std::collections::HashMap; +use chrono::Utc; + +/// Expire time for the JWT tokens in seconds. +const JWT_EXP_SECONDS: i64 = 900; +/// Amount of bytes the refresh tokens should consist of +const REFRESH_TOKEN_N_BYTES: u32 = 64; pub fn verify_user(conn: &PgConnection, username: &str, password: &str) -> Result { // TODO handle non-"NotFound" Diesel errors accordingely @@ -20,3 +30,24 @@ pub fn verify_user(conn: &PgConnection, username: &str, password: &str) -> Resul _ => Err(AuthError::InvalidPassword), } } + +struct JWTResponse { + token: String, + refresh_token: String +} + +pub fn generate_jwt_token(conn: &PgConnection, user: &User) -> JWTResponse { + // TODO actually use proper secret here + // TODO don't just unwrap here + let key: Hmac = Hmac::new_from_slice(b"some-secret").unwrap(); + + // Create the claims + let mut claims = HashMap::new(); + claims.insert("id", user.id.to_string()); + claims.insert("username", user.username); + claims.insert("exp", (Utc::now().timestamp() + JWT_EXP_SECONDS).to_string()); + + // Sign the claims into a new token + // TODO don't just unwrap here + let token = claims.sign_with_key(&key).unwrap(); +} diff --git a/src/rb/models.rs b/src/rb/models.rs index d9455d6..0357366 100644 --- a/src/rb/models.rs +++ b/src/rb/models.rs @@ -1,11 +1,14 @@ use diesel::Queryable; use uuid::Uuid; +use serde::Serialize; -#[derive(Queryable)] +#[derive(Queryable, Serialize)] pub struct User { - id: Uuid, - username: String, + pub id: Uuid, + pub username: String, + #[serde(skip_serializing)] pub password: String, + #[serde(skip_serializing)] blocked: bool, admin: bool, } diff --git a/src/rbs/auth.rs b/src/rbs/auth.rs index 1c9d793..19f43a3 100644 --- a/src/rbs/auth.rs +++ b/src/rbs/auth.rs @@ -11,9 +11,12 @@ struct Credentials { #[post("/login", data = "")] async fn login(conn: RbDbConn, credentials: Json) { + let credentials = credentials.into_inner(); + let user = conn .run(move |c| verify_user(c, &credentials.username, &credentials.password)) .await; + user } // /refresh