mirror of
https://github.com/kanidm/kanidm.git
synced 2025-05-05 16:45:04 +02:00
* make everything cookie consistent * Stricter on expiry * Relearn a painful lesson about needing domains in removal cookies * fix: DRY cookie creation code and reduce the sins
84 lines
2.4 KiB
Rust
84 lines
2.4 KiB
Rust
//! Support Utilities for interacting with cookies.
|
|
|
|
use crate::https::ServerState;
|
|
use axum_extra::extract::cookie::{Cookie, CookieJar, SameSite};
|
|
use compact_jwt::{Jws, JwsSigner};
|
|
use serde::de::DeserializeOwned;
|
|
use serde::Serialize;
|
|
|
|
fn new_cookie<'a>(state: &'_ ServerState, ck_id: &'a str, value: String) -> Cookie<'a> {
|
|
let mut token_cookie = Cookie::new(ck_id, value);
|
|
token_cookie.set_secure(state.secure_cookies);
|
|
token_cookie.set_same_site(SameSite::Lax);
|
|
// Prevent Document.cookie accessing this. Still works with fetch.
|
|
token_cookie.set_http_only(true);
|
|
// We set a domain here because it allows subdomains
|
|
// of the idm to share the cookie. If domain was incorrect
|
|
// then webauthn won't work anyway!
|
|
token_cookie.set_domain(state.domain.clone());
|
|
token_cookie.set_path("/");
|
|
token_cookie
|
|
}
|
|
|
|
#[instrument(name = "views::cookies::destroy", level = "debug", skip(jar, state))]
|
|
pub fn destroy(jar: CookieJar, ck_id: &str, state: &ServerState) -> CookieJar {
|
|
if let Some(ck) = jar.get(ck_id) {
|
|
let mut removal_cookie = ck.clone();
|
|
removal_cookie.make_removal();
|
|
|
|
// Need to be set to domain else the cookie isn't removed!
|
|
removal_cookie.set_domain(state.domain.clone());
|
|
|
|
// Need to be set to / to remove on all parent paths.
|
|
// If you don't set a path, NOTHING IS REMOVED!!!
|
|
removal_cookie.set_path("/");
|
|
|
|
jar.add(removal_cookie)
|
|
} else {
|
|
jar
|
|
}
|
|
}
|
|
|
|
pub fn make_unsigned<'a>(state: &'_ ServerState, ck_id: &'a str, value: String) -> Cookie<'a> {
|
|
new_cookie(state, ck_id, value)
|
|
}
|
|
|
|
pub fn make_signed<'a, T: Serialize>(
|
|
state: &'_ ServerState,
|
|
ck_id: &'a str,
|
|
value: &'_ T,
|
|
) -> Option<Cookie<'a>> {
|
|
let kref = &state.jws_signer;
|
|
|
|
let jws = Jws::into_json(value)
|
|
.map_err(|e| {
|
|
error!(?e);
|
|
})
|
|
.ok()?;
|
|
|
|
// Get the header token ready.
|
|
let token = kref
|
|
.sign(&jws)
|
|
.map(|jwss| jwss.to_string())
|
|
.map_err(|e| {
|
|
error!(?e);
|
|
})
|
|
.ok()?;
|
|
|
|
Some(new_cookie(state, ck_id, token))
|
|
}
|
|
|
|
pub fn get_signed<T: DeserializeOwned>(
|
|
state: &ServerState,
|
|
jar: &CookieJar,
|
|
ck_id: &str,
|
|
) -> Option<T> {
|
|
jar.get(ck_id)
|
|
.map(|c| c.value())
|
|
.and_then(|s| state.deserialise_from_str::<T>(s))
|
|
}
|
|
|
|
pub fn get_unsigned<'a>(jar: &'a CookieJar, ck_id: &'_ str) -> Option<&'a str> {
|
|
jar.get(ck_id).map(|c| c.value())
|
|
}
|