Skip to content

Commit eebf8db

Browse files
authored
feat: support MutualTLS. (#254)
* feat: support MutualTLS. * chore: fix clippy warnings
1 parent 15ddd40 commit eebf8db

File tree

3 files changed

+64
-2
lines changed

3 files changed

+64
-2
lines changed

lib/src/auth/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub enum ConnectionTLSConfig {
55
None,
66
ClientCACertificate(ClientCertificate),
77
NoSSLValidation,
8+
MutualTLS(MutualTLS),
89
}
910

1011
#[derive(Debug, Clone, PartialEq)]
@@ -19,3 +20,24 @@ impl ClientCertificate {
1920
}
2021
}
2122
}
23+
24+
#[derive(Debug, Clone, PartialEq)]
25+
pub struct MutualTLS {
26+
pub(crate) cert_file: Option<PathBuf>,
27+
pub(crate) client_cert: PathBuf,
28+
pub(crate) client_key: PathBuf,
29+
}
30+
31+
impl MutualTLS {
32+
pub fn new(
33+
cert_file: Option<impl AsRef<Path>>,
34+
client_cert: impl AsRef<Path>,
35+
client_key: impl AsRef<Path>,
36+
) -> Self {
37+
MutualTLS {
38+
cert_file: cert_file.map(|p| p.as_ref().to_path_buf()),
39+
client_cert: client_cert.as_ref().to_path_buf(),
40+
client_key: client_key.as_ref().to_path_buf(),
41+
}
42+
}
43+
}

lib/src/config.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::auth::{ClientCertificate, ConnectionTLSConfig};
1+
use crate::auth::{ClientCertificate, ConnectionTLSConfig, MutualTLS};
22
use crate::errors::{Error, Result};
33
#[cfg(feature = "unstable-bolt-protocol-impl-v2")]
44
use serde::{Deserialize, Deserializer, Serialize};
@@ -159,6 +159,18 @@ impl ConfigBuilder {
159159
self
160160
}
161161

162+
//Used for bidirectional authentication
163+
pub fn with_mutual_tls_validation(
164+
mut self,
165+
client_cert: Option<impl AsRef<Path>>,
166+
ssl_cert: impl AsRef<Path>,
167+
ssl_key: impl AsRef<Path>,
168+
) -> Self {
169+
self.tls_config =
170+
ConnectionTLSConfig::MutualTLS(MutualTLS::new(client_cert, ssl_cert, ssl_key));
171+
self
172+
}
173+
162174
/// Skip SSL validation. This is not recommended for production use.
163175
/// This is true by default when connecting to the server using `neo4j+ssc` or 'bolt+ssc' schemes.
164176
pub fn skip_ssl_validation(mut self) -> Self {

lib/src/connection.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,10 @@ impl ConnectionInfo {
401401
.then(|| {
402402
// do not apply validation if using a self-signed certificate,as the documentation suggests
403403
let config = if !validation {
404-
&ConnectionTLSConfig::NoSSLValidation
404+
match tls_config {
405+
ConnectionTLSConfig::MutualTLS(_) => tls_config,
406+
_ => &ConnectionTLSConfig::NoSSLValidation,
407+
}
405408
} else {
406409
tls_config
407410
};
@@ -477,6 +480,31 @@ impl ConnectionInfo {
477480
.dangerous()
478481
.with_custom_certificate_verifier(Arc::new(NoCertificateVerification))
479482
.with_no_client_auth(),
483+
ConnectionTLSConfig::MutualTLS(mutual) => {
484+
let cert_file = File::open(&mutual.client_cert)?;
485+
let mut cert_reader = BufReader::new(cert_file);
486+
let cert_certs = rustls_pemfile::certs(&mut cert_reader).flatten();
487+
488+
let cert_key = File::open(&mutual.client_key)?;
489+
let mut key_reader = BufReader::new(cert_key);
490+
let keys = rustls_pemfile::private_key(&mut key_reader);
491+
let keys = keys?.unwrap();
492+
if mutual.cert_file.is_some() {
493+
let root_cert_file = File::open(mutual.cert_file.as_ref().unwrap())?;
494+
let mut root_reader = BufReader::new(root_cert_file);
495+
let root_certs = rustls_pemfile::certs(&mut root_reader).flatten();
496+
root_cert_store.add_parsable_certificates(root_certs);
497+
builder
498+
.with_root_certificates(root_cert_store)
499+
.with_client_auth_cert(cert_certs.collect(), keys)
500+
.map_err(|_e| Error::ConnectionError)?
501+
} else {
502+
builder
503+
.with_root_certificates(RootCertStore::empty())
504+
.with_client_auth_cert(cert_certs.collect(), keys)
505+
.map_err(|_e| Error::ConnectionError)?
506+
}
507+
}
480508
};
481509

482510
let config = Arc::new(config);

0 commit comments

Comments
 (0)