allow auth token in cookie
This commit is contained in:
parent
a83a099f34
commit
3edf10edd9
5 changed files with 48 additions and 33 deletions
22
Cargo.lock
generated
22
Cargo.lock
generated
|
@ -587,25 +587,6 @@ version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "h2"
|
|
||||||
version = "0.3.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"fnv",
|
|
||||||
"futures-core",
|
|
||||||
"futures-sink",
|
|
||||||
"futures-util",
|
|
||||||
"http",
|
|
||||||
"indexmap",
|
|
||||||
"slab",
|
|
||||||
"tokio",
|
|
||||||
"tokio-util 0.7.1",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
|
@ -695,7 +676,6 @@ dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2",
|
|
||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"httparse",
|
"httparse",
|
||||||
|
@ -933,6 +913,7 @@ dependencies = [
|
||||||
"rocket_sync_db_pools",
|
"rocket_sync_db_pools",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"time 0.3.9",
|
||||||
"tokio",
|
"tokio",
|
||||||
"trust-dns-client",
|
"trust-dns-client",
|
||||||
"trust-dns-proto",
|
"trust-dns-proto",
|
||||||
|
@ -1752,7 +1733,6 @@ dependencies = [
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -11,7 +11,7 @@ trust-dns-client = { version = "0.21", features = ["dnssec-openssl"] }
|
||||||
trust-dns-proto = "0.21"
|
trust-dns-proto = "0.21"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
rocket = { git = "https://github.com/SergioBenitez/Rocket", rev = "6bdd2f8", version = "0.5.0-rc.1", features = ["json"] }
|
rocket = { git = "https://github.com/SergioBenitez/Rocket", rev = "6bdd2f8", version = "0.5.0-rc.1", features = ["json"], default-features = false }
|
||||||
rocket_sync_db_pools = { git = "https://github.com/SergioBenitez/Rocket", rev = "6bdd2f8", default-features = false, features = ["diesel_sqlite_pool"], version = "0.1.0-rc.1"}
|
rocket_sync_db_pools = { git = "https://github.com/SergioBenitez/Rocket", rev = "6bdd2f8", default-features = false, features = ["diesel_sqlite_pool"], version = "0.1.0-rc.1"}
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
uuid = { version = "0.8.2", features = ["v4", "serde"] }
|
uuid = { version = "0.8.2", features = ["v4", "serde"] }
|
||||||
|
@ -27,3 +27,5 @@ argon2 = {version = "0.4", default-features = false, features = ["alloc", "passw
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
# From trust-dns-client
|
# From trust-dns-client
|
||||||
futures-util = { version = "0.3.5", default-features = false, features = ["std"] }
|
futures-util = { version = "0.3.5", default-features = false, features = ["std"] }
|
||||||
|
# From rocket / cookie-rs
|
||||||
|
time = "0.3"
|
||||||
|
|
|
@ -23,6 +23,7 @@ use rocket::outcome::try_outcome;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
|
||||||
|
|
||||||
#[rocket::async_trait]
|
#[rocket::async_trait]
|
||||||
impl<'r> FromRequest<'r> for Box<dyn RecordConnector> {
|
impl<'r> FromRequest<'r> for Box<dyn RecordConnector> {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
|
@ -21,6 +21,7 @@ use crate::models::auth::Session;
|
||||||
|
|
||||||
const BEARER: &str = "Bearer ";
|
const BEARER: &str = "Bearer ";
|
||||||
const AUTH_HEADER: &str = "Authorization";
|
const AUTH_HEADER: &str = "Authorization";
|
||||||
|
pub const COOKIE_NAME: &str = "session_id";
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, DbEnum, Deserialize, Clone)]
|
#[derive(Debug, DbEnum, Deserialize, Clone)]
|
||||||
|
@ -114,21 +115,37 @@ impl UserInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_token_from_header<'r>(request: &'r Request<'_>) -> Outcome<String, ErrorResponse> {
|
||||||
|
let auth_header = match request.headers().get_one(AUTH_HEADER) {
|
||||||
|
None => return Outcome::Forward(()),
|
||||||
|
Some(auth_header) => auth_header,
|
||||||
|
};
|
||||||
|
|
||||||
|
let token = if auth_header.starts_with(BEARER) {
|
||||||
|
auth_header.trim_start_matches(BEARER).to_string()
|
||||||
|
} else {
|
||||||
|
return ErrorResponse::from(UserError::MalformedHeader).into();
|
||||||
|
};
|
||||||
|
|
||||||
|
Outcome::Success(token)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_token_from_cookie<'r>(request: &'r Request<'_>) -> Outcome<String, ErrorResponse> {
|
||||||
|
match request.cookies().get(COOKIE_NAME) {
|
||||||
|
None => Outcome::Forward(()),
|
||||||
|
Some(session_cookie) => Outcome::Success(session_cookie.value().to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[rocket::async_trait]
|
#[rocket::async_trait]
|
||||||
impl<'r> FromRequest<'r> for UserInfo {
|
impl<'r> FromRequest<'r> for UserInfo {
|
||||||
type Error = ErrorResponse;
|
type Error = ErrorResponse;
|
||||||
|
|
||||||
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||||
let auth_header = match request.headers().get_one(AUTH_HEADER) {
|
let token = try_outcome!(
|
||||||
None => return Outcome::Forward(()),
|
get_token_from_header(request)
|
||||||
Some(auth_header) => auth_header,
|
.forward_then(|_| get_token_from_cookie(request))
|
||||||
};
|
);
|
||||||
|
|
||||||
let token = if auth_header.starts_with(BEARER) {
|
|
||||||
auth_header.trim_start_matches(BEARER).to_string()
|
|
||||||
} else {
|
|
||||||
return ErrorResponse::from(UserError::MalformedHeader).into()
|
|
||||||
};
|
|
||||||
|
|
||||||
let conn = try_outcome!(request.guard::<DbConn>().await.map_failure(make_500));
|
let conn = try_outcome!(request.guard::<DbConn>().await.map_failure(make_500));
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use rocket::http::{Cookie, SameSite, CookieJar};
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
use rocket::State;
|
use rocket::State;
|
||||||
use rocket::http::Status;
|
use rocket::http::Status;
|
||||||
|
@ -5,13 +6,15 @@ use rocket::http::Status;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::DbConn;
|
use crate::DbConn;
|
||||||
use crate::models;
|
use crate::models;
|
||||||
|
use time;
|
||||||
|
|
||||||
|
|
||||||
#[post("/users/me/token", data = "<auth_request>")]
|
#[post("/users/me/token", data = "<auth_request>")]
|
||||||
pub async fn create_auth_token(
|
pub async fn create_auth_token(
|
||||||
conn: DbConn,
|
conn: DbConn,
|
||||||
config: &State<Config>,
|
config: &State<Config>,
|
||||||
auth_request: Json<models::AuthTokenRequest>
|
auth_request: Json<models::AuthTokenRequest>,
|
||||||
|
cookies: &CookieJar<'_>
|
||||||
) -> Result<Json<models::Session>, models::ErrorResponse> {
|
) -> Result<Json<models::Session>, models::ErrorResponse> {
|
||||||
|
|
||||||
let session_duration = config.web_app.token_duration;
|
let session_duration = config.web_app.token_duration;
|
||||||
|
@ -26,6 +29,18 @@ pub async fn create_auth_token(
|
||||||
models::Session::new(c, &user_info, session_duration)
|
models::Session::new(c, &user_info, session_duration)
|
||||||
}).await?;
|
}).await?;
|
||||||
|
|
||||||
|
// Conversion between different date / time libraries, very cursed, I don't like that
|
||||||
|
// About unwrap: I guess too bad if session time is over year 9999 (current max time if time-rs)
|
||||||
|
let expires = time::OffsetDateTime::from_unix_timestamp(session.expires_at.timestamp()).unwrap();
|
||||||
|
|
||||||
|
let session_cookie = Cookie::build(models::user::COOKIE_NAME, session.session_id.clone())
|
||||||
|
.same_site(SameSite::Strict)
|
||||||
|
.secure(true)
|
||||||
|
.http_only(true)
|
||||||
|
.expires(expires)
|
||||||
|
.finish();
|
||||||
|
|
||||||
|
cookies.add(session_cookie);
|
||||||
|
|
||||||
Ok(Json(session))
|
Ok(Json(session))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue