1use super::connection::TlsConfig;
5use std::sync::Arc;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
9pub enum ScramChannelBindingMode {
10 Disable,
12 #[default]
14 Prefer,
15 Require,
17}
18
19impl ScramChannelBindingMode {
20 pub fn parse(value: &str) -> Option<Self> {
22 match value.trim().to_ascii_lowercase().as_str() {
23 "disable" | "off" | "false" | "no" => Some(Self::Disable),
24 "prefer" | "on" | "true" | "yes" => Some(Self::Prefer),
25 "require" | "required" => Some(Self::Require),
26 _ => None,
27 }
28 }
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum EnterpriseAuthMechanism {
34 KerberosV5,
36 GssApi,
38 Sspi,
40}
41
42#[derive(Debug, Clone, Copy)]
44pub struct GssTokenRequest<'a> {
45 pub session_id: u64,
47 pub mechanism: EnterpriseAuthMechanism,
49 pub server_token: Option<&'a [u8]>,
51}
52
53pub type GssTokenProvider =
58 Arc<dyn for<'a> Fn(GssTokenRequest<'a>) -> Result<Vec<u8>, String> + Send + Sync>;
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub struct AuthSettings {
65 pub allow_cleartext_password: bool,
67 pub allow_md5_password: bool,
69 pub allow_scram_sha_256: bool,
71 pub allow_kerberos_v5: bool,
73 pub allow_gssapi: bool,
75 pub allow_sspi: bool,
77 pub channel_binding: ScramChannelBindingMode,
79}
80
81impl Default for AuthSettings {
82 fn default() -> Self {
83 Self {
84 allow_cleartext_password: true,
85 allow_md5_password: true,
86 allow_scram_sha_256: true,
87 allow_kerberos_v5: false,
88 allow_gssapi: false,
89 allow_sspi: false,
90 channel_binding: ScramChannelBindingMode::Prefer,
91 }
92 }
93}
94
95impl AuthSettings {
96 pub fn scram_only() -> Self {
98 Self {
99 allow_cleartext_password: false,
100 allow_md5_password: false,
101 allow_scram_sha_256: true,
102 allow_kerberos_v5: false,
103 allow_gssapi: false,
104 allow_sspi: false,
105 channel_binding: ScramChannelBindingMode::Prefer,
106 }
107 }
108
109 pub fn gssapi_only() -> Self {
111 Self {
112 allow_cleartext_password: false,
113 allow_md5_password: false,
114 allow_scram_sha_256: false,
115 allow_kerberos_v5: true,
116 allow_gssapi: true,
117 allow_sspi: true,
118 channel_binding: ScramChannelBindingMode::Prefer,
119 }
120 }
121
122 pub(crate) fn has_any_password_method(self) -> bool {
123 self.allow_cleartext_password || self.allow_md5_password || self.allow_scram_sha_256
124 }
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
129pub enum TlsMode {
130 #[default]
132 Disable,
133 Prefer,
135 Require,
137}
138
139impl TlsMode {
140 pub fn parse_sslmode(value: &str) -> Option<Self> {
142 match value.trim().to_ascii_lowercase().as_str() {
143 "disable" => Some(Self::Disable),
144 "allow" | "prefer" => Some(Self::Prefer),
145 "require" | "verify-ca" | "verify-full" => Some(Self::Require),
146 _ => None,
147 }
148 }
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
158pub enum GssEncMode {
159 #[default]
161 Disable,
162 Prefer,
164 Require,
166}
167
168impl GssEncMode {
169 pub fn parse_gssencmode(value: &str) -> Option<Self> {
171 match value.trim().to_ascii_lowercase().as_str() {
172 "disable" => Some(Self::Disable),
173 "prefer" => Some(Self::Prefer),
174 "require" => Some(Self::Require),
175 _ => None,
176 }
177 }
178}
179
180#[derive(Clone, Default)]
186pub struct ConnectOptions {
187 pub tls_mode: TlsMode,
189 pub gss_enc_mode: GssEncMode,
191 pub tls_ca_cert_pem: Option<Vec<u8>>,
193 pub mtls: Option<TlsConfig>,
195 pub gss_token_provider: Option<GssTokenProvider>,
197 pub auth: AuthSettings,
199 pub io_uring: bool,
205 pub startup_params: Vec<(String, String)>,
208}
209
210impl std::fmt::Debug for ConnectOptions {
211 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212 f.debug_struct("ConnectOptions")
213 .field("tls_mode", &self.tls_mode)
214 .field("gss_enc_mode", &self.gss_enc_mode)
215 .field(
216 "tls_ca_cert_pem",
217 &self.tls_ca_cert_pem.as_ref().map(std::vec::Vec::len),
218 )
219 .field("mtls", &self.mtls.as_ref().map(|_| "<configured>"))
220 .field(
221 "gss_token_provider",
222 &self.gss_token_provider.as_ref().map(|_| "<configured>"),
223 )
224 .field("auth", &self.auth)
225 .field("io_uring", &self.io_uring)
226 .field("startup_params_count", &self.startup_params.len())
227 .finish()
228 }
229}
230
231impl ConnectOptions {
232 pub fn with_startup_param(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
236 let key = key.into();
237 let value = value.into();
238 self.startup_params
239 .retain(|(existing, _)| !existing.eq_ignore_ascii_case(&key));
240 self.startup_params.push((key, value));
241 self
242 }
243
244 pub fn with_logical_replication(mut self) -> Self {
246 self.startup_params
247 .retain(|(k, _)| !k.eq_ignore_ascii_case("replication"));
248 self.startup_params
249 .push(("replication".to_string(), "database".to_string()));
250 self
251 }
252
253 pub fn with_io_uring(mut self, enabled: bool) -> Self {
255 self.io_uring = enabled;
256 self
257 }
258}