First step done

This commit is contained in:
William Brown 2025-04-03 15:11:22 +10:00
parent ad012cd6fd
commit 9b3a4ad761
4 changed files with 103 additions and 25 deletions
server
core/src
testkit-macros/src
testkit/tests/testkit

View file

@ -100,6 +100,59 @@ pub struct TlsConfiguration {
pub client_ca: Option<PathBuf>,
}
#[derive(Deserialize, Debug, Clone, Default)]
pub enum LdapAddressInfo {
#[default]
None,
#[serde(rename = "proxy-v2")]
ProxyV2,
}
impl LdapAddressInfo {
pub fn proxy_v2(&self) -> bool {
matches!(self, Self::ProxyV2)
}
}
impl Display for LdapAddressInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::None => f.write_str("none"),
Self::ProxyV2 => f.write_str("proxy-v2"),
}
}
}
#[derive(Deserialize, Debug, Clone, Default)]
pub enum HttpAddressInfo {
#[default]
None,
#[serde(rename = "x-forward-for")]
XForwardFor,
#[serde(rename = "proxy-v2")]
ProxyV2,
}
impl HttpAddressInfo {
pub fn is_x_forward_for(&self) -> bool {
matches!(self, Self::XForwardFor)
}
pub fn proxy_v2(&self) -> bool {
matches!(self, Self::ProxyV2)
}
}
impl Display for HttpAddressInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::None => f.write_str("none"),
Self::XForwardFor => f.write_str("x-forward-for"),
Self::ProxyV2 => f.write_str("proxy-v2"),
}
}
}
/// This is the Server Configuration as read from `server.toml` or environment variables.
///
/// Fields noted as "REQUIRED" are required for the server to start, even if they show as optional due to how file parsing works.
@ -217,7 +270,10 @@ pub struct ServerConfigV2 {
role: Option<ServerRole>,
log_level: Option<LogLevel>,
online_backup: Option<OnlineBackup>,
trust_x_forward_for: Option<bool>,
http_client_address_info: Option<HttpAddressInfo>,
ldap_client_address_info: Option<LdapAddressInfo>,
adminbindpath: Option<String>,
thread_count: Option<usize>,
maximum_request_size_bytes: Option<usize>,
@ -490,7 +546,10 @@ pub struct Configuration {
pub db_fs_type: Option<FsType>,
pub db_arc_size: Option<usize>,
pub maximum_request: usize,
pub trust_x_forward_for: bool,
pub http_client_address_info: HttpAddressInfo,
pub ldap_client_address_info: LdapAddressInfo,
pub tls_config: Option<TlsConfiguration>,
pub integration_test_config: Option<Box<IntegrationTestConfig>>,
pub online_backup: Option<OnlineBackup>,
@ -522,7 +581,8 @@ impl Configuration {
db_fs_type: None,
db_arc_size: None,
maximum_request: 256 * 1024, // 256k
trust_x_forward_for: None,
http_client_address_info: HttpAddressInfo::default(),
ldap_client_address_info: LdapAddressInfo::default(),
tls_key: None,
tls_chain: None,
tls_client_ca: None,
@ -547,7 +607,8 @@ impl Configuration {
db_fs_type: None,
db_arc_size: None,
maximum_request: 256 * 1024, // 256k
trust_x_forward_for: false,
http_client_address_info: HttpAddressInfo::default(),
ldap_client_address_info: LdapAddressInfo::default(),
tls_config: None,
integration_test_config: None,
online_backup: None,
@ -587,7 +648,17 @@ impl fmt::Display for Configuration {
None => write!(f, "arcsize: AUTO, "),
}?;
write!(f, "max request size: {}b, ", self.maximum_request)?;
write!(f, "trust X-Forwarded-For: {}, ", self.trust_x_forward_for)?;
write!(
f,
"http client address info: {}, ",
self.http_client_address_info
)?;
write!(
f,
"ldap client address info: {}, ",
self.ldap_client_address_info
)?;
write!(f, "with TLS: {}, ", self.tls_config.is_some())?;
match &self.online_backup {
Some(bck) => write!(
@ -642,7 +713,8 @@ pub struct ConfigurationBuilder {
db_fs_type: Option<FsType>,
db_arc_size: Option<usize>,
maximum_request: usize,
trust_x_forward_for: Option<bool>,
http_client_address_info: HttpAddressInfo,
ldap_client_address_info: LdapAddressInfo,
tls_key: Option<PathBuf>,
tls_chain: Option<PathBuf>,
tls_client_ca: Option<PathBuf>,
@ -691,8 +763,8 @@ impl ConfigurationBuilder {
self.db_arc_size = env_config.db_arc_size;
}
if env_config.trust_x_forward_for.is_some() {
self.trust_x_forward_for = env_config.trust_x_forward_for;
if env_config.trust_x_forward_for == Some(true) {
self.http_client_address_info = HttpAddressInfo::XForwardFor;
}
if env_config.tls_key.is_some() {
@ -813,8 +885,8 @@ impl ConfigurationBuilder {
self.db_arc_size = config.db_arc_size;
}
if config.trust_x_forward_for.is_some() {
self.trust_x_forward_for = config.trust_x_forward_for;
if config.trust_x_forward_for == Some(true) {
self.http_client_address_info = HttpAddressInfo::XForwardFor;
}
if config.online_backup.is_some() {
@ -893,8 +965,12 @@ impl ConfigurationBuilder {
self.db_arc_size = config.db_arc_size;
}
if config.trust_x_forward_for.is_some() {
self.trust_x_forward_for = config.trust_x_forward_for;
if let Some(http_client_address_info) = config.http_client_address_info {
self.http_client_address_info = http_client_address_info
}
if let Some(ldap_client_address_info) = config.ldap_client_address_info {
self.ldap_client_address_info = ldap_client_address_info
}
if config.online_backup.is_some() {
@ -930,7 +1006,8 @@ impl ConfigurationBuilder {
db_fs_type,
db_arc_size,
maximum_request,
trust_x_forward_for,
http_client_address_info,
ldap_client_address_info,
tls_key,
tls_chain,
tls_client_ca,
@ -986,7 +1063,6 @@ impl ConfigurationBuilder {
let adminbindpath =
adminbindpath.unwrap_or(env!("KANIDM_SERVER_ADMIN_BIND_PATH").to_string());
let address = bindaddress.unwrap_or(DEFAULT_SERVER_ADDRESS.to_string());
let trust_x_forward_for = trust_x_forward_for.unwrap_or_default();
let output_mode = output_mode.unwrap_or_default();
let role = role.unwrap_or(ServerRole::WriteReplica);
let log_level = log_level.unwrap_or_default();
@ -1000,7 +1076,8 @@ impl ConfigurationBuilder {
db_fs_type,
db_arc_size,
maximum_request,
trust_x_forward_for,
http_client_address_info,
ldap_client_address_info,
tls_config,
online_backup,
domain,

View file

@ -211,7 +211,7 @@ pub async fn create_https_server(
error!(?err, "Unable to generate content security policy");
})?;
let trust_x_forward_for = config.trust_x_forward_for;
let trust_x_forward_for = config.http_client_address_info.is_x_forward_for();
let origin = Url::parse(&config.origin)
// Should be impossible!

View file

@ -10,7 +10,7 @@ const ALLOWED_ATTRIBUTES: &[&str] = &[
"threads",
"db_path",
"maximum_request",
"trust_x_forward_for",
"http_client_address_info",
"role",
"output_mode",
"log_level",

View file

@ -5,12 +5,13 @@ use std::{
use kanidm_client::KanidmClient;
use kanidm_proto::constants::X_FORWARDED_FOR;
use kanidmd_core::config::HttpAddressInfo;
const DEFAULT_IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
// *test where we don't trust the x-forwarded-for header
#[kanidmd_testkit::test(trust_x_forward_for = false)]
#[kanidmd_testkit::test(http_client_address_info = HttpAddressInfo::None)]
async fn dont_trust_xff_send_header(rsclient: &KanidmClient) {
let client = rsclient.client();
@ -31,7 +32,7 @@ async fn dont_trust_xff_send_header(rsclient: &KanidmClient) {
assert_eq!(ip_res, DEFAULT_IP_ADDRESS);
}
#[kanidmd_testkit::test(trust_x_forward_for = false)]
#[kanidmd_testkit::test(http_client_address_info = HttpAddressInfo::None)]
async fn dont_trust_xff_dont_send_header(rsclient: &KanidmClient) {
let client = rsclient.client();
@ -57,7 +58,7 @@ async fn dont_trust_xff_dont_send_header(rsclient: &KanidmClient) {
// *test where we trust the x-forwarded-for header
#[kanidmd_testkit::test(trust_x_forward_for = true)]
#[kanidmd_testkit::test(http_client_address_info = HttpAddressInfo::XForwardFor)]
async fn trust_xff_send_invalid_header_single_value(rsclient: &KanidmClient) {
let client = rsclient.client();
@ -77,7 +78,7 @@ async fn trust_xff_send_invalid_header_single_value(rsclient: &KanidmClient) {
// TODO: Right now we reject the request only if the leftmost address is invalid. In the future that could change so we could also have a test
// with a valid leftmost address and an invalid address later in the list. Right now it wouldn't work.
//
#[kanidmd_testkit::test(trust_x_forward_for = true)]
#[kanidmd_testkit::test(http_client_address_info = HttpAddressInfo::XForwardFor)]
async fn trust_xff_send_invalid_header_multiple_values(rsclient: &KanidmClient) {
let client = rsclient.client();
@ -94,7 +95,7 @@ async fn trust_xff_send_invalid_header_multiple_values(rsclient: &KanidmClient)
assert_eq!(res.status(), 400);
}
#[kanidmd_testkit::test(trust_x_forward_for = true)]
#[kanidmd_testkit::test(http_client_address_info = HttpAddressInfo::XForwardFor)]
async fn trust_xff_send_valid_header_single_ipv4_address(rsclient: &KanidmClient) {
let ip_addr = "2001:db8:85a3:8d3:1319:8a2e:370:7348";
@ -114,7 +115,7 @@ async fn trust_xff_send_valid_header_single_ipv4_address(rsclient: &KanidmClient
assert_eq!(ip_res, IpAddr::from_str(ip_addr).unwrap());
}
#[kanidmd_testkit::test(trust_x_forward_for = true)]
#[kanidmd_testkit::test(http_client_address_info = HttpAddressInfo::XForwardFor)]
async fn trust_xff_send_valid_header_single_ipv6_address(rsclient: &KanidmClient) {
let ip_addr = "203.0.113.195";
@ -134,7 +135,7 @@ async fn trust_xff_send_valid_header_single_ipv6_address(rsclient: &KanidmClient
assert_eq!(ip_res, IpAddr::from_str(ip_addr).unwrap());
}
#[kanidmd_testkit::test(trust_x_forward_for = true)]
#[kanidmd_testkit::test(http_client_address_info = HttpAddressInfo::XForwardFor)]
async fn trust_xff_send_valid_header_multiple_address(rsclient: &KanidmClient) {
let first_ip_addr = "203.0.113.195, 2001:db8:85a3:8d3:1319:8a2e:370:7348";
@ -175,7 +176,7 @@ async fn trust_xff_send_valid_header_multiple_address(rsclient: &KanidmClient) {
);
}
#[kanidmd_testkit::test(trust_x_forward_for = true)]
#[kanidmd_testkit::test(http_client_address_info = HttpAddressInfo::XForwardFor)]
async fn trust_xff_dont_send_header(rsclient: &KanidmClient) {
let client = rsclient.client();