mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 12:37:00 +01:00
Regrets Dot Pee Enn Gee (#2804)
Upgrade Axum Co-authored-by: James Hodgkinson <james@terminaloutcomes.com>
This commit is contained in:
parent
f669f5a0e8
commit
1e7b94b7cf
638
Cargo.lock
generated
638
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
17
Cargo.toml
17
Cargo.toml
|
@ -89,18 +89,16 @@ serde_with = "3.7.0"
|
||||||
argon2 = { version = "0.5.3", features = ["alloc"] }
|
argon2 = { version = "0.5.3", features = ["alloc"] }
|
||||||
async-recursion = "1.1.0"
|
async-recursion = "1.1.0"
|
||||||
async-trait = "^0.1.78"
|
async-trait = "^0.1.78"
|
||||||
axum = { version = "0.6.20", features = [
|
axum = { version = "0.7.5", features = [
|
||||||
"form",
|
"form",
|
||||||
"headers",
|
|
||||||
"http2",
|
|
||||||
"json",
|
"json",
|
||||||
"macros",
|
"macros",
|
||||||
"multipart",
|
"multipart",
|
||||||
"original-uri",
|
"original-uri",
|
||||||
"query",
|
"query",
|
||||||
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
] }
|
] }
|
||||||
axum-csp = { version = "0.0.5" }
|
|
||||||
base32 = "^0.4.0"
|
base32 = "^0.4.0"
|
||||||
base64 = "^0.21.7"
|
base64 = "^0.21.7"
|
||||||
base64urlsafedata = "0.5.0"
|
base64urlsafedata = "0.5.0"
|
||||||
|
@ -129,9 +127,10 @@ gloo = "^0.8.1"
|
||||||
gloo-utils = "0.2.0"
|
gloo-utils = "0.2.0"
|
||||||
hashbrown = { version = "0.14.3", features = ["serde", "inline-more", "ahash"] }
|
hashbrown = { version = "0.14.3", features = ["serde", "inline-more", "ahash"] }
|
||||||
hex = "^0.4.3"
|
hex = "^0.4.3"
|
||||||
http = "0.2.12"
|
http = "1.1.0"
|
||||||
hyper = { version = "0.14.28", features = ["full"] }
|
hyper = { version = "1.3.1", features = ["server", "client"] }
|
||||||
hyper-tls = "0.5.0"
|
hyper-util = { version = "0.1.5", features = ["server", "tokio"] }
|
||||||
|
hyper-tls = "0.6.0"
|
||||||
idlset = "^0.2.4"
|
idlset = "^0.2.4"
|
||||||
image = { version = "0.24.9", default-features = false, features = [
|
image = { version = "0.24.9", default-features = false, features = [
|
||||||
"gif",
|
"gif",
|
||||||
|
@ -181,7 +180,7 @@ quote = "1"
|
||||||
rand = "^0.8.5"
|
rand = "^0.8.5"
|
||||||
rand_chacha = "0.3.1"
|
rand_chacha = "0.3.1"
|
||||||
regex = "1.10.3"
|
regex = "1.10.3"
|
||||||
reqwest = { version = "0.11.26", default-features = false, features = [
|
reqwest = { version = "0.12.4", default-features = false, features = [
|
||||||
"cookies",
|
"cookies",
|
||||||
"json",
|
"json",
|
||||||
"gzip",
|
"gzip",
|
||||||
|
@ -224,7 +223,7 @@ tracing-forest = "^0.1.6"
|
||||||
url = "^2.5.0"
|
url = "^2.5.0"
|
||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
utoipa = "4.2.0"
|
utoipa = "4.2.0"
|
||||||
utoipa-swagger-ui = "4.0.0"
|
utoipa-swagger-ui = "6.0.0"
|
||||||
uuid = "^1.8.0"
|
uuid = "^1.8.0"
|
||||||
|
|
||||||
wasm-bindgen = "^0.2.92"
|
wasm-bindgen = "^0.2.92"
|
||||||
|
|
|
@ -24,6 +24,8 @@ reqwest = { workspace = true, default-features = false, features = [
|
||||||
] }
|
] }
|
||||||
kanidm_proto = { workspace = true }
|
kanidm_proto = { workspace = true }
|
||||||
kanidm_lib_file_permissions = { workspace = true }
|
kanidm_lib_file_permissions = { workspace = true }
|
||||||
|
http = { workspace = true }
|
||||||
|
hyper = { workspace = true }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
time = { workspace = true, features = ["serde", "std"] }
|
time = { workspace = true, features = ["serde", "std"] }
|
||||||
|
@ -39,4 +41,4 @@ toml = { workspace = true }
|
||||||
uuid = { workspace = true, features = ["serde", "v4"] }
|
uuid = { workspace = true, features = ["serde", "v4"] }
|
||||||
url = { workspace = true, features = ["serde"] }
|
url = { workspace = true, features = ["serde"] }
|
||||||
webauthn-rs-proto = { workspace = true, features = ["wasm"] }
|
webauthn-rs-proto = { workspace = true, features = ["wasm"] }
|
||||||
hyper = { workspace = true }
|
# hyper = { workspace = true }
|
||||||
|
|
|
@ -2032,9 +2032,9 @@ impl KanidmClient {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_no_client_version_check_on_502() {
|
async fn test_no_client_version_check_on_502() {
|
||||||
let res = reqwest::Response::from(
|
let res = reqwest::Response::from(
|
||||||
hyper::Response::builder()
|
http::Response::builder()
|
||||||
.status(StatusCode::GATEWAY_TIMEOUT)
|
.status(StatusCode::GATEWAY_TIMEOUT)
|
||||||
.body(hyper::Body::empty())
|
.body("")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
let client = KanidmClientBuilder::new()
|
let client = KanidmClientBuilder::new()
|
||||||
|
@ -2045,9 +2045,9 @@ async fn test_no_client_version_check_on_502() {
|
||||||
client.expect_version(&res).await;
|
client.expect_version(&res).await;
|
||||||
|
|
||||||
let res = reqwest::Response::from(
|
let res = reqwest::Response::from(
|
||||||
hyper::Response::builder()
|
http::Response::builder()
|
||||||
.status(StatusCode::BAD_GATEWAY)
|
.status(StatusCode::BAD_GATEWAY)
|
||||||
.body(hyper::Body::empty())
|
.body("")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
let client = KanidmClientBuilder::new()
|
let client = KanidmClientBuilder::new()
|
||||||
|
|
|
@ -19,10 +19,9 @@ doctest = false
|
||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
axum = { workspace = true }
|
axum = { workspace = true }
|
||||||
axum-auth = "0.4.1"
|
axum-auth = "0.4.1"
|
||||||
axum-csp = { workspace = true }
|
axum-extra = { version = "0.9.3", features = ["cookie"] }
|
||||||
axum-extra = { version = "0.7.7", features = ["cookie"] }
|
axum-macros = "0.4.1"
|
||||||
axum-macros = "0.3.8"
|
axum-server = { version = "0.6.0", features = ["tls-openssl"] }
|
||||||
axum-server = { version = "0.5.1", features = ["tls-openssl"] }
|
|
||||||
bytes = { workspace = true }
|
bytes = { workspace = true }
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
compact_jwt = { workspace = true }
|
compact_jwt = { workspace = true }
|
||||||
|
@ -33,6 +32,7 @@ futures-util = { workspace = true }
|
||||||
hashbrown = { workspace = true }
|
hashbrown = { workspace = true }
|
||||||
http = { workspace = true }
|
http = { workspace = true }
|
||||||
hyper = { workspace = true }
|
hyper = { workspace = true }
|
||||||
|
hyper-util = { workspace = true }
|
||||||
kanidm_proto = { workspace = true }
|
kanidm_proto = { workspace = true }
|
||||||
kanidm_utils_users = { workspace = true }
|
kanidm_utils_users = { workspace = true }
|
||||||
kanidmd_lib = { workspace = true }
|
kanidmd_lib = { workspace = true }
|
||||||
|
@ -53,7 +53,7 @@ tokio-openssl = { workspace = true }
|
||||||
tokio-util = { workspace = true, features = ["codec"] }
|
tokio-util = { workspace = true, features = ["codec"] }
|
||||||
toml = { workspace = true }
|
toml = { workspace = true }
|
||||||
tower = { version = "0.4.13", features = ["tokio-stream", "tracing"] }
|
tower = { version = "0.4.13", features = ["tokio-stream", "tracing"] }
|
||||||
tower-http = { version = "0.4.4", features = [
|
tower-http = { version = "0.5.2", features = [
|
||||||
"compression-gzip",
|
"compression-gzip",
|
||||||
"fs",
|
"fs",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
|
@ -5,12 +5,12 @@ use axum::{
|
||||||
http::{
|
http::{
|
||||||
header::HeaderName, header::AUTHORIZATION as AUTHORISATION, request::Parts, StatusCode,
|
header::HeaderName, header::AUTHORIZATION as AUTHORISATION, request::Parts, StatusCode,
|
||||||
},
|
},
|
||||||
|
serve::IncomingStream,
|
||||||
RequestPartsExt,
|
RequestPartsExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
use axum_extra::extract::cookie::CookieJar;
|
use axum_extra::extract::cookie::CookieJar;
|
||||||
|
|
||||||
use hyper::server::conn::AddrStream;
|
|
||||||
use kanidm_proto::constants::X_FORWARDED_FOR;
|
use kanidm_proto::constants::X_FORWARDED_FOR;
|
||||||
use kanidm_proto::internal::COOKIE_BEARER_TOKEN;
|
use kanidm_proto::internal::COOKIE_BEARER_TOKEN;
|
||||||
use kanidmd_lib::prelude::{ClientAuthInfo, ClientCertInfo, Source};
|
use kanidmd_lib::prelude::{ClientAuthInfo, ClientCertInfo, Source};
|
||||||
|
@ -192,8 +192,17 @@ impl Connected<ClientConnInfo> for ClientConnInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Connected<&'a AddrStream> for ClientConnInfo {
|
impl Connected<SocketAddr> for ClientConnInfo {
|
||||||
fn connect_info(target: &'a AddrStream) -> Self {
|
fn connect_info(addr: SocketAddr) -> Self {
|
||||||
|
ClientConnInfo {
|
||||||
|
addr,
|
||||||
|
client_cert: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Connected<IncomingStream<'_>> for ClientConnInfo {
|
||||||
|
fn connect_info(target: IncomingStream<'_>) -> Self {
|
||||||
ClientConnInfo {
|
ClientConnInfo {
|
||||||
addr: target.remote_addr(),
|
addr: target.remote_addr(),
|
||||||
client_cert: None,
|
client_cert: None,
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
headers::{CacheControl, HeaderMapExt},
|
body::Body,
|
||||||
http::{header, HeaderValue, Request},
|
http::{header, HeaderValue, Request},
|
||||||
middleware::Next,
|
middleware::Next,
|
||||||
response::Response,
|
response::Response,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Adds `no-cache max-age=0` to the response headers.
|
/// Adds `no-cache max-age=0` to the response headers.
|
||||||
pub async fn dont_cache_me<B>(request: Request<B>, next: Next<B>) -> Response {
|
pub async fn dont_cache_me(request: Request<Body>, next: Next) -> Response {
|
||||||
let mut response = next.run(request).await;
|
let mut response = next.run(request).await;
|
||||||
response.headers_mut().insert(
|
response.headers_mut().insert(
|
||||||
header::CACHE_CONTROL,
|
header::CACHE_CONTROL,
|
||||||
HeaderValue::from_static("no-store no-cache max-age=0"),
|
HeaderValue::from_static("no-store, no-cache, max-age=0"),
|
||||||
);
|
);
|
||||||
response
|
response
|
||||||
.headers_mut()
|
.headers_mut()
|
||||||
|
@ -20,13 +20,12 @@ pub async fn dont_cache_me<B>(request: Request<B>, next: Next<B>) -> Response {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a cache control header of 300 seconds to the response headers.
|
/// Adds a cache control header of 300 seconds to the response headers.
|
||||||
pub async fn cache_me<B>(request: Request<B>, next: Next<B>) -> Response {
|
pub async fn cache_me(request: Request<Body>, next: Next) -> Response {
|
||||||
let mut response = next.run(request).await;
|
let mut response = next.run(request).await;
|
||||||
let cache_header = CacheControl::new()
|
response.headers_mut().insert(
|
||||||
.with_max_age(std::time::Duration::from_secs(300))
|
header::CACHE_CONTROL,
|
||||||
.with_private();
|
HeaderValue::from_static("private, max-age=300"),
|
||||||
|
);
|
||||||
response.headers_mut().typed_insert(cache_header);
|
|
||||||
response
|
response
|
||||||
.headers_mut()
|
.headers_mut()
|
||||||
.insert(header::PRAGMA, HeaderValue::from_static("no-cache"));
|
.insert(header::PRAGMA, HeaderValue::from_static("no-cache"));
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use tower_http::compression::CompressionLayer;
|
use tower_http::compression::CompressionLayer;
|
||||||
|
|
||||||
// TODO: this should skip compression on responses smaller than ~256 bytes because gzip can make them bigger.
|
// TODO: this should skip compression on responses smaller than ~256 bytes because gzip can make them bigger.
|
||||||
/// This builds a compression layer with the following configuration:
|
/// This builds a compression layer with the following configuration:
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
use axum::http::{header, HeaderValue, Request};
|
use axum::{
|
||||||
use axum::middleware::Next;
|
body::Body,
|
||||||
use axum::response::Response;
|
http::{header, HeaderValue, Request},
|
||||||
|
middleware::Next,
|
||||||
|
response::Response,
|
||||||
|
};
|
||||||
|
|
||||||
const HSTS_HEADER: &str = "max-age=86400";
|
const HSTS_HEADER: &str = "max-age=86400";
|
||||||
|
|
||||||
pub async fn strict_transport_security_layer<B>(request: Request<B>, next: Next<B>) -> Response {
|
pub async fn strict_transport_security_layer(request: Request<Body>, next: Next) -> Response {
|
||||||
// wait for the middleware to come back
|
// wait for the middleware to come back
|
||||||
let mut response = next.run(request).await;
|
let mut response = next.run(request).await;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
|
body::Body,
|
||||||
http::{HeaderValue, Request},
|
http::{HeaderValue, Request},
|
||||||
middleware::Next,
|
middleware::Next,
|
||||||
response::Response,
|
response::Response,
|
||||||
|
@ -15,7 +16,7 @@ pub(crate) mod security_headers;
|
||||||
const KANIDM_VERSION: &str = env!("CARGO_PKG_VERSION");
|
const KANIDM_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
/// Injects a header into the response with "X-KANIDM-VERSION" matching the version of the package.
|
/// Injects a header into the response with "X-KANIDM-VERSION" matching the version of the package.
|
||||||
pub async fn version_middleware<B>(request: Request<B>, next: Next<B>) -> Response {
|
pub async fn version_middleware(request: Request<Body>, next: Next) -> Response {
|
||||||
let mut response = next.run(request).await;
|
let mut response = next.run(request).await;
|
||||||
response
|
response
|
||||||
.headers_mut()
|
.headers_mut()
|
||||||
|
@ -26,7 +27,7 @@ pub async fn version_middleware<B>(request: Request<B>, next: Next<B>) -> Respon
|
||||||
#[cfg(any(test, debug_assertions))]
|
#[cfg(any(test, debug_assertions))]
|
||||||
/// This is a debug middleware to ensure that /v1/ endpoints only return JSON
|
/// This is a debug middleware to ensure that /v1/ endpoints only return JSON
|
||||||
#[instrument(level = "trace", name = "are_we_json_yet", skip_all)]
|
#[instrument(level = "trace", name = "are_we_json_yet", skip_all)]
|
||||||
pub async fn are_we_json_yet<B>(request: Request<B>, next: Next<B>) -> Response {
|
pub async fn are_we_json_yet(request: Request<Body>, next: Next) -> Response {
|
||||||
let uri = request.uri().path().to_string();
|
let uri = request.uri().path().to_string();
|
||||||
|
|
||||||
let response = next.run(request).await;
|
let response = next.run(request).await;
|
||||||
|
@ -54,7 +55,7 @@ pub struct KOpId {
|
||||||
|
|
||||||
/// This runs at the start of the request, adding an extension with `KOpId` which has useful things inside it.
|
/// This runs at the start of the request, adding an extension with `KOpId` which has useful things inside it.
|
||||||
#[instrument(level = "trace", name = "kopid_middleware", skip_all)]
|
#[instrument(level = "trace", name = "kopid_middleware", skip_all)]
|
||||||
pub async fn kopid_middleware<B>(mut request: Request<B>, next: Next<B>) -> Response {
|
pub async fn kopid_middleware(mut request: Request<Body>, next: Next) -> Response {
|
||||||
// generate the event ID
|
// generate the event ID
|
||||||
let eventid = sketching::tracing_forest::id();
|
let eventid = sketching::tracing_forest::id();
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
use axum::extract::State;
|
use axum::{
|
||||||
use axum::http::header;
|
body::Body,
|
||||||
use axum::http::HeaderValue;
|
extract::State,
|
||||||
use axum::http::Request;
|
http::{header, HeaderValue, Request},
|
||||||
use axum::middleware::Next;
|
middleware::Next,
|
||||||
use axum::response::Response;
|
response::Response,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::https::ServerState;
|
use crate::https::ServerState;
|
||||||
|
|
||||||
const PERMISSIONS_POLICY_VALUE: &str = "fullscreen=(), geolocation=()";
|
const PERMISSIONS_POLICY_VALUE: &str = "fullscreen=(), geolocation=()";
|
||||||
const X_CONTENT_TYPE_OPTIONS_VALUE: &str = "nosniff";
|
const X_CONTENT_TYPE_OPTIONS_VALUE: &str = "nosniff";
|
||||||
|
|
||||||
pub async fn security_headers_layer<B>(
|
pub async fn security_headers_layer(
|
||||||
State(state): State<ServerState>,
|
State(state): State<ServerState>,
|
||||||
request: Request<B>,
|
request: Request<Body>,
|
||||||
next: Next<B>,
|
next: Next,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
// wait for the middleware to come back
|
// wait for the middleware to come back
|
||||||
let mut response = next.run(request).await;
|
let mut response = next.run(request).await;
|
||||||
|
|
|
@ -16,47 +16,48 @@ mod v1_scim;
|
||||||
|
|
||||||
use self::extractors::ClientConnInfo;
|
use self::extractors::ClientConnInfo;
|
||||||
use self::javascript::*;
|
use self::javascript::*;
|
||||||
|
use self::v1::SessionId;
|
||||||
use crate::actors::{QueryServerReadV1, QueryServerWriteV1};
|
use crate::actors::{QueryServerReadV1, QueryServerWriteV1};
|
||||||
use crate::config::{Configuration, ServerRole, TlsConfiguration};
|
use crate::config::{Configuration, ServerRole, TlsConfiguration};
|
||||||
use axum::extract::connect_info::IntoMakeServiceWithConnectInfo;
|
use crate::CoreAction;
|
||||||
use axum::http::{HeaderMap, HeaderValue};
|
|
||||||
use axum::middleware::{from_fn, from_fn_with_state};
|
use axum::{
|
||||||
use axum::response::Redirect;
|
body::Body,
|
||||||
use axum::routing::*;
|
extract::connect_info::IntoMakeServiceWithConnectInfo,
|
||||||
use axum::Router;
|
http::{HeaderMap, HeaderValue, Request},
|
||||||
use axum_csp::{CspDirectiveType, CspValue};
|
middleware::{from_fn, from_fn_with_state},
|
||||||
|
response::Redirect,
|
||||||
|
routing::*,
|
||||||
|
Router,
|
||||||
|
};
|
||||||
|
|
||||||
use axum_extra::extract::cookie::CookieJar;
|
use axum_extra::extract::cookie::CookieJar;
|
||||||
use compact_jwt::{JwsCompact, JwsHs256Signer, JwsVerifier};
|
use compact_jwt::{JwsCompact, JwsHs256Signer, JwsVerifier};
|
||||||
|
use futures::pin_mut;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use hyper::server::accept::Accept;
|
use hyper::body::Incoming;
|
||||||
use hyper::server::conn::{AddrStream, Http};
|
use hyper_util::rt::{TokioExecutor, TokioIo};
|
||||||
use kanidm_proto::constants::KSESSIONID;
|
use kanidm_proto::{constants::KSESSIONID, internal::COOKIE_AUTH_SESSION_ID};
|
||||||
use kanidm_proto::internal::COOKIE_AUTH_SESSION_ID;
|
use kanidmd_lib::{idm::ClientCertInfo, status::StatusActor};
|
||||||
use kanidmd_lib::idm::ClientCertInfo;
|
|
||||||
use kanidmd_lib::status::StatusActor;
|
|
||||||
use openssl::nid;
|
use openssl::nid;
|
||||||
use openssl::ssl::{Ssl, SslAcceptor, SslFiletype, SslMethod, SslSessionCacheMode, SslVerifyMode};
|
use openssl::ssl::{Ssl, SslAcceptor, SslFiletype, SslMethod, SslSessionCacheMode, SslVerifyMode};
|
||||||
use openssl::x509::X509;
|
use openssl::x509::X509;
|
||||||
use sketching::*;
|
|
||||||
use tokio_openssl::SslStream;
|
|
||||||
|
|
||||||
use futures_util::future::poll_fn;
|
use sketching::*;
|
||||||
use tokio::net::TcpListener;
|
use tokio::{
|
||||||
|
net::{TcpListener, TcpStream},
|
||||||
|
sync::broadcast,
|
||||||
|
};
|
||||||
|
use tokio_openssl::SslStream;
|
||||||
|
use tower::Service;
|
||||||
|
use tower_http::{services::ServeDir, trace::TraceLayer};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{ErrorKind, Read};
|
use std::io::{ErrorKind, Read};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::{net::SocketAddr, str::FromStr};
|
use std::{net::SocketAddr, str::FromStr};
|
||||||
use tokio::sync::broadcast;
|
|
||||||
use tower_http::services::ServeDir;
|
|
||||||
use tower_http::trace::TraceLayer;
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::CoreAction;
|
|
||||||
|
|
||||||
use self::v1::SessionId;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ServerState {
|
pub struct ServerState {
|
||||||
|
@ -213,34 +214,28 @@ pub async fn create_https_server(
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|f| f.hash)
|
.map(|f| f.hash)
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
let mut js_directives: Vec<CspValue> = js_directives
|
|
||||||
.into_iter()
|
|
||||||
.map(|value| CspValue::Sha384 { value })
|
|
||||||
.collect();
|
|
||||||
js_directives.extend(vec![CspValue::UnsafeEval, CspValue::SelfSite]);
|
|
||||||
|
|
||||||
let csp_header = axum_csp::CspSetBuilder::new()
|
let js_checksums: String = js_directives
|
||||||
// default-src 'self';
|
.iter()
|
||||||
.add(CspDirectiveType::DefaultSrc, vec![CspValue::SelfSite])
|
.map(|value| format!(" 'sha384-{}'", value))
|
||||||
// form-action https: 'self';
|
.collect();
|
||||||
.add(
|
|
||||||
CspDirectiveType::FormAction,
|
let csp_header = format!(
|
||||||
vec![CspValue::SelfSite, CspValue::SchemeHttps],
|
concat!(
|
||||||
)
|
"base-uri 'self' https:; ",
|
||||||
// base-uri 'self';
|
"default-src 'self'; ",
|
||||||
.add(
|
"form-action 'self' https:;",
|
||||||
CspDirectiveType::BaseUri,
|
"frame-ancestors 'none'; ",
|
||||||
vec![CspValue::SelfSite, CspValue::SchemeHttps],
|
"img-src 'self' data:; ",
|
||||||
)
|
"worker-src 'none'; ",
|
||||||
// worker-src 'none';
|
"script-src 'self' 'unsafe-eval'{};"
|
||||||
.add(CspDirectiveType::WorkerSource, vec![CspValue::None])
|
),
|
||||||
// frame-ancestors 'none'
|
js_checksums
|
||||||
.add(CspDirectiveType::FrameAncestors, vec![CspValue::None])
|
);
|
||||||
.add(CspDirectiveType::ScriptSource, js_directives)
|
|
||||||
.add(
|
let csp_header = HeaderValue::from_str(&csp_header).map_err(|err| {
|
||||||
CspDirectiveType::ImgSrc,
|
error!(?err, "Unable to generate content security policy");
|
||||||
vec![CspValue::SelfSite, CspValue::SchemeData],
|
})?;
|
||||||
);
|
|
||||||
|
|
||||||
let trust_x_forward_for = config.trust_x_forward_for;
|
let trust_x_forward_for = config.trust_x_forward_for;
|
||||||
|
|
||||||
|
@ -251,7 +246,7 @@ pub async fn create_https_server(
|
||||||
jws_signer,
|
jws_signer,
|
||||||
js_files,
|
js_files,
|
||||||
trust_x_forward_for,
|
trust_x_forward_for,
|
||||||
csp_header: csp_header.finish(),
|
csp_header,
|
||||||
domain: config.domain.clone(),
|
domain: config.domain.clone(),
|
||||||
secure_cookies: config.integration_test_config.is_none(),
|
secure_cookies: config.integration_test_config.is_none(),
|
||||||
};
|
};
|
||||||
|
@ -537,23 +532,13 @@ async fn server_loop(
|
||||||
}
|
}
|
||||||
|
|
||||||
let tls_acceptor = tls_builder.build();
|
let tls_acceptor = tls_builder.build();
|
||||||
|
pin_mut!(listener);
|
||||||
|
|
||||||
let protocol = Arc::new(Http::new());
|
|
||||||
let mut listener =
|
|
||||||
hyper::server::conn::AddrIncoming::from_listener(listener).map_err(|err| {
|
|
||||||
std::io::Error::new(
|
|
||||||
ErrorKind::Other,
|
|
||||||
format!("Failed to create listener: {:?}", err),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
loop {
|
loop {
|
||||||
if let Some(Ok(stream)) = poll_fn(|cx| Pin::new(&mut listener).poll_accept(cx)).await {
|
if let Ok((stream, addr)) = listener.accept().await {
|
||||||
let tls_acceptor = tls_acceptor.clone();
|
let tls_acceptor = tls_acceptor.clone();
|
||||||
let app = app.clone();
|
let app = app.clone();
|
||||||
|
tokio::spawn(handle_conn(tls_acceptor, stream, app, addr));
|
||||||
// let svc = tower::MakeService::make_service(&mut app, &stream);
|
|
||||||
// tokio::spawn(handle_conn(tls_acceptor, stream, svc, protocol.clone()));
|
|
||||||
tokio::spawn(handle_conn(tls_acceptor, stream, app, protocol.clone()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -561,18 +546,15 @@ async fn server_loop(
|
||||||
/// This handles an individual connection.
|
/// This handles an individual connection.
|
||||||
pub(crate) async fn handle_conn(
|
pub(crate) async fn handle_conn(
|
||||||
acceptor: SslAcceptor,
|
acceptor: SslAcceptor,
|
||||||
stream: AddrStream,
|
stream: TcpStream,
|
||||||
// svc: ResponseFuture<Router, ClientConnInfo>,
|
|
||||||
mut app: IntoMakeServiceWithConnectInfo<Router, ClientConnInfo>,
|
mut app: IntoMakeServiceWithConnectInfo<Router, ClientConnInfo>,
|
||||||
protocol: Arc<Http>,
|
addr: SocketAddr,
|
||||||
) -> Result<(), std::io::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
let ssl = Ssl::new(acceptor.context()).map_err(|e| {
|
let ssl = Ssl::new(acceptor.context()).map_err(|e| {
|
||||||
error!("Failed to create TLS context: {:?}", e);
|
error!("Failed to create TLS context: {:?}", e);
|
||||||
std::io::Error::from(ErrorKind::ConnectionAborted)
|
std::io::Error::from(ErrorKind::ConnectionAborted)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let addr = stream.remote_addr();
|
|
||||||
|
|
||||||
let mut tls_stream = SslStream::new(ssl, stream).map_err(|e| {
|
let mut tls_stream = SslStream::new(ssl, stream).map_err(|e| {
|
||||||
error!("Failed to create TLS stream: {:?}", e);
|
error!("Failed to create TLS stream: {:?}", e);
|
||||||
std::io::Error::from(ErrorKind::ConnectionAborted)
|
std::io::Error::from(ErrorKind::ConnectionAborted)
|
||||||
|
@ -611,15 +593,33 @@ pub(crate) async fn handle_conn(
|
||||||
|
|
||||||
debug!(?client_conn_info);
|
debug!(?client_conn_info);
|
||||||
|
|
||||||
let svc = tower::MakeService::make_service(&mut app, client_conn_info);
|
let svc = tower::MakeService::<ClientConnInfo, hyper::Request<Body>>::make_service(
|
||||||
|
&mut app,
|
||||||
|
client_conn_info,
|
||||||
|
);
|
||||||
|
|
||||||
let svc = svc.await.map_err(|e| {
|
let svc = svc.await.map_err(|e| {
|
||||||
error!("Failed to build HTTP response: {:?}", e);
|
error!("Failed to build HTTP response: {:?}", e);
|
||||||
std::io::Error::from(ErrorKind::Other)
|
std::io::Error::from(ErrorKind::Other)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
protocol
|
// Hyper has its own `AsyncRead` and `AsyncWrite` traits and doesn't use tokio.
|
||||||
.serve_connection(tls_stream, svc)
|
// `TokioIo` converts between them.
|
||||||
|
let stream = TokioIo::new(tls_stream);
|
||||||
|
|
||||||
|
// Hyper also has its own `Service` trait and doesn't use tower. We can use
|
||||||
|
// `hyper::service::service_fn` to create a hyper `Service` that calls our app through
|
||||||
|
// `tower::Service::call`.
|
||||||
|
let hyper_service = hyper::service::service_fn(move |request: Request<Incoming>| {
|
||||||
|
// We have to clone `tower_service` because hyper's `Service` uses `&self` whereas
|
||||||
|
// tower's `Service` requires `&mut self`.
|
||||||
|
//
|
||||||
|
// We don't need to call `poll_ready` since `Router` is always ready.
|
||||||
|
svc.clone().call(request)
|
||||||
|
});
|
||||||
|
|
||||||
|
hyper_util::server::conn::auto::Builder::new(TokioExecutor::new())
|
||||||
|
.serve_connection_with_upgrades(stream, hyper_service)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
debug!("Failed to complete connection: {:?}", e);
|
debug!("Failed to complete connection: {:?}", e);
|
||||||
|
|
|
@ -2,19 +2,21 @@ use super::errors::WebError;
|
||||||
use super::middleware::KOpId;
|
use super::middleware::KOpId;
|
||||||
use super::ServerState;
|
use super::ServerState;
|
||||||
use crate::https::extractors::VerifiedClientInformation;
|
use crate::https::extractors::VerifiedClientInformation;
|
||||||
use axum::extract::{Path, Query, State};
|
use axum::{
|
||||||
use axum::http::header::{
|
body::Body,
|
||||||
ACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_ORIGIN, CONTENT_TYPE, LOCATION,
|
extract::{Path, Query, State},
|
||||||
WWW_AUTHENTICATE,
|
http::header::{
|
||||||
|
ACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_ORIGIN, CONTENT_TYPE, LOCATION,
|
||||||
|
WWW_AUTHENTICATE,
|
||||||
|
},
|
||||||
|
http::{HeaderValue, StatusCode},
|
||||||
|
middleware::from_fn,
|
||||||
|
response::{IntoResponse, Response},
|
||||||
|
routing::{get, post},
|
||||||
|
Extension, Form, Json, Router,
|
||||||
};
|
};
|
||||||
use axum::http::{HeaderValue, StatusCode};
|
|
||||||
use axum::middleware::from_fn;
|
|
||||||
use axum::response::{IntoResponse, Response};
|
|
||||||
use axum::routing::{get, post};
|
|
||||||
use axum::{Extension, Form, Json, Router};
|
|
||||||
use axum_macros::debug_handler;
|
use axum_macros::debug_handler;
|
||||||
use compact_jwt::{JwkKeySet, OidcToken};
|
use compact_jwt::{JwkKeySet, OidcToken};
|
||||||
use hyper::Body;
|
|
||||||
use kanidm_proto::constants::uri::{
|
use kanidm_proto::constants::uri::{
|
||||||
OAUTH2_AUTHORISE, OAUTH2_AUTHORISE_PERMIT, OAUTH2_AUTHORISE_REJECT,
|
OAUTH2_AUTHORISE, OAUTH2_AUTHORISE_PERMIT, OAUTH2_AUTHORISE_REJECT,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2846,7 +2846,7 @@ fn auth_session_state_management(
|
||||||
bearer_cookie.set_path("/");
|
bearer_cookie.set_path("/");
|
||||||
jar = jar
|
jar = jar
|
||||||
.add(bearer_cookie)
|
.add(bearer_cookie)
|
||||||
.remove(Cookie::named(COOKIE_AUTH_SESSION_ID));
|
.remove(Cookie::from(COOKIE_AUTH_SESSION_ID));
|
||||||
Ok(ProtoAuthState::Success(token_str))
|
Ok(ProtoAuthState::Success(token_str))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ use axum::extract::{Path, State};
|
||||||
use axum::response::Html;
|
use axum::response::Html;
|
||||||
use axum::routing::{get, post};
|
use axum::routing::{get, post};
|
||||||
use axum::{Extension, Json, Router};
|
use axum::{Extension, Json, Router};
|
||||||
use axum_auth::AuthBearer;
|
|
||||||
use kanidm_proto::scim_v1::{ScimSyncRequest, ScimSyncState};
|
use kanidm_proto::scim_v1::{ScimSyncRequest, ScimSyncState};
|
||||||
use kanidm_proto::v1::Entry as ProtoEntry;
|
use kanidm_proto::v1::Entry as ProtoEntry;
|
||||||
use kanidmd_lib::prelude::*;
|
use kanidmd_lib::prelude::*;
|
||||||
|
@ -247,10 +246,8 @@ async fn scim_sync_get(
|
||||||
State(state): State<ServerState>,
|
State(state): State<ServerState>,
|
||||||
Extension(kopid): Extension<KOpId>,
|
Extension(kopid): Extension<KOpId>,
|
||||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||||
AuthBearer(bearer): AuthBearer,
|
|
||||||
) -> Result<Json<ScimSyncState>, WebError> {
|
) -> Result<Json<ScimSyncState>, WebError> {
|
||||||
// Given the token, what is it's connected sync state?
|
// Given the token, what is it's connected sync state?
|
||||||
trace!(?bearer);
|
|
||||||
state
|
state
|
||||||
.qe_r_ref
|
.qe_r_ref
|
||||||
.handle_scim_sync_status(client_auth_info, kopid.eventid)
|
.handle_scim_sync_status(client_auth_info, kopid.eventid)
|
||||||
|
|
Loading…
Reference in a new issue