First successful JWT token request achieved

develop
Jef Roosens 2021-08-21 18:51:29 +02:00
parent 0d4d96d761
commit 13259249fd
Signed by untrusted user: Jef Roosens
GPG Key ID: 955C0660072F691F
4 changed files with 25 additions and 9 deletions

2
Cargo.lock generated
View File

@ -155,6 +155,7 @@ dependencies = [
"libc", "libc",
"num-integer", "num-integer",
"num-traits", "num-traits",
"serde",
"time 0.1.44", "time 0.1.44",
"winapi", "winapi",
] ]
@ -252,6 +253,7 @@ checksum = "bba51ca66f57261fd17cadf8b73e4775cc307d0521d855de3f5de91a8f074e0e"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"byteorder", "byteorder",
"chrono",
"diesel_derives", "diesel_derives",
"pq-sys", "pq-sys",
"r2d2", "r2d2",

View File

@ -16,7 +16,7 @@ path = "src/rbs/main.rs"
[dependencies] [dependencies]
# ORM # ORM
diesel = { version = "1.4.7", features = ["postgres", "uuidv07"] } diesel = { version = "1.4.7", features = ["postgres", "uuidv07", "chrono"] }
diesel_migrations = "1.4.0" diesel_migrations = "1.4.0"
# To properly compile libpq statically # To properly compile libpq statically
openssl = "0.10.36" openssl = "0.10.36"
@ -27,7 +27,7 @@ uuid = { version = "0.8.2", features = ["serde"] }
jwt = "0.14.0" jwt = "0.14.0"
hmac = "*" hmac = "*"
sha2 = "*" sha2 = "*"
chrono = "0.4.19" chrono = { version = "*", features = [ "serde" ] }
base64 = "0.13.0" base64 = "0.13.0"
# Backend web framework # Backend web framework

View File

@ -17,6 +17,14 @@ use std::collections::HashMap;
const JWT_EXP_SECONDS: i64 = 900; const JWT_EXP_SECONDS: i64 = 900;
/// Amount of bytes the refresh tokens should consist of /// Amount of bytes the refresh tokens should consist of
const REFRESH_TOKEN_N_BYTES: usize = 64; const REFRESH_TOKEN_N_BYTES: usize = 64;
/// Expire time for refresh tokens; here: one week
const REFRESH_TOKEN_EXP_SECONDS: i64 = 36288000;
fn log<T>(message: &str, o: T) -> T {
println!("{}", message);
o
}
pub fn verify_user(conn: &PgConnection, username: &str, password: &str) -> crate::Result<User> { pub fn verify_user(conn: &PgConnection, username: &str, password: &str) -> crate::Result<User> {
// TODO handle non-"NotFound" Diesel errors accordingely // TODO handle non-"NotFound" Diesel errors accordingely
@ -46,7 +54,9 @@ pub struct JWTResponse {
pub fn generate_jwt_token(conn: &PgConnection, user: &User) -> crate::Result<JWTResponse> { pub fn generate_jwt_token(conn: &PgConnection, user: &User) -> crate::Result<JWTResponse> {
// TODO actually use proper secret here // TODO actually use proper secret here
let key: Hmac<Sha256> = let key: Hmac<Sha256> =
Hmac::new_from_slice(b"some-secret").map_err(|_| RBError::JWTCreationError)?; Hmac::new_from_slice(b"some-secret").map_err(|_| log("Failed to create key", RBError::JWTCreationError))?;
let current_time = Utc::now();
// Create the claims // Create the claims
let mut claims = HashMap::new(); let mut claims = HashMap::new();
@ -55,23 +65,27 @@ pub fn generate_jwt_token(conn: &PgConnection, user: &User) -> crate::Result<JWT
claims.insert("admin", user.admin.to_string()); claims.insert("admin", user.admin.to_string());
claims.insert( claims.insert(
"exp", "exp",
(Utc::now().timestamp() + JWT_EXP_SECONDS).to_string(), (current_time.timestamp() + JWT_EXP_SECONDS).to_string(),
); );
// Sign the claims into a new token // Sign the claims into a new token
let token = claims let token = claims
.sign_with_key(&key) .sign_with_key(&key)
.map_err(|_| RBError::JWTCreationError)?; .map_err(|_| log("Failed to sign token", RBError::JWTCreationError))?;
// Generate a random refresh token // Generate a random refresh token
let mut refresh_token = [0u8; REFRESH_TOKEN_N_BYTES]; let mut refresh_token = [0u8; REFRESH_TOKEN_N_BYTES];
thread_rng().fill(&mut refresh_token[..]); thread_rng().fill(&mut refresh_token[..]);
let refresh_expire = (current_time + chrono::Duration::seconds(REFRESH_TOKEN_EXP_SECONDS)).naive_utc();
// Store refresh token in database // Store refresh token in database
// TODO add expires_at here (it's what's causing the errors)
insert_into(refresh_tokens::refresh_tokens) insert_into(refresh_tokens::refresh_tokens)
.values(NewRefreshToken { .values(NewRefreshToken {
token: refresh_token.to_vec(), token: refresh_token.to_vec(),
user_id: user.id, user_id: user.id,
expires_at: refresh_expire
}) })
.execute(conn) .execute(conn)
.map_err(|_| RBError::JWTCreationError)?; .map_err(|_| RBError::JWTCreationError)?;
@ -94,7 +108,6 @@ pub fn hash_password(password: &str) -> crate::Result<String> {
pub fn create_admin_user(conn: &PgConnection, username: &str, password: &str) -> crate::Result<bool> { pub fn create_admin_user(conn: &PgConnection, username: &str, password: &str) -> crate::Result<bool> {
let pass_hashed = hash_password(password)?; let pass_hashed = hash_password(password)?;
println!("{}", pass_hashed);
let new_user = NewUser { let new_user = NewUser {
username: username.to_string(), username: username.to_string(),
password: pass_hashed, password: pass_hashed,
@ -103,9 +116,9 @@ pub fn create_admin_user(conn: &PgConnection, username: &str, password: &str) ->
insert_into(users::users) insert_into(users::users)
.values(&new_user) .values(&new_user)
// .on_conflict((users::username, users::password, users::admin)) .on_conflict(users::username)
// .do_update() .do_update()
// .set(&new_user) .set(&new_user)
.execute(conn).map_err(|_| RBError::AdminCreationError)?; .execute(conn).map_err(|_| RBError::AdminCreationError)?;
Ok(true) Ok(true)

View File

@ -27,4 +27,5 @@ pub struct NewUser {
pub struct NewRefreshToken { pub struct NewRefreshToken {
pub token: Vec<u8>, pub token: Vec<u8>,
pub user_id: Uuid, pub user_id: Uuid,
pub expires_at: chrono::NaiveDateTime
} }