Skip to main content

slim_bindings/
common_config.rs

1// Copyright AGNTCY Contributors (https://github.com/agntcy)
2// SPDX-License-Identifier: Apache-2.0
3
4use slim_config::auth::basic::Config as BasicAuthConfig;
5use slim_config::tls::client::TlsClientConfig as CoreTlsClientConfig;
6use slim_config::tls::server::TlsServerConfig as CoreTlsServerConfig;
7
8use crate::identity_config::{ClientJwtAuth, JwtAuth, StaticJwtAuth};
9
10/// SPIRE configuration for SPIFFE Workload API integration
11#[derive(uniffi::Record, Clone, Debug, PartialEq)]
12pub struct SpireConfig {
13    /// Path to the SPIFFE Workload API socket (None => use SPIFFE_ENDPOINT_SOCKET env var)
14    pub socket_path: Option<String>,
15    /// Optional target SPIFFE ID when requesting JWT SVIDs
16    pub target_spiffe_id: Option<String>,
17    /// Audiences to request/verify for JWT SVIDs
18    pub jwt_audiences: Vec<String>,
19    /// Optional trust domains override for X.509 bundle retrieval
20    pub trust_domains: Vec<String>,
21}
22
23impl Default for SpireConfig {
24    fn default() -> Self {
25        SpireConfig {
26            socket_path: None,
27            target_spiffe_id: None,
28            jwt_audiences: vec!["slim".to_string()],
29            trust_domains: vec![],
30        }
31    }
32}
33
34#[cfg(not(target_family = "windows"))]
35impl From<SpireConfig> for slim_config::auth::spire::SpireConfig {
36    fn from(config: SpireConfig) -> Self {
37        slim_config::auth::spire::SpireConfig {
38            socket_path: config.socket_path,
39            target_spiffe_id: config.target_spiffe_id,
40            jwt_audiences: config.jwt_audiences,
41            trust_domains: config.trust_domains,
42        }
43    }
44}
45
46#[cfg(not(target_family = "windows"))]
47impl From<slim_config::auth::spire::SpireConfig> for SpireConfig {
48    fn from(config: slim_config::auth::spire::SpireConfig) -> Self {
49        SpireConfig {
50            socket_path: config.socket_path,
51            target_spiffe_id: config.target_spiffe_id,
52            jwt_audiences: config.jwt_audiences,
53            trust_domains: config.trust_domains,
54        }
55    }
56}
57
58/// TLS certificate and key source configuration
59#[derive(uniffi::Enum, Clone, Debug, PartialEq)]
60pub enum TlsSource {
61    /// Load certificate and key from PEM strings
62    Pem { cert: String, key: String },
63    /// Load certificate and key from files (with auto-reload support)
64    File { cert: String, key: String },
65    /// Load certificate and key from SPIRE Workload API
66    Spire { config: SpireConfig },
67    /// No certificate/key configured
68    None,
69}
70
71impl From<TlsSource> for slim_config::tls::common::TlsSource {
72    fn from(source: TlsSource) -> Self {
73        match source {
74            TlsSource::Pem { cert, key } => slim_config::tls::common::TlsSource::Pem { cert, key },
75            TlsSource::File { cert, key } => {
76                slim_config::tls::common::TlsSource::File { cert, key }
77            }
78            #[cfg(not(target_family = "windows"))]
79            TlsSource::Spire { config } => slim_config::tls::common::TlsSource::Spire {
80                config: config.into(),
81            },
82            #[cfg(target_family = "windows")]
83            TlsSource::Spire { .. } => {
84                panic!("SPIRE is not supported on Windows");
85            }
86            TlsSource::None => slim_config::tls::common::TlsSource::None,
87        }
88    }
89}
90
91impl From<slim_config::tls::common::TlsSource> for TlsSource {
92    fn from(source: slim_config::tls::common::TlsSource) -> Self {
93        match source {
94            slim_config::tls::common::TlsSource::Pem { cert, key } => TlsSource::Pem { cert, key },
95            slim_config::tls::common::TlsSource::File { cert, key } => {
96                TlsSource::File { cert, key }
97            }
98            #[cfg(not(target_family = "windows"))]
99            slim_config::tls::common::TlsSource::Spire { config } => TlsSource::Spire {
100                config: config.into(),
101            },
102            slim_config::tls::common::TlsSource::None => TlsSource::None,
103        }
104    }
105}
106
107/// CA certificate source configuration
108#[derive(uniffi::Enum, Clone, Debug, PartialEq)]
109pub enum CaSource {
110    /// Load CA from file
111    File { path: String },
112    /// Load CA from PEM string
113    Pem { data: String },
114    /// Load CA from SPIRE Workload API
115    Spire { config: SpireConfig },
116    /// No CA configured
117    None,
118}
119
120impl From<CaSource> for slim_config::tls::common::CaSource {
121    fn from(source: CaSource) -> Self {
122        match source {
123            CaSource::File { path } => slim_config::tls::common::CaSource::File { path },
124            CaSource::Pem { data } => slim_config::tls::common::CaSource::Pem { data },
125            #[cfg(not(target_family = "windows"))]
126            CaSource::Spire { config } => slim_config::tls::common::CaSource::Spire {
127                config: config.into(),
128            },
129            #[cfg(target_family = "windows")]
130            CaSource::Spire { .. } => {
131                panic!("SPIRE is not supported on Windows");
132            }
133            CaSource::None => slim_config::tls::common::CaSource::None,
134        }
135    }
136}
137
138impl From<slim_config::tls::common::CaSource> for CaSource {
139    fn from(source: slim_config::tls::common::CaSource) -> Self {
140        match source {
141            slim_config::tls::common::CaSource::File { path } => CaSource::File { path },
142            slim_config::tls::common::CaSource::Pem { data } => CaSource::Pem { data },
143            #[cfg(not(target_family = "windows"))]
144            slim_config::tls::common::CaSource::Spire { config } => CaSource::Spire {
145                config: config.into(),
146            },
147            slim_config::tls::common::CaSource::None => CaSource::None,
148        }
149    }
150}
151
152/// TLS configuration for client connections
153#[derive(uniffi::Record, Clone, Debug, PartialEq)]
154pub struct TlsClientConfig {
155    /// Disable TLS entirely (plain text connection)
156    pub insecure: bool,
157    /// Skip server certificate verification (enables TLS but doesn't verify certs)
158    /// WARNING: Only use for testing - insecure in production!
159    pub insecure_skip_verify: bool,
160    /// Certificate and key source for client authentication
161    pub source: TlsSource,
162    /// CA certificate source for verifying server certificates
163    pub ca_source: CaSource,
164    /// Include system CA certificates pool (default: true)
165    pub include_system_ca_certs_pool: bool,
166    /// TLS version to use: "tls1.2" or "tls1.3" (default: "tls1.3")
167    pub tls_version: String,
168}
169
170impl Default for TlsClientConfig {
171    fn default() -> Self {
172        let core_defaults = CoreTlsClientConfig::default();
173        TlsClientConfig {
174            insecure: core_defaults.insecure,
175            insecure_skip_verify: core_defaults.insecure_skip_verify,
176            source: core_defaults.config.source.into(),
177            ca_source: core_defaults.config.ca_source.into(),
178            include_system_ca_certs_pool: core_defaults.config.include_system_ca_certs_pool,
179            tls_version: core_defaults.config.tls_version,
180        }
181    }
182}
183
184impl From<TlsClientConfig> for CoreTlsClientConfig {
185    fn from(config: TlsClientConfig) -> Self {
186        CoreTlsClientConfig {
187            config: slim_config::tls::common::Config {
188                source: config.source.into(),
189                ca_source: config.ca_source.into(),
190                include_system_ca_certs_pool: config.include_system_ca_certs_pool,
191                tls_version: config.tls_version,
192                reload_interval: None,
193            },
194            insecure: config.insecure,
195            insecure_skip_verify: config.insecure_skip_verify,
196        }
197    }
198}
199
200impl From<CoreTlsClientConfig> for TlsClientConfig {
201    fn from(config: CoreTlsClientConfig) -> Self {
202        TlsClientConfig {
203            insecure: config.insecure,
204            insecure_skip_verify: config.insecure_skip_verify,
205            source: config.config.source.into(),
206            ca_source: config.config.ca_source.into(),
207            include_system_ca_certs_pool: config.config.include_system_ca_certs_pool,
208            tls_version: config.config.tls_version,
209        }
210    }
211}
212
213/// TLS configuration for server connections
214#[derive(uniffi::Record, Clone, Debug, PartialEq)]
215pub struct TlsServerConfig {
216    /// Disable TLS entirely (plain text connection)
217    pub insecure: bool,
218    /// Certificate and key source for server authentication
219    pub source: TlsSource,
220    /// CA certificate source for verifying client certificates
221    pub client_ca: CaSource,
222    /// Include system CA certificates pool (default: true)
223    pub include_system_ca_certs_pool: Option<bool>,
224    /// TLS version to use: "tls1.2" or "tls1.3" (default: "tls1.3")
225    pub tls_version: Option<String>,
226    /// Reload client CA file when modified
227    pub reload_client_ca_file: Option<bool>,
228}
229
230impl Default for TlsServerConfig {
231    fn default() -> Self {
232        TlsServerConfig {
233            insecure: false,
234            source: TlsSource::None,
235            client_ca: CaSource::None,
236            include_system_ca_certs_pool: None,
237            tls_version: None,
238            reload_client_ca_file: None,
239        }
240    }
241}
242
243impl From<TlsServerConfig> for CoreTlsServerConfig {
244    fn from(config: TlsServerConfig) -> Self {
245        let core_defaults = CoreTlsServerConfig::default();
246        CoreTlsServerConfig {
247            config: slim_config::tls::common::Config {
248                source: config.source.into(),
249                ca_source: slim_config::tls::common::CaSource::None,
250                include_system_ca_certs_pool: config
251                    .include_system_ca_certs_pool
252                    .unwrap_or(core_defaults.config.include_system_ca_certs_pool),
253                tls_version: config
254                    .tls_version
255                    .unwrap_or(core_defaults.config.tls_version),
256                reload_interval: None,
257            },
258            insecure: config.insecure,
259            client_ca: config.client_ca.into(),
260            reload_client_ca_file: config
261                .reload_client_ca_file
262                .unwrap_or(core_defaults.reload_client_ca_file),
263        }
264    }
265}
266
267impl From<CoreTlsServerConfig> for TlsServerConfig {
268    fn from(config: CoreTlsServerConfig) -> Self {
269        TlsServerConfig {
270            insecure: config.insecure,
271            source: config.config.source.into(),
272            client_ca: config.client_ca.into(),
273            include_system_ca_certs_pool: Some(config.config.include_system_ca_certs_pool),
274            tls_version: Some(config.config.tls_version),
275            reload_client_ca_file: Some(config.reload_client_ca_file),
276        }
277    }
278}
279
280/// Basic authentication configuration
281#[derive(uniffi::Record, Clone, Debug, PartialEq)]
282pub struct BasicAuth {
283    pub username: String,
284    pub password: String,
285}
286
287impl From<BasicAuth> for BasicAuthConfig {
288    fn from(config: BasicAuth) -> Self {
289        BasicAuthConfig::new(&config.username, &config.password)
290    }
291}
292
293impl From<BasicAuthConfig> for BasicAuth {
294    fn from(config: BasicAuthConfig) -> Self {
295        BasicAuth {
296            username: config.username().to_string(),
297            password: config.password().as_str().to_string(),
298        }
299    }
300}
301
302/// Authentication configuration enum for client
303#[derive(uniffi::Enum, Clone, Debug, PartialEq)]
304pub enum ClientAuthenticationConfig {
305    Basic {
306        config: BasicAuth,
307    },
308    StaticJwt {
309        config: StaticJwtAuth,
310    },
311    Jwt {
312        config: ClientJwtAuth,
313    },
314    /// SPIRE/SPIFFE authentication (non-Windows only)
315    #[cfg(not(target_family = "windows"))]
316    Spire {
317        config: SpireConfig,
318    },
319    None,
320}
321
322impl From<ClientAuthenticationConfig> for slim_config::grpc::client::AuthenticationConfig {
323    fn from(config: ClientAuthenticationConfig) -> Self {
324        match config {
325            ClientAuthenticationConfig::Basic { config } => {
326                slim_config::grpc::client::AuthenticationConfig::Basic(config.into())
327            }
328            ClientAuthenticationConfig::StaticJwt { config } => {
329                slim_config::grpc::client::AuthenticationConfig::StaticJwt(config.into())
330            }
331            ClientAuthenticationConfig::Jwt { config } => {
332                slim_config::grpc::client::AuthenticationConfig::Jwt(config.into())
333            }
334            #[cfg(not(target_family = "windows"))]
335            ClientAuthenticationConfig::Spire { config } => {
336                slim_config::grpc::client::AuthenticationConfig::Spire(config.into())
337            }
338            ClientAuthenticationConfig::None => {
339                slim_config::grpc::client::AuthenticationConfig::None
340            }
341        }
342    }
343}
344
345impl From<slim_config::grpc::client::AuthenticationConfig> for ClientAuthenticationConfig {
346    fn from(config: slim_config::grpc::client::AuthenticationConfig) -> Self {
347        match config {
348            slim_config::grpc::client::AuthenticationConfig::None => {
349                ClientAuthenticationConfig::None
350            }
351            slim_config::grpc::client::AuthenticationConfig::Basic(basic) => {
352                ClientAuthenticationConfig::Basic {
353                    config: basic.into(),
354                }
355            }
356            slim_config::grpc::client::AuthenticationConfig::StaticJwt(jwt) => {
357                ClientAuthenticationConfig::StaticJwt { config: jwt.into() }
358            }
359            slim_config::grpc::client::AuthenticationConfig::Jwt(jwt) => {
360                ClientAuthenticationConfig::Jwt { config: jwt.into() }
361            }
362            #[cfg(not(target_family = "windows"))]
363            slim_config::grpc::client::AuthenticationConfig::Spire(spire) => {
364                ClientAuthenticationConfig::Spire {
365                    config: spire.into(),
366                }
367            }
368        }
369    }
370}
371
372/// Authentication configuration enum for server
373#[derive(uniffi::Enum, Clone, Debug, PartialEq)]
374pub enum ServerAuthenticationConfig {
375    Basic {
376        config: BasicAuth,
377    },
378    Jwt {
379        config: JwtAuth,
380    },
381    /// SPIRE/SPIFFE authentication (non-Windows only)
382    #[cfg(not(target_family = "windows"))]
383    Spire {
384        config: SpireConfig,
385    },
386    None,
387}
388
389impl From<ServerAuthenticationConfig> for slim_config::grpc::server::AuthenticationConfig {
390    fn from(config: ServerAuthenticationConfig) -> Self {
391        match config {
392            ServerAuthenticationConfig::Basic { config } => {
393                slim_config::grpc::server::AuthenticationConfig::Basic(config.into())
394            }
395            ServerAuthenticationConfig::Jwt { config } => {
396                slim_config::grpc::server::AuthenticationConfig::Jwt(config.into())
397            }
398            #[cfg(not(target_family = "windows"))]
399            ServerAuthenticationConfig::Spire { config } => {
400                slim_config::grpc::server::AuthenticationConfig::Spire(config.into())
401            }
402            ServerAuthenticationConfig::None => {
403                slim_config::grpc::server::AuthenticationConfig::None
404            }
405        }
406    }
407}
408
409impl From<slim_config::grpc::server::AuthenticationConfig> for ServerAuthenticationConfig {
410    fn from(config: slim_config::grpc::server::AuthenticationConfig) -> Self {
411        match config {
412            slim_config::grpc::server::AuthenticationConfig::None => {
413                ServerAuthenticationConfig::None
414            }
415            slim_config::grpc::server::AuthenticationConfig::Basic(basic) => {
416                ServerAuthenticationConfig::Basic {
417                    config: basic.into(),
418                }
419            }
420            slim_config::grpc::server::AuthenticationConfig::Jwt(jwt) => {
421                ServerAuthenticationConfig::Jwt { config: jwt.into() }
422            }
423            #[cfg(not(target_family = "windows"))]
424            slim_config::grpc::server::AuthenticationConfig::Spire(spire) => {
425                ServerAuthenticationConfig::Spire {
426                    config: spire.into(),
427                }
428            }
429        }
430    }
431}
432
433#[cfg(test)]
434mod tests {
435    use super::*;
436    use crate::identity_config::{
437        JwtAlgorithm, JwtKeyConfig, JwtKeyData, JwtKeyFormat, JwtKeyType,
438    };
439    use std::time::Duration;
440
441    // Test SpireConfig default
442    #[test]
443    fn test_spire_config_default() {
444        let config = SpireConfig::default();
445        assert_eq!(config.socket_path, None);
446        assert_eq!(config.target_spiffe_id, None);
447        assert_eq!(config.jwt_audiences, vec!["slim".to_string()]);
448        assert_eq!(config.trust_domains, Vec::<String>::new());
449    }
450
451    // Test SpireConfig conversions (non-Windows only)
452    #[cfg(not(target_family = "windows"))]
453    #[test]
454    fn test_spire_config_conversions() {
455        let config = SpireConfig {
456            socket_path: Some("/var/run/spire/socket".to_string()),
457            target_spiffe_id: Some("spiffe://example.com/service".to_string()),
458            jwt_audiences: vec!["audience1".to_string(), "audience2".to_string()],
459            trust_domains: vec!["example.com".to_string()],
460        };
461
462        let core_config: slim_config::auth::spire::SpireConfig = config.clone().into();
463        assert_eq!(core_config.socket_path, config.socket_path);
464        assert_eq!(core_config.target_spiffe_id, config.target_spiffe_id);
465        assert_eq!(core_config.jwt_audiences, config.jwt_audiences);
466        assert_eq!(core_config.trust_domains, config.trust_domains);
467
468        let back: SpireConfig = core_config.into();
469        assert_eq!(back, config);
470    }
471
472    // Test TlsSource conversions - Pem variant
473    #[test]
474    fn test_tls_source_pem_conversion() {
475        let source = TlsSource::Pem {
476            cert: "-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----".to_string(),
477            key: "-----BEGIN PRIVATE KEY-----\ntest\n-----END PRIVATE KEY-----".to_string(),
478        };
479
480        let core_source: slim_config::tls::common::TlsSource = source.clone().into();
481        let back: TlsSource = core_source.into();
482        assert_eq!(back, source);
483    }
484
485    // Test TlsSource conversions - File variant
486    #[test]
487    fn test_tls_source_file_conversion() {
488        let source = TlsSource::File {
489            cert: "/path/to/cert.pem".to_string(),
490            key: "/path/to/key.pem".to_string(),
491        };
492
493        let core_source: slim_config::tls::common::TlsSource = source.clone().into();
494        let back: TlsSource = core_source.into();
495        assert_eq!(back, source);
496    }
497
498    // Test TlsSource conversions - None variant
499    #[test]
500    fn test_tls_source_none_conversion() {
501        let source = TlsSource::None;
502        let core_source: slim_config::tls::common::TlsSource = source.clone().into();
503        let back: TlsSource = core_source.into();
504        assert_eq!(back, source);
505    }
506
507    // Test TlsSource conversions - Spire variant (non-Windows only)
508    #[cfg(not(target_family = "windows"))]
509    #[test]
510    fn test_tls_source_spire_conversion() {
511        let source = TlsSource::Spire {
512            config: SpireConfig::default(),
513        };
514
515        let core_source: slim_config::tls::common::TlsSource = source.clone().into();
516        let back: TlsSource = core_source.into();
517        assert_eq!(back, source);
518    }
519
520    // Test CaSource conversions - File variant
521    #[test]
522    fn test_ca_source_file_conversion() {
523        let source = CaSource::File {
524            path: "/path/to/ca.pem".to_string(),
525        };
526
527        let core_source: slim_config::tls::common::CaSource = source.clone().into();
528        let back: CaSource = core_source.into();
529        assert_eq!(back, source);
530    }
531
532    // Test CaSource conversions - Pem variant
533    #[test]
534    fn test_ca_source_pem_conversion() {
535        let source = CaSource::Pem {
536            data: "-----BEGIN CERTIFICATE-----\nCA\n-----END CERTIFICATE-----".to_string(),
537        };
538
539        let core_source: slim_config::tls::common::CaSource = source.clone().into();
540        let back: CaSource = core_source.into();
541        assert_eq!(back, source);
542    }
543
544    // Test CaSource conversions - None variant
545    #[test]
546    fn test_ca_source_none_conversion() {
547        let source = CaSource::None;
548        let core_source: slim_config::tls::common::CaSource = source.clone().into();
549        let back: CaSource = core_source.into();
550        assert_eq!(back, source);
551    }
552
553    // Test CaSource conversions - Spire variant (non-Windows only)
554    #[cfg(not(target_family = "windows"))]
555    #[test]
556    fn test_ca_source_spire_conversion() {
557        let source = CaSource::Spire {
558            config: SpireConfig::default(),
559        };
560
561        let core_source: slim_config::tls::common::CaSource = source.clone().into();
562        let back: CaSource = core_source.into();
563        assert_eq!(back, source);
564    }
565
566    // Test TlsClientConfig default
567    #[test]
568    fn test_tls_client_config_default() {
569        let config = TlsClientConfig::default();
570        assert!(!config.insecure);
571        assert!(!config.insecure_skip_verify);
572        assert_eq!(config.source, TlsSource::None);
573        assert_eq!(config.ca_source, CaSource::None);
574        assert!(config.include_system_ca_certs_pool);
575        assert_eq!(config.tls_version, "tls1.3");
576    }
577
578    // Test TlsClientConfig conversions
579    #[test]
580    fn test_tls_client_config_conversion() {
581        let config = TlsClientConfig {
582            insecure: false,
583            insecure_skip_verify: false,
584            source: TlsSource::File {
585                cert: "/path/to/cert.pem".to_string(),
586                key: "/path/to/key.pem".to_string(),
587            },
588            ca_source: CaSource::File {
589                path: "/path/to/ca.pem".to_string(),
590            },
591            include_system_ca_certs_pool: true,
592            tls_version: "tls1.3".to_string(),
593        };
594
595        let core_config: CoreTlsClientConfig = config.clone().into();
596        assert_eq!(core_config.insecure, config.insecure);
597        assert_eq!(
598            core_config.insecure_skip_verify,
599            config.insecure_skip_verify
600        );
601        assert_eq!(
602            core_config.config.include_system_ca_certs_pool,
603            config.include_system_ca_certs_pool
604        );
605        assert_eq!(core_config.config.tls_version, config.tls_version);
606
607        let back: TlsClientConfig = core_config.into();
608        assert_eq!(back, config);
609    }
610
611    // Test TlsClientConfig with insecure options
612    #[test]
613    fn test_tls_client_config_insecure() {
614        let config = TlsClientConfig {
615            insecure: true,
616            insecure_skip_verify: true,
617            source: TlsSource::None,
618            ca_source: CaSource::None,
619            include_system_ca_certs_pool: false,
620            tls_version: "tls1.2".to_string(),
621        };
622
623        let core_config: CoreTlsClientConfig = config.clone().into();
624        let back: TlsClientConfig = core_config.into();
625        assert!(back.insecure);
626        assert!(back.insecure_skip_verify);
627        assert!(!back.include_system_ca_certs_pool);
628        assert_eq!(back.tls_version, "tls1.2");
629    }
630
631    // Test TlsServerConfig default
632    #[test]
633    fn test_tls_server_config_default() {
634        let config = TlsServerConfig::default();
635        assert!(!config.insecure);
636        assert_eq!(config.source, TlsSource::None);
637        assert_eq!(config.client_ca, CaSource::None);
638        assert_eq!(config.include_system_ca_certs_pool, None);
639        assert_eq!(config.tls_version, None);
640        assert_eq!(config.reload_client_ca_file, None);
641
642        // Verify core defaults are applied when converting
643        let core: CoreTlsServerConfig = config.into();
644        assert!(core.config.include_system_ca_certs_pool);
645        assert_eq!(core.config.tls_version, "tls1.3");
646        assert!(!core.reload_client_ca_file);
647    }
648
649    // Test TlsServerConfig conversions
650    #[test]
651    fn test_tls_server_config_conversion() {
652        let config = TlsServerConfig {
653            insecure: false,
654            source: TlsSource::Pem {
655                cert: "cert-data".to_string(),
656                key: "key-data".to_string(),
657            },
658            client_ca: CaSource::Pem {
659                data: "ca-data".to_string(),
660            },
661            include_system_ca_certs_pool: Some(true),
662            tls_version: Some("tls1.3".to_string()),
663            reload_client_ca_file: Some(true),
664        };
665
666        let core_config: CoreTlsServerConfig = config.clone().into();
667        assert_eq!(core_config.insecure, config.insecure);
668        assert_eq!(
669            core_config.reload_client_ca_file,
670            config.reload_client_ca_file.unwrap()
671        );
672        assert_eq!(
673            core_config.config.include_system_ca_certs_pool,
674            config.include_system_ca_certs_pool.unwrap()
675        );
676        assert_eq!(
677            core_config.config.tls_version,
678            config.tls_version.clone().unwrap()
679        );
680
681        let back: TlsServerConfig = core_config.into();
682        assert_eq!(back, config);
683    }
684
685    // Test BasicAuth conversions
686    #[test]
687    fn test_basic_auth_conversion() {
688        let auth = BasicAuth {
689            username: "testuser".to_string(),
690            password: "testpassword".to_string(),
691        };
692
693        let core_auth: BasicAuthConfig = auth.clone().into();
694        assert_eq!(core_auth.username(), "testuser");
695        assert_eq!(core_auth.password().as_str(), "testpassword");
696
697        let back: BasicAuth = core_auth.into();
698        assert_eq!(back, auth);
699    }
700
701    // Test ClientAuthenticationConfig - Basic variant
702    #[test]
703    fn test_client_auth_config_basic() {
704        let config = ClientAuthenticationConfig::Basic {
705            config: BasicAuth {
706                username: "user".to_string(),
707                password: "pass".to_string(),
708            },
709        };
710
711        let core_config: slim_config::grpc::client::AuthenticationConfig = config.clone().into();
712        let back: ClientAuthenticationConfig = core_config.into();
713        assert_eq!(back, config);
714    }
715
716    // Test ClientAuthenticationConfig - StaticJwt variant
717    #[test]
718    fn test_client_auth_config_static_jwt() {
719        let config = ClientAuthenticationConfig::StaticJwt {
720            config: StaticJwtAuth {
721                token_file: "/path/to/token.jwt".to_string(),
722                duration: Duration::from_secs(3600),
723            },
724        };
725
726        let core_config: slim_config::grpc::client::AuthenticationConfig = config.clone().into();
727        let back: ClientAuthenticationConfig = core_config.into();
728        assert_eq!(back, config);
729    }
730
731    // Test ClientAuthenticationConfig - Jwt variant
732    #[test]
733    fn test_client_auth_config_jwt() {
734        let config = ClientAuthenticationConfig::Jwt {
735            config: ClientJwtAuth {
736                key: JwtKeyType::Autoresolve,
737                audience: Some(vec!["api".to_string()]),
738                issuer: None,
739                subject: None,
740                duration: Duration::from_secs(3600),
741            },
742        };
743
744        let core_config: slim_config::grpc::client::AuthenticationConfig = config.clone().into();
745        let back: ClientAuthenticationConfig = core_config.into();
746        assert_eq!(back, config);
747    }
748
749    // Test ClientAuthenticationConfig - None variant
750    #[test]
751    fn test_client_auth_config_none() {
752        let config = ClientAuthenticationConfig::None;
753        let core_config: slim_config::grpc::client::AuthenticationConfig = config.clone().into();
754        let back: ClientAuthenticationConfig = core_config.into();
755        assert_eq!(back, config);
756    }
757
758    // Test ServerAuthenticationConfig - Basic variant
759    #[test]
760    fn test_server_auth_config_basic() {
761        let config = ServerAuthenticationConfig::Basic {
762            config: BasicAuth {
763                username: "admin".to_string(),
764                password: "secret".to_string(),
765            },
766        };
767
768        let core_config: slim_config::grpc::server::AuthenticationConfig = config.clone().into();
769        let back: ServerAuthenticationConfig = core_config.into();
770        assert_eq!(back, config);
771    }
772
773    // Test ServerAuthenticationConfig - Jwt variant
774    #[test]
775    fn test_server_auth_config_jwt() {
776        let config = ServerAuthenticationConfig::Jwt {
777            config: JwtAuth {
778                key: JwtKeyType::Decoding {
779                    key: JwtKeyConfig {
780                        algorithm: JwtAlgorithm::RS256,
781                        format: JwtKeyFormat::Pem,
782                        key: JwtKeyData::File {
783                            path: "/path/to/key.pem".to_string(),
784                        },
785                    },
786                },
787                audience: Some(vec!["service".to_string()]),
788                issuer: Some("issuer".to_string()),
789                subject: None,
790                duration: Duration::from_secs(7200),
791            },
792        };
793
794        let core_config: slim_config::grpc::server::AuthenticationConfig = config.clone().into();
795        let back: ServerAuthenticationConfig = core_config.into();
796        assert_eq!(back, config);
797    }
798
799    // Test ServerAuthenticationConfig - None variant
800    #[test]
801    fn test_server_auth_config_none() {
802        let config = ServerAuthenticationConfig::None;
803        let core_config: slim_config::grpc::server::AuthenticationConfig = config.clone().into();
804        let back: ServerAuthenticationConfig = core_config.into();
805        assert_eq!(back, config);
806    }
807
808    // Test complex TlsClientConfig with all options
809    #[test]
810    fn test_complex_tls_client_config() {
811        let config = TlsClientConfig {
812            insecure: false,
813            insecure_skip_verify: false,
814            source: TlsSource::Pem {
815                cert: "-----BEGIN CERTIFICATE-----\ncert\n-----END CERTIFICATE-----".to_string(),
816                key: "-----BEGIN PRIVATE KEY-----\nkey\n-----END PRIVATE KEY-----".to_string(),
817            },
818            ca_source: CaSource::Pem {
819                data: "-----BEGIN CERTIFICATE-----\nCA\n-----END CERTIFICATE-----".to_string(),
820            },
821            include_system_ca_certs_pool: false,
822            tls_version: "tls1.2".to_string(),
823        };
824
825        let core_config: CoreTlsClientConfig = config.clone().into();
826        let back: TlsClientConfig = core_config.into();
827        assert_eq!(back, config);
828    }
829
830    // Test complex TlsServerConfig with all options
831    #[test]
832    fn test_complex_tls_server_config() {
833        let config = TlsServerConfig {
834            insecure: false,
835            source: TlsSource::File {
836                cert: "/etc/tls/server.crt".to_string(),
837                key: "/etc/tls/server.key".to_string(),
838            },
839            client_ca: CaSource::File {
840                path: "/etc/tls/ca.crt".to_string(),
841            },
842            include_system_ca_certs_pool: Some(false),
843            tls_version: Some("tls1.2".to_string()),
844            reload_client_ca_file: Some(true),
845        };
846
847        let core_config: CoreTlsServerConfig = config.clone().into();
848        let back: TlsServerConfig = core_config.into();
849        assert_eq!(back, config);
850    }
851
852    // Test all TlsSource variants
853    #[test]
854    fn test_all_tls_source_variants() {
855        let variants = vec![
856            TlsSource::Pem {
857                cert: "cert1".to_string(),
858                key: "key1".to_string(),
859            },
860            TlsSource::File {
861                cert: "/path1".to_string(),
862                key: "/path2".to_string(),
863            },
864            TlsSource::None,
865        ];
866
867        for variant in variants {
868            let core: slim_config::tls::common::TlsSource = variant.clone().into();
869            let back: TlsSource = core.into();
870            assert_eq!(back, variant);
871        }
872    }
873
874    // Test all CaSource variants
875    #[test]
876    fn test_all_ca_source_variants() {
877        let variants = vec![
878            CaSource::File {
879                path: "/ca/path".to_string(),
880            },
881            CaSource::Pem {
882                data: "ca-pem-data".to_string(),
883            },
884            CaSource::None,
885        ];
886
887        for variant in variants {
888            let core: slim_config::tls::common::CaSource = variant.clone().into();
889            let back: CaSource = core.into();
890            assert_eq!(back, variant);
891        }
892    }
893
894    // Test SpireConfig with minimal configuration
895    #[test]
896    fn test_spire_config_minimal() {
897        let config = SpireConfig {
898            socket_path: None,
899            target_spiffe_id: None,
900            jwt_audiences: vec![],
901            trust_domains: vec![],
902        };
903
904        assert_eq!(config.socket_path, None);
905        assert_eq!(config.target_spiffe_id, None);
906        assert!(config.jwt_audiences.is_empty());
907        assert!(config.trust_domains.is_empty());
908    }
909
910    // Test SpireConfig with full configuration
911    #[test]
912    fn test_spire_config_full() {
913        let config = SpireConfig {
914            socket_path: Some("/var/run/spire.sock".to_string()),
915            target_spiffe_id: Some("spiffe://example.com/workload".to_string()),
916            jwt_audiences: vec!["aud1".to_string(), "aud2".to_string(), "aud3".to_string()],
917            trust_domains: vec!["domain1.com".to_string(), "domain2.com".to_string()],
918        };
919
920        assert_eq!(config.socket_path, Some("/var/run/spire.sock".to_string()));
921        assert_eq!(
922            config.target_spiffe_id,
923            Some("spiffe://example.com/workload".to_string())
924        );
925        assert_eq!(config.jwt_audiences.len(), 3);
926        assert_eq!(config.trust_domains.len(), 2);
927    }
928}