mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
Add version header and warnings (#1175)
This commit is contained in:
parent
719de54342
commit
92d79489fc
|
@ -30,7 +30,7 @@ pub use reqwest::StatusCode;
|
|||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::error::Error as SerdeJsonError;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
use webauthn_rs_proto::{
|
||||
|
@ -46,6 +46,9 @@ pub const APPLICATION_JSON: &str = "application/json";
|
|||
pub const KOPID: &str = "X-KANIDM-OPID";
|
||||
pub const KSESSIONID: &str = "X-KANIDM-AUTH-SESSION-ID";
|
||||
|
||||
const KVERSION: &str = "X-KANIDM-VERSION";
|
||||
const EXPECT_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ClientError {
|
||||
Unauthorized,
|
||||
|
@ -106,6 +109,7 @@ pub struct KanidmClient {
|
|||
pub(crate) builder: KanidmClientBuilder,
|
||||
pub(crate) bearer_token: RwLock<Option<String>>,
|
||||
pub(crate) auth_session_id: RwLock<Option<String>>,
|
||||
pub(crate) check_version: Mutex<bool>,
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
|
@ -404,6 +408,7 @@ impl KanidmClientBuilder {
|
|||
bearer_token: RwLock::new(None),
|
||||
origin,
|
||||
auth_session_id: RwLock::new(None),
|
||||
check_version: Mutex::new(true),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -440,6 +445,31 @@ impl KanidmClient {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn expect_version(&self, response: &reqwest::Response) {
|
||||
let mut guard = self.check_version.lock().await;
|
||||
|
||||
if !*guard {
|
||||
return;
|
||||
}
|
||||
|
||||
let ver = response
|
||||
.headers()
|
||||
.get(KVERSION)
|
||||
.and_then(|hv| hv.to_str().ok())
|
||||
.unwrap_or("");
|
||||
|
||||
let matching = ver == EXPECT_VERSION;
|
||||
|
||||
if !matching {
|
||||
warn!(server_version = ?ver, client_version = ?EXPECT_VERSION, "Mismatched client and server version - features may not work, or other unforseen errors may occur.")
|
||||
}
|
||||
|
||||
debug_assert!(matching);
|
||||
|
||||
// Check is done once, mark as no longer needing to occur
|
||||
*guard = false;
|
||||
}
|
||||
|
||||
async fn perform_simple_post_request<R: Serialize, T: DeserializeOwned>(
|
||||
&self,
|
||||
dest: &str,
|
||||
|
@ -457,6 +487,8 @@ impl KanidmClient {
|
|||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
let opid = response
|
||||
.headers()
|
||||
.get(KOPID)
|
||||
|
@ -517,6 +549,8 @@ impl KanidmClient {
|
|||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
// If we have a sessionid header in the response, get it now.
|
||||
|
||||
let headers = response.headers();
|
||||
|
@ -577,6 +611,8 @@ impl KanidmClient {
|
|||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
let opid = response
|
||||
.headers()
|
||||
.get(KOPID)
|
||||
|
@ -630,6 +666,8 @@ impl KanidmClient {
|
|||
.await
|
||||
.map_err(ClientError::Transport)?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
let opid = response
|
||||
.headers()
|
||||
.get(KOPID)
|
||||
|
@ -681,6 +719,8 @@ impl KanidmClient {
|
|||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
let opid = response
|
||||
.headers()
|
||||
.get(KOPID)
|
||||
|
@ -721,6 +761,8 @@ impl KanidmClient {
|
|||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
let opid = response
|
||||
.headers()
|
||||
.get(KOPID)
|
||||
|
@ -766,6 +808,8 @@ impl KanidmClient {
|
|||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
let opid = response
|
||||
.headers()
|
||||
.get(KOPID)
|
||||
|
@ -816,6 +860,8 @@ impl KanidmClient {
|
|||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
let opid = response
|
||||
.headers()
|
||||
.get(KOPID)
|
||||
|
@ -1183,6 +1229,8 @@ impl KanidmClient {
|
|||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
let opid = response
|
||||
.headers()
|
||||
.get(KOPID)
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
#![deny(clippy::trivially_copy_pass_by_ref)]
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::os::unix::fs::symlink;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::os::unix::fs::symlink;
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
use std::{fs, io};
|
||||
|
@ -81,7 +81,11 @@ fn chown(path: &Path, gid: u32) -> Result<(), String> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn create_home_directory(info: &HomeDirectoryInfo, home_prefix: &str, use_etc_skel: bool) -> Result<(), String> {
|
||||
fn create_home_directory(
|
||||
info: &HomeDirectoryInfo,
|
||||
home_prefix: &str,
|
||||
use_etc_skel: bool,
|
||||
) -> Result<(), String> {
|
||||
// Final sanity check to prevent certain classes of attacks.
|
||||
let name = info
|
||||
.name
|
||||
|
|
|
@ -211,3 +211,21 @@ impl<State: Clone + Send + Sync + 'static> tide::Middleware<State>
|
|||
Ok(response)
|
||||
}
|
||||
}
|
||||
|
||||
const KANIDM_VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct VersionHeaderMiddleware;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<State: Clone + Send + Sync + 'static> tide::Middleware<State> for VersionHeaderMiddleware {
|
||||
async fn handle(
|
||||
&self,
|
||||
request: tide::Request<State>,
|
||||
next: tide::Next<'_, State>,
|
||||
) -> tide::Result {
|
||||
let mut response = next.run(request).await;
|
||||
response.insert_header("X-KANIDM-VERSION", KANIDM_VERSION);
|
||||
Ok(response)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -374,18 +374,20 @@ pub fn create_https_server(
|
|||
js_files: js_files.to_owned(),
|
||||
});
|
||||
|
||||
// Add middleware?
|
||||
// Add the logging subsystem.
|
||||
tserver.with(sketching::middleware::TreeMiddleware::new(
|
||||
trust_x_forward_for,
|
||||
));
|
||||
|
||||
// We do not force a session ttl, because we validate this elsewhere in usage.
|
||||
// Add cookie handling.
|
||||
tserver.with(
|
||||
// We do not force a session ttl, because we validate this elsewhere in usage.
|
||||
tide::sessions::SessionMiddleware::new(tide::sessions::CookieStore::new(), cookie_key)
|
||||
.with_cookie_name("kanidm-session")
|
||||
.with_same_site_policy(tide::http::cookies::SameSite::Strict),
|
||||
);
|
||||
|
||||
// Strict responses.
|
||||
tserver.with(StrictResponseMiddleware::default());
|
||||
|
||||
// Add routes
|
||||
|
@ -467,6 +469,8 @@ pub fn create_https_server(
|
|||
|
||||
// ==== Some routes can be cached - these are here:
|
||||
let mut tserver_cacheable = tserver.at("");
|
||||
// Add our version injector, we only add this to apis.
|
||||
tserver_cacheable.with(VersionHeaderMiddleware::default());
|
||||
tserver_cacheable.with(CacheableMiddleware::default());
|
||||
|
||||
// We allow clients to cache the unix token for accounts and groups.
|
||||
|
@ -486,6 +490,8 @@ pub fn create_https_server(
|
|||
|
||||
// ==== These routes can not be cached
|
||||
let mut appserver = tserver.at("");
|
||||
// Add our version injector, we only add this to apis.
|
||||
appserver.with(VersionHeaderMiddleware::default());
|
||||
appserver.with(NoCacheMiddleware::default());
|
||||
|
||||
// let mut well_known = appserver.at("/.well-known");
|
||||
|
|
Loading…
Reference in a new issue