Skip to content

Commit

Permalink
make bearer tokens great again (#33)
Browse files Browse the repository at this point in the history
* proper bearer token

* fix: formatting

---------

Co-authored-by: Tobias Oettl <[email protected]>
  • Loading branch information
CodeF0x and Tobias Oettl authored Oct 9, 2024
1 parent 8707461 commit 336e3a4
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 12 deletions.
81 changes: 75 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use hmac::Hmac;
use jwt::SignWithKey;
use sha2::Sha256;
use std::io::Result;
use std::time::{SystemTime, UNIX_EPOCH};

#[actix_web::main]
async fn main() -> Result<()> {
Expand Down Expand Up @@ -222,8 +223,14 @@ async fn login(payload: Json<LoginPayload>) -> impl Responder {
.unwrap();

if is_valid {
let expiry_date = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis()
+ 24 * 60 * 60 * 1000;
let claims = TokenClaims {
id: database_user.id,
expiry_date,
};
let token_str = claims.sign_with_key(&jwt_secret).unwrap();

Expand Down Expand Up @@ -816,27 +823,89 @@ mod tests {
use crate::database::DataBase;
use crate::get_tickets;
use crate::middleware::validator;
use crate::models::NewSession;
use crate::models::{NewSession, TokenClaims};
use crate::schema::sessions::dsl::sessions;
use actix_web::http::StatusCode;
use actix_web::{test, web};
use actix_web_httpauth::middleware::HttpAuthentication;
use diesel::RunQueryDsl;
use hmac::{Hmac, Mac};
use jwt::SignWithKey;
use serial_test::serial;
use sha2::Sha256;
use std::time::{SystemTime, UNIX_EPOCH};

#[actix_web::test]
#[serial]
async fn test_expiry_date() {
setup_database();

let jwt_secret: Hmac<Sha256> = Hmac::new_from_slice(
std::env::var("JWT_SECRET")
.expect("JWT_SECRET must be set!")
.as_bytes(),
)
.unwrap();

let expiry_date = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis()
// 24 hours in present
- 24 * 60 * 60 * 1000;
let claims = TokenClaims { id: 1, expiry_date };
let token_str = claims.sign_with_key(&jwt_secret).unwrap();

let mut db = DataBase::new();
diesel::insert_into(sessions)
.values(NewSession {
token: token_str.clone(),
})
.execute(&mut db.connection)
.unwrap();

let app = test::init_service(
App::new().service(
web::scope("")
.wrap(HttpAuthentication::bearer(validator))
.service(get_tickets),
),
)
.await;
let req = TestRequest::get()
.uri("/tickets")
.insert_header(("Authorization", format!("Bearer {token_str}")))
.to_request();

let response = test::call_service(&app, req).await;

assert_eq!(response.status().as_u16(), StatusCode::UNAUTHORIZED);
}

#[actix_web::test]
#[serial]
async fn test_middleware() {
setup_database();

// bearer for "123"
let bearer_token =
"eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MX0.oi92tHHWj5HdQO8Hd9vIYD6suTWosoiBnpdRBIcNGpM";
let jwt_secret: Hmac<Sha256> = Hmac::new_from_slice(
std::env::var("JWT_SECRET")
.expect("JWT_SECRET must be set!")
.as_bytes(),
)
.unwrap();

let expiry_date = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis()
+ 24 * 60 * 60 * 60 * 1000;
let claims = TokenClaims { id: 1, expiry_date };
let token_str = claims.sign_with_key(&jwt_secret).unwrap();

let mut db = DataBase::new();
diesel::insert_into(sessions)
.values(NewSession {
token: bearer_token.to_string(),
token: token_str.clone(),
})
.execute(&mut db.connection)
.unwrap();
Expand All @@ -851,7 +920,7 @@ mod tests {
.await;
let req = TestRequest::get()
.uri("/tickets")
.insert_header(("Authorization", format!("Bearer {bearer_token}")))
.insert_header(("Authorization", format!("Bearer {token_str}")))
.to_request();

let response = test::call_service(&app, req).await;
Expand Down
20 changes: 14 additions & 6 deletions src/middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ use crate::database::{session_in_db, DataBase};
use crate::models::TokenClaims;
use actix_web::dev::ServiceRequest;
use actix_web::{Error, HttpMessage};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use actix_web_httpauth::extractors::bearer::{BearerAuth, Config};
use actix_web_httpauth::extractors::{bearer, AuthenticationError};
use dotenvy::dotenv;
use hmac::digest::KeyInit;
use hmac::Hmac;
use jwt::VerifyWithKey;
use sha2::Sha256;
use std::time::{SystemTime, UNIX_EPOCH};

pub async fn validator(
req: ServiceRequest,
Expand Down Expand Up @@ -38,15 +39,22 @@ pub async fn validator(

match claims {
Ok(value) => {
if value.expiry_date
< SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis()
{
let config = Config::default().scope("");

return Err((AuthenticationError::from(config).into(), req));
}

req.extensions_mut().insert(value);
Ok(req)
}
Err(_) => {
let config = req
.app_data::<bearer::Config>()
.cloned()
.unwrap_or_default()
.scope("");
let config = Config::default().scope("");

Err((AuthenticationError::from(config).into(), req))
}
Expand Down
1 change: 1 addition & 0 deletions src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ pub struct NewUser {
#[derive(Serialize, Deserialize)]
pub struct TokenClaims {
pub id: i32,
pub expiry_date: u128,
}

#[derive(Serialize, Deserialize, Queryable, Debug)]
Expand Down

0 comments on commit 336e3a4

Please sign in to comment.