connectorx/sources/postgres/
connection.rs1use crate::sources::postgres::errors::PostgresSourceError;
2use crate::utils::remove_query_params;
3use openssl::ssl::{SslConnector, SslFiletype, SslMethod, SslVerifyMode};
4use postgres::{config::SslMode, Config};
5use postgres_openssl::MakeTlsConnector;
6use std::collections::HashMap;
7use std::convert::TryFrom;
8use std::path::PathBuf;
9use url::Url;
10
11#[derive(Clone, Debug)]
12pub struct TlsConfig {
13 pub pg_config: Config,
15 pub client_cert: Option<(PathBuf, PathBuf)>,
17 pub root_cert: Option<PathBuf>,
19}
20
21impl TryFrom<TlsConfig> for MakeTlsConnector {
22 type Error = PostgresSourceError;
23 fn try_from(tls_config: TlsConfig) -> Result<Self, Self::Error> {
27 let mut builder = SslConnector::builder(SslMethod::tls_client())?;
28 let ssl_mode = tls_config.pg_config.get_ssl_mode();
29 let (verify_ca, verify_hostname) = match ssl_mode {
30 SslMode::Disable | SslMode::Prefer => (false, false),
31 SslMode::Require => match tls_config.root_cert {
32 Some(_) => (true, false),
38 None => (false, false),
39 },
40 _ => panic!("unexpected sslmode {:?}", ssl_mode),
46 };
47
48 if let Some((cert, key)) = tls_config.client_cert {
49 builder.set_certificate_file(cert, SslFiletype::PEM)?;
50 builder.set_private_key_file(key, SslFiletype::PEM)?;
51 }
52
53 if let Some(root_cert) = tls_config.root_cert {
54 builder.set_ca_file(root_cert)?;
55 }
56
57 if !verify_ca {
58 builder.set_verify(SslVerifyMode::NONE); }
60
61 let mut tls_connector = MakeTlsConnector::new(builder.build());
62
63 if !verify_hostname {
64 tls_connector.set_callback(|connect, _| {
65 connect.set_verify_hostname(false);
66 Ok(())
67 });
68 }
69
70 Ok(tls_connector)
71 }
72}
73
74fn strip_bad_opts(url: &Url) -> Url {
76 remove_query_params(url, &["sslkey", "sslcert", "sslrootcert"])
77}
78
79pub fn rewrite_tls_args(
80 conn: &Url,
81) -> Result<(Config, Option<MakeTlsConnector>), PostgresSourceError> {
82 let params: HashMap<String, String> = conn.query_pairs().into_owned().collect();
89
90 let sslcert = params.get("sslcert").map(PathBuf::from);
91 let sslkey = params.get("sslkey").map(PathBuf::from);
92 let root_cert = params.get("sslrootcert").map(PathBuf::from);
93 let client_cert = match (sslcert, sslkey) {
94 (Some(a), Some(b)) => Some((a, b)),
95 _ => None,
96 };
97
98 let stripped_url = strip_bad_opts(conn);
99 let pg_config: Config = stripped_url.as_str().parse()?;
100
101 let tls_config = TlsConfig {
102 pg_config: pg_config.clone(),
103 client_cert,
104 root_cert,
105 };
106
107 let tls_connector = match pg_config.get_ssl_mode() {
108 SslMode::Disable => None,
109 _ => Some(MakeTlsConnector::try_from(tls_config)?),
110 };
111
112 Ok((pg_config, tls_connector))
113}