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
42pub type GssTokenProvider = fn(EnterpriseAuthMechanism, Option<&[u8]>) -> Result<Vec<u8>, String>;
50
51#[derive(Debug, Clone, Copy)]
53pub struct GssTokenRequest<'a> {
54 pub session_id: u64,
56 pub mechanism: EnterpriseAuthMechanism,
58 pub server_token: Option<&'a [u8]>,
60}
61
62pub type GssTokenProviderEx =
67 Arc<dyn for<'a> Fn(GssTokenRequest<'a>) -> Result<Vec<u8>, String> + Send + Sync>;
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub struct AuthSettings {
74 pub allow_cleartext_password: bool,
76 pub allow_md5_password: bool,
78 pub allow_scram_sha_256: bool,
80 pub allow_kerberos_v5: bool,
82 pub allow_gssapi: bool,
84 pub allow_sspi: bool,
86 pub channel_binding: ScramChannelBindingMode,
88}
89
90impl Default for AuthSettings {
91 fn default() -> Self {
92 Self {
93 allow_cleartext_password: true,
94 allow_md5_password: true,
95 allow_scram_sha_256: true,
96 allow_kerberos_v5: false,
97 allow_gssapi: false,
98 allow_sspi: false,
99 channel_binding: ScramChannelBindingMode::Prefer,
100 }
101 }
102}
103
104impl AuthSettings {
105 pub fn scram_only() -> Self {
107 Self {
108 allow_cleartext_password: false,
109 allow_md5_password: false,
110 allow_scram_sha_256: true,
111 allow_kerberos_v5: false,
112 allow_gssapi: false,
113 allow_sspi: false,
114 channel_binding: ScramChannelBindingMode::Prefer,
115 }
116 }
117
118 pub fn gssapi_only() -> Self {
120 Self {
121 allow_cleartext_password: false,
122 allow_md5_password: false,
123 allow_scram_sha_256: false,
124 allow_kerberos_v5: true,
125 allow_gssapi: true,
126 allow_sspi: true,
127 channel_binding: ScramChannelBindingMode::Prefer,
128 }
129 }
130
131 pub(crate) fn has_any_password_method(self) -> bool {
132 self.allow_cleartext_password || self.allow_md5_password || self.allow_scram_sha_256
133 }
134}
135
136#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
138pub enum TlsMode {
139 #[default]
141 Disable,
142 Prefer,
144 Require,
146}
147
148impl TlsMode {
149 pub fn parse_sslmode(value: &str) -> Option<Self> {
151 match value.trim().to_ascii_lowercase().as_str() {
152 "disable" => Some(Self::Disable),
153 "allow" | "prefer" => Some(Self::Prefer),
154 "require" | "verify-ca" | "verify-full" => Some(Self::Require),
155 _ => None,
156 }
157 }
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
167pub enum GssEncMode {
168 #[default]
170 Disable,
171 Prefer,
173 Require,
175}
176
177impl GssEncMode {
178 pub fn parse_gssencmode(value: &str) -> Option<Self> {
180 match value.trim().to_ascii_lowercase().as_str() {
181 "disable" => Some(Self::Disable),
182 "prefer" => Some(Self::Prefer),
183 "require" => Some(Self::Require),
184 _ => None,
185 }
186 }
187}
188
189#[derive(Clone, Default)]
195pub struct ConnectOptions {
196 pub tls_mode: TlsMode,
198 pub gss_enc_mode: GssEncMode,
200 pub tls_ca_cert_pem: Option<Vec<u8>>,
202 pub mtls: Option<TlsConfig>,
204 pub gss_token_provider: Option<GssTokenProvider>,
206 pub gss_token_provider_ex: Option<GssTokenProviderEx>,
208 pub auth: AuthSettings,
210 pub startup_params: Vec<(String, String)>,
213}
214
215impl std::fmt::Debug for ConnectOptions {
216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 f.debug_struct("ConnectOptions")
218 .field("tls_mode", &self.tls_mode)
219 .field("gss_enc_mode", &self.gss_enc_mode)
220 .field(
221 "tls_ca_cert_pem",
222 &self.tls_ca_cert_pem.as_ref().map(std::vec::Vec::len),
223 )
224 .field("mtls", &self.mtls.as_ref().map(|_| "<configured>"))
225 .field(
226 "gss_token_provider",
227 &self.gss_token_provider.as_ref().map(|_| "<configured>"),
228 )
229 .field(
230 "gss_token_provider_ex",
231 &self.gss_token_provider_ex.as_ref().map(|_| "<configured>"),
232 )
233 .field("auth", &self.auth)
234 .field("startup_params_count", &self.startup_params.len())
235 .finish()
236 }
237}
238
239impl ConnectOptions {
240 pub fn with_startup_param(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
244 let key = key.into();
245 let value = value.into();
246 self.startup_params
247 .retain(|(existing, _)| !existing.eq_ignore_ascii_case(&key));
248 self.startup_params.push((key, value));
249 self
250 }
251
252 pub fn with_logical_replication(mut self) -> Self {
254 self.startup_params
255 .retain(|(k, _)| !k.eq_ignore_ascii_case("replication"));
256 self.startup_params
257 .push(("replication".to_string(), "database".to_string()));
258 self
259 }
260}