tokens: return result as string, moved cookie handling outside

This commit is contained in:
Philippe Loctaux 2023-04-03 17:56:57 +02:00
parent 088a1f0076
commit ba9ecb9f5c
3 changed files with 54 additions and 51 deletions

View file

@ -1,9 +1,13 @@
use crate::routes::prelude::*; use crate::routes::prelude::*;
use crate::tokens::{generate_jwt, generate_refresh_token}; use crate::tokens::{generate_jwt, generate_refresh_token};
use crate::tokens::{
JWT_COOKIE_NAME, JWT_DURATION_MINUTES, REFRESH_TOKEN_COOKIE_NAME, REFRESH_TOKEN_DURATION_DAYS,
};
use apps::App; use apps::App;
use refresh_tokens::RefreshToken; use refresh_tokens::RefreshToken;
use rocket::fs::TempFile; use rocket::fs::TempFile;
use rocket::http::CookieJar; use rocket::http::{Cookie, CookieJar, SameSite};
use rocket::time::Duration;
use rocket::{get, post}; use rocket::{get, post};
use settings::Settings; use settings::Settings;
use std::net::IpAddr; use std::net::IpAddr;
@ -120,16 +124,19 @@ pub async fn settings_security_form(
RefreshToken::revoke_all(&mut transaction).await?; RefreshToken::revoke_all(&mut transaction).await?;
// Generate refresh token // Generate refresh token
generate_refresh_token( let refresh_token =
&mut transaction, generate_refresh_token(&mut transaction, ip_address, user.id(), app.id())
ip_address,
user.id(),
app.id(),
cookie_jar,
)
.await .await
.map_err(Error::internal_server_error)?; .map_err(Error::internal_server_error)?;
// Add refresh token as a cookie
let mut cookie = Cookie::new(REFRESH_TOKEN_COOKIE_NAME, refresh_token);
cookie.set_secure(true);
cookie.set_http_only(true);
cookie.set_same_site(SameSite::Strict);
cookie.set_max_age(Duration::days(REFRESH_TOKEN_DURATION_DAYS));
cookie_jar.add(cookie);
// Get base url // Get base url
let settings = Settings::get(&mut transaction).await?; let settings = Settings::get(&mut transaction).await?;
let home_page = settings let home_page = settings
@ -138,16 +145,23 @@ pub async fn settings_security_form(
.ok_or_else(|| Error::bad_request("Server url is not set"))?; .ok_or_else(|| Error::bad_request("Server url is not set"))?;
// Generate jwt // Generate jwt
generate_jwt( let jwt = generate_jwt(
&mut transaction, &mut transaction,
&private_key, &private_key,
&home_page, &home_page,
&app.id().0, &app.id().0,
&user, &user,
cookie_jar,
) )
.await .await
.map_err(Error::internal_server_error)?; .map_err(Error::internal_server_error)?;
// Add jwt as a cookie
let mut cookie = Cookie::new(JWT_COOKIE_NAME, jwt);
cookie.set_secure(true);
cookie.set_http_only(true);
cookie.set_same_site(SameSite::Strict);
cookie.set_max_age(Duration::minutes(JWT_DURATION_MINUTES));
cookie_jar.add(cookie);
} }
} }
transaction.commit().await?; transaction.commit().await?;

View file

@ -5,17 +5,15 @@ use authorization_codes::AuthorizationCode;
use jwt::database::Key; use jwt::database::Key;
use jwt::PrivateKey; use jwt::PrivateKey;
use refresh_tokens::RefreshToken; use refresh_tokens::RefreshToken;
use rocket::http::CookieJar; use rocket::get;
use rocket::{get, UriDisplayQuery};
use settings::Settings; use settings::Settings;
use std::net::IpAddr; use std::net::IpAddr;
use users::User; use users::User;
use crate::tokens::{
#[derive(Debug, FromForm, UriDisplayQuery)] JWT_COOKIE_NAME, JWT_DURATION_MINUTES, REFRESH_TOKEN_COOKIE_NAME, REFRESH_TOKEN_DURATION_DAYS,
pub struct RedirectRequest<'r> { };
pub code: &'r str, use rocket::http::{Cookie, CookieJar, SameSite};
pub state: &'r str, use rocket::time::Duration;
}
#[get("/oauth/redirect?<redirect_request..>")] #[get("/oauth/redirect?<redirect_request..>")]
pub async fn redirect_page( pub async fn redirect_page(
@ -79,16 +77,23 @@ pub async fn redirect_page(
// TODO: refactor for "code" route // TODO: refactor for "code" route
// Generate refresh token // Generate refresh token
generate_refresh_token( let refresh_token = generate_refresh_token(
&mut transaction, &mut transaction,
ip_address, ip_address,
user.id(), user.id(),
app.id(), app.id(),
cookie_jar,
) )
.await .await
.map_err(Error::internal_server_error)?; .map_err(Error::internal_server_error)?;
// Add refresh token as a cookie
let mut cookie = Cookie::new(REFRESH_TOKEN_COOKIE_NAME, refresh_token);
cookie.set_secure(true);
cookie.set_http_only(true);
cookie.set_same_site(SameSite::Strict);
cookie.set_max_age(Duration::days(REFRESH_TOKEN_DURATION_DAYS));
cookie_jar.add(cookie);
// Get latest key from database // Get latest key from database
let key = Key::get_most_recent(&mut transaction) let key = Key::get_most_recent(&mut transaction)
.await? .await?
@ -105,16 +110,23 @@ pub async fn redirect_page(
.await??; .await??;
// Generate jwt // Generate jwt
generate_jwt( let jwt = generate_jwt(
&mut transaction, &mut transaction,
&private_key, &private_key,
&home_page, &home_page,
&app.id().0, &app.id().0,
&user, &user,
cookie_jar,
) )
.await .await
.map_err(Error::internal_server_error)?; .map_err(Error::internal_server_error)?;
// Add jwt as a cookie
let mut cookie = Cookie::new(JWT_COOKIE_NAME, jwt);
cookie.set_secure(true);
cookie.set_http_only(true);
cookie.set_same_site(SameSite::Strict);
cookie.set_max_age(Duration::minutes(JWT_DURATION_MINUTES));
cookie_jar.add(cookie);
} }
transaction.commit().await?; transaction.commit().await?;

View file

@ -2,8 +2,6 @@ use hash::SecretString;
use id::{AppID, UserID}; use id::{AppID, UserID};
use jwt::{JwtClaims, PrivateKey}; use jwt::{JwtClaims, PrivateKey};
use refresh_tokens::RefreshToken; use refresh_tokens::RefreshToken;
use rocket::http::{Cookie, CookieJar, SameSite};
use rocket::time::Duration;
use rocket::tokio::task; use rocket::tokio::task;
use rocket_db_pools::sqlx::SqliteExecutor; use rocket_db_pools::sqlx::SqliteExecutor;
use std::net::IpAddr; use std::net::IpAddr;
@ -17,8 +15,7 @@ pub async fn generate_refresh_token(
ip_address: IpAddr, ip_address: IpAddr,
user_id: &UserID, user_id: &UserID,
app_id: &AppID, app_id: &AppID,
cookie_jar: &CookieJar<'_>, ) -> Result<String, String> {
) -> Result<(), String> {
// Generate refresh token // Generate refresh token
let refresh_token = task::spawn_blocking(|| SecretString::new(64)) let refresh_token = task::spawn_blocking(|| SecretString::new(64))
.await .await
@ -36,18 +33,7 @@ pub async fn generate_refresh_token(
.await .await
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
// Add refresh token as a cookie Ok(refresh_token.to_string())
let mut cookie = Cookie::new(
REFRESH_TOKEN_COOKIE_NAME,
refresh_token.as_ref().to_string(),
);
cookie.set_secure(true);
cookie.set_http_only(true);
cookie.set_same_site(SameSite::Strict);
cookie.set_max_age(Duration::days(REFRESH_TOKEN_DURATION_DAYS));
cookie_jar.add(cookie);
Ok(())
} }
pub const JWT_DURATION_MINUTES: i64 = 15; pub const JWT_DURATION_MINUTES: i64 = 15;
@ -59,8 +45,7 @@ pub async fn generate_jwt(
issuer: &str, issuer: &str,
audience: &str, audience: &str,
user: &User, user: &User,
cookie_jar: &CookieJar<'_>, ) -> Result<String, String> {
) -> Result<(), String> {
// TODO: get user roles // TODO: get user roles
let roles = vec![]; let roles = vec![];
@ -69,13 +54,5 @@ pub async fn generate_jwt(
.sign_serialize(private_key, JWT_DURATION_MINUTES) .sign_serialize(private_key, JWT_DURATION_MINUTES)
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
// Add jwt as a cookie Ok(jwt)
let mut cookie = Cookie::new(JWT_COOKIE_NAME, jwt);
cookie.set_secure(true);
cookie.set_http_only(true);
cookie.set_same_site(SameSite::Strict);
cookie.set_max_age(Duration::minutes(JWT_DURATION_MINUTES));
cookie_jar.add(cookie);
Ok(())
} }