Add end2end tests #2
@ -50,7 +50,7 @@ impl ClientConfig {
|
|||||||
self._keys_cache = KeysCache {
|
self._keys_cache = KeysCache {
|
||||||
_root_certificate_cache: load_pem_file(&self.root_certificate, "root certificate")?,
|
_root_certificate_cache: load_pem_file(&self.root_certificate, "root certificate")?,
|
||||||
_tls_cert_cache: load_pem_file(&self.tls_cert, "client certificate")?,
|
_tls_cert_cache: load_pem_file(&self.tls_cert, "client certificate")?,
|
||||||
_tls_key_cache: load_pem_file(&self.tls_cert, "client key")?,
|
_tls_key_cache: load_pem_file(&self.tls_key, "client key")?,
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ pub async fn run_app(mut config: ServerConfig) -> std::io::Result<()> {
|
|||||||
|
|
||||||
let config = match args.has_tls_client_auth() {
|
let config = match args.has_tls_client_auth() {
|
||||||
true => config
|
true => config
|
||||||
.with_client_cert_verifier(Arc::new(CustomCertClientVerifier::new(args.clone()))),
|
.with_client_cert_verifier(Arc::new(CustomCertClientVerifier::new(args.clone())?)),
|
||||||
false => config.with_no_client_auth(),
|
false => config.with_no_client_auth(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use rustls::{Certificate, DistinguishedNames, Error, RootCertStore};
|
|||||||
use x509_parser::prelude::{CertificateRevocationList, FromDer, X509Certificate};
|
use x509_parser::prelude::{CertificateRevocationList, FromDer, X509Certificate};
|
||||||
|
|
||||||
use crate::base::cert_utils::parse_pem_certificates;
|
use crate::base::cert_utils::parse_pem_certificates;
|
||||||
|
use crate::base::err_utils::{encpasulate_error, new_err};
|
||||||
use crate::tcp_relay_server::server_config::ServerConfig;
|
use crate::tcp_relay_server::server_config::ServerConfig;
|
||||||
|
|
||||||
pub struct CustomCertClientVerifier {
|
pub struct CustomCertClientVerifier {
|
||||||
@ -16,21 +16,28 @@ pub struct CustomCertClientVerifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CustomCertClientVerifier {
|
impl CustomCertClientVerifier {
|
||||||
pub fn new(conf: Arc<ServerConfig>) -> Self {
|
pub fn new(conf: Arc<ServerConfig>) -> std::io::Result<Self> {
|
||||||
// Build root certifications list
|
// Build root certifications list
|
||||||
let cert_path = conf
|
let cert_path = conf
|
||||||
.tls_client_auth_root_cert
|
.tls_client_auth_root_cert
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.expect("No root certificates for client authentication provided!");
|
.expect("No root certificates for client authentication provided!");
|
||||||
let cert_file = std::fs::read(cert_path)
|
let cert_file = std::fs::read(cert_path).map_err(|e| {
|
||||||
.expect("Failed to read root certificates for client authentication!");
|
encpasulate_error(
|
||||||
|
e,
|
||||||
|
"Failed to read root certificates for client authentication!",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
let root_certs = parse_pem_certificates(&cert_file)
|
let root_certs = parse_pem_certificates(&cert_file).map_err(|e| {
|
||||||
.expect("Failed to read root certificates for server authentication!");
|
encpasulate_error(
|
||||||
|
e,
|
||||||
|
"Failed to read root certificates for server authentication!",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
if root_certs.is_empty() {
|
if root_certs.is_empty() {
|
||||||
log::error!("No certificates found for client authentication!");
|
return Err(new_err("No certificates found for client authentication!"));
|
||||||
panic!();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut store = RootCertStore::empty();
|
let mut store = RootCertStore::empty();
|
||||||
@ -42,19 +49,21 @@ impl CustomCertClientVerifier {
|
|||||||
|
|
||||||
// Parse CRL file (if any)
|
// Parse CRL file (if any)
|
||||||
let crl = if let Some(crl_file) = &conf.tls_revocation_list {
|
let crl = if let Some(crl_file) = &conf.tls_revocation_list {
|
||||||
let crl_file = std::fs::read(crl_file).expect("Failed to open / read CRL file!");
|
let crl_file = std::fs::read(crl_file)
|
||||||
|
.map_err(|e| encpasulate_error(e, "Failed to open / read CRL file!"))?;
|
||||||
|
|
||||||
let parsed_crl = pem::parse(crl_file).expect("Failed to decode CRL file!");
|
let parsed_crl = pem::parse(crl_file)
|
||||||
|
.map_err(|e| encpasulate_error(e, "Failed to decode CRL file!"))?;
|
||||||
|
|
||||||
Some(parsed_crl.contents)
|
Some(parsed_crl.contents)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Ok(Self {
|
||||||
upstream_cert_verifier: Box::new(AllowAnyAuthenticatedClient::new(store)),
|
upstream_cert_verifier: Box::new(AllowAnyAuthenticatedClient::new(store)),
|
||||||
crl,
|
crl,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ enum PortsAllocation {
|
|||||||
TestsWithoutPortOpened,
|
TestsWithoutPortOpened,
|
||||||
DummyTCPServer,
|
DummyTCPServer,
|
||||||
ValidWithTokenAuth,
|
ValidWithTokenAuth,
|
||||||
|
ValidWithTLSAuth,
|
||||||
InvalidWithTokenAuth,
|
InvalidWithTokenAuth,
|
||||||
ValidWithMultipleTokenAuth,
|
ValidWithMultipleTokenAuth,
|
||||||
ValidWithTokenFile,
|
ValidWithTokenFile,
|
||||||
@ -34,6 +35,7 @@ mod server_invalid_tls_config_missing_key;
|
|||||||
mod server_invalid_token_file;
|
mod server_invalid_token_file;
|
||||||
mod valid_token_with_custom_increment;
|
mod valid_token_with_custom_increment;
|
||||||
mod valid_with_multiple_token_auth;
|
mod valid_with_multiple_token_auth;
|
||||||
|
mod valid_with_tls_auth;
|
||||||
mod valid_with_token_auth;
|
mod valid_with_token_auth;
|
||||||
mod valid_with_token_auth_and_server_tls;
|
mod valid_with_token_auth_and_server_tls;
|
||||||
mod valid_with_token_auth_multiple_ports;
|
mod valid_with_token_auth_multiple_ports;
|
||||||
|
@ -4,6 +4,8 @@ use crate::test::{get_port_number, PortsAllocation};
|
|||||||
|
|
||||||
const TOKEN: &str = "mytok";
|
const TOKEN: &str = "mytok";
|
||||||
|
|
||||||
|
const BAD_PATH: &str = "/bad/path/to/key/file";
|
||||||
|
|
||||||
fn port(index: u16) -> u16 {
|
fn port(index: u16) -> u16 {
|
||||||
get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
|
get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
|
||||||
}
|
}
|
||||||
@ -22,7 +24,7 @@ async fn invalid_key_path() {
|
|||||||
listen_address: format!("127.0.0.1:{}", port(0)),
|
listen_address: format!("127.0.0.1:{}", port(0)),
|
||||||
increment_ports: 1,
|
increment_ports: 1,
|
||||||
tls_cert: Some(pki.localhost_crt.file_path()),
|
tls_cert: Some(pki.localhost_crt.file_path()),
|
||||||
tls_key: Some("/bad/path/to/key/file".to_string()),
|
tls_key: Some(BAD_PATH.to_string()),
|
||||||
tls_client_auth_root_cert: None,
|
tls_client_auth_root_cert: None,
|
||||||
tls_revocation_list: None,
|
tls_revocation_list: None,
|
||||||
})
|
})
|
||||||
@ -43,7 +45,7 @@ async fn invalid_cert_path() {
|
|||||||
upstream_server: "127.0.0.1".to_string(),
|
upstream_server: "127.0.0.1".to_string(),
|
||||||
listen_address: format!("127.0.0.1:{}", port(0)),
|
listen_address: format!("127.0.0.1:{}", port(0)),
|
||||||
increment_ports: 1,
|
increment_ports: 1,
|
||||||
tls_cert: Some("/bad/path/to/key/file".to_string()),
|
tls_cert: Some(BAD_PATH.to_string()),
|
||||||
tls_key: Some(pki.localhost_key.file_path()),
|
tls_key: Some(pki.localhost_key.file_path()),
|
||||||
tls_client_auth_root_cert: None,
|
tls_client_auth_root_cert: None,
|
||||||
tls_revocation_list: None,
|
tls_revocation_list: None,
|
||||||
@ -51,3 +53,47 @@ async fn invalid_cert_path() {
|
|||||||
.await
|
.await
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn invalid_client_root_cert_path() {
|
||||||
|
let _ = env_logger::builder().is_test(true).try_init();
|
||||||
|
|
||||||
|
let pki = Pki::load();
|
||||||
|
|
||||||
|
crate::tcp_relay_server::run_app(ServerConfig {
|
||||||
|
tokens: vec![TOKEN.to_string()],
|
||||||
|
tokens_file: None,
|
||||||
|
ports: vec![port(1)],
|
||||||
|
upstream_server: "127.0.0.1".to_string(),
|
||||||
|
listen_address: format!("127.0.0.1:{}", port(0)),
|
||||||
|
increment_ports: 1,
|
||||||
|
tls_cert: Some(pki.localhost_crt.file_path()),
|
||||||
|
tls_key: Some(pki.localhost_key.file_path()),
|
||||||
|
tls_client_auth_root_cert: Some(BAD_PATH.to_string()),
|
||||||
|
tls_revocation_list: None,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn invalid_client_root_crl_path() {
|
||||||
|
let _ = env_logger::builder().is_test(true).try_init();
|
||||||
|
|
||||||
|
let pki = Pki::load();
|
||||||
|
|
||||||
|
crate::tcp_relay_server::run_app(ServerConfig {
|
||||||
|
tokens: vec![TOKEN.to_string()],
|
||||||
|
tokens_file: None,
|
||||||
|
ports: vec![port(1)],
|
||||||
|
upstream_server: "127.0.0.1".to_string(),
|
||||||
|
listen_address: format!("127.0.0.1:{}", port(0)),
|
||||||
|
increment_ports: 1,
|
||||||
|
tls_cert: Some(pki.localhost_crt.file_path()),
|
||||||
|
tls_key: Some(pki.localhost_key.file_path()),
|
||||||
|
tls_client_auth_root_cert: Some(pki.root_ca_crl.file_path()),
|
||||||
|
tls_revocation_list: Some(BAD_PATH.to_string()),
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap_err();
|
||||||
|
}
|
||||||
|
61
src/test/valid_with_tls_auth.rs
Normal file
61
src/test/valid_with_tls_auth.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
use tokio::task;
|
||||||
|
|
||||||
|
use crate::tcp_relay_client::client_config::ClientConfig;
|
||||||
|
use crate::tcp_relay_server::server_config::ServerConfig;
|
||||||
|
use crate::test::dummy_tcp_sockets::{
|
||||||
|
dummy_tcp_client_square_root_requests, wait_for_port, DummyTCPServer,
|
||||||
|
};
|
||||||
|
use crate::test::pki::Pki;
|
||||||
|
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
|
||||||
|
|
||||||
|
fn port(index: u16) -> u16 {
|
||||||
|
get_port_number(PortsAllocation::ValidWithTLSAuth, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test() {
|
||||||
|
let _ = env_logger::builder().is_test(true).try_init();
|
||||||
|
|
||||||
|
// Start internal service
|
||||||
|
let local_server = DummyTCPServer::start(port(1)).await;
|
||||||
|
tokio::spawn(async move {
|
||||||
|
local_server.loop_conn_square_operations().await;
|
||||||
|
});
|
||||||
|
|
||||||
|
let pki = Pki::load();
|
||||||
|
|
||||||
|
let local_set = task::LocalSet::new();
|
||||||
|
local_set
|
||||||
|
.run_until(async move {
|
||||||
|
wait_for_port(port(1)).await;
|
||||||
|
|
||||||
|
// Start server relay
|
||||||
|
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
|
||||||
|
tokens: vec![],
|
||||||
|
tokens_file: None,
|
||||||
|
ports: vec![port(1)],
|
||||||
|
upstream_server: "127.0.0.1".to_string(),
|
||||||
|
listen_address: format!("127.0.0.1:{}", port(0)),
|
||||||
|
increment_ports: 1,
|
||||||
|
tls_cert: Some(pki.localhost_crt.file_path()),
|
||||||
|
tls_key: Some(pki.localhost_key.file_path()),
|
||||||
|
tls_client_auth_root_cert: Some(pki.root_ca_crt.file_path()),
|
||||||
|
tls_revocation_list: Some(pki.root_ca_crl.file_path()),
|
||||||
|
}));
|
||||||
|
wait_for_port(port(0)).await;
|
||||||
|
|
||||||
|
// Start client relay
|
||||||
|
task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
|
||||||
|
relay_url: format!("https://localhost:{}", port(0)),
|
||||||
|
listen_address: LOCALHOST_IP.to_string(),
|
||||||
|
root_certificate: Some(pki.root_ca_crt.file_path()),
|
||||||
|
tls_cert: Some(pki.valid_client_crt.file_path()),
|
||||||
|
tls_key: Some(pki.valid_client_key.file_path()),
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
wait_for_port(port(2)).await;
|
||||||
|
|
||||||
|
dummy_tcp_client_square_root_requests(port(2), 10).await;
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user