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                enforce_pqc: false,
194            },
195            insecure: config.insecure,
196            insecure_skip_verify: config.insecure_skip_verify,
197        }
198    }
199}
200
201impl From<CoreTlsClientConfig> for TlsClientConfig {
202    fn from(config: CoreTlsClientConfig) -> Self {
203        TlsClientConfig {
204            insecure: config.insecure,
205            insecure_skip_verify: config.insecure_skip_verify,
206            source: config.config.source.into(),
207            ca_source: config.config.ca_source.into(),
208            include_system_ca_certs_pool: config.config.include_system_ca_certs_pool,
209            tls_version: config.config.tls_version,
210        }
211    }
212}
213
214/// TLS configuration for server connections
215#[derive(uniffi::Record, Clone, Debug, PartialEq)]
216pub struct TlsServerConfig {
217    /// Disable TLS entirely (plain text connection)
218    pub insecure: bool,
219    /// Certificate and key source for server authentication
220    pub source: TlsSource,
221    /// CA certificate source for verifying client certificates
222    pub client_ca: CaSource,
223    /// Include system CA certificates pool (default: true)
224    pub include_system_ca_certs_pool: Option<bool>,
225    /// TLS version to use: "tls1.2" or "tls1.3" (default: "tls1.3")
226    pub tls_version: Option<String>,
227    /// Reload client CA file when modified
228    pub reload_client_ca_file: Option<bool>,
229}
230
231impl Default for TlsServerConfig {
232    fn default() -> Self {
233        TlsServerConfig {
234            insecure: false,
235            source: TlsSource::None,
236            client_ca: CaSource::None,
237            include_system_ca_certs_pool: None,
238            tls_version: None,
239            reload_client_ca_file: None,
240        }
241    }
242}
243
244impl From<TlsServerConfig> for CoreTlsServerConfig {
245    fn from(config: TlsServerConfig) -> Self {
246        let core_defaults = CoreTlsServerConfig::default();
247        CoreTlsServerConfig {
248            config: slim_config::tls::common::Config {
249                source: config.source.into(),
250                ca_source: slim_config::tls::common::CaSource::None,
251                include_system_ca_certs_pool: config
252                    .include_system_ca_certs_pool
253                    .unwrap_or(core_defaults.config.include_system_ca_certs_pool),
254                tls_version: config
255                    .tls_version
256                    .unwrap_or(core_defaults.config.tls_version),
257                reload_interval: None,
258                enforce_pqc: false,
259            },
260            insecure: config.insecure,
261            client_ca: config.client_ca.into(),
262            reload_client_ca_file: config
263                .reload_client_ca_file
264                .unwrap_or(core_defaults.reload_client_ca_file),
265        }
266    }
267}
268
269impl From<CoreTlsServerConfig> for TlsServerConfig {
270    fn from(config: CoreTlsServerConfig) -> Self {
271        TlsServerConfig {
272            insecure: config.insecure,
273            source: config.config.source.into(),
274            client_ca: config.client_ca.into(),
275            include_system_ca_certs_pool: Some(config.config.include_system_ca_certs_pool),
276            tls_version: Some(config.config.tls_version),
277            reload_client_ca_file: Some(config.reload_client_ca_file),
278        }
279    }
280}
281
282/// Basic authentication configuration
283#[derive(uniffi::Record, Clone, Debug, PartialEq)]
284pub struct BasicAuth {
285    pub username: String,
286    pub password: String,
287}
288
289impl From<BasicAuth> for BasicAuthConfig {
290    fn from(config: BasicAuth) -> Self {
291        BasicAuthConfig::new(&config.username, &config.password)
292    }
293}
294
295impl From<BasicAuthConfig> for BasicAuth {
296    fn from(config: BasicAuthConfig) -> Self {
297        BasicAuth {
298            username: config.username().to_string(),
299            password: config.password().as_str().to_string(),
300        }
301    }
302}
303
304/// Authentication configuration enum for client
305#[derive(uniffi::Enum, Clone, Debug, PartialEq)]
306pub enum ClientAuthenticationConfig {
307    Basic {
308        config: BasicAuth,
309    },
310    StaticJwt {
311        config: StaticJwtAuth,
312    },
313    Jwt {
314        config: ClientJwtAuth,
315    },
316    /// SPIRE/SPIFFE authentication (non-Windows only)
317    #[cfg(not(target_family = "windows"))]
318    Spire {
319        config: SpireConfig,
320    },
321    None,
322}
323
324impl From<ClientAuthenticationConfig> for slim_config::grpc::client::AuthenticationConfig {
325    fn from(config: ClientAuthenticationConfig) -> Self {
326        match config {
327            ClientAuthenticationConfig::Basic { config } => {
328                slim_config::grpc::client::AuthenticationConfig::Basic(config.into())
329            }
330            ClientAuthenticationConfig::StaticJwt { config } => {
331                slim_config::grpc::client::AuthenticationConfig::StaticJwt(config.into())
332            }
333            ClientAuthenticationConfig::Jwt { config } => {
334                slim_config::grpc::client::AuthenticationConfig::Jwt(config.into())
335            }
336            #[cfg(not(target_family = "windows"))]
337            ClientAuthenticationConfig::Spire { config } => {
338                slim_config::grpc::client::AuthenticationConfig::Spire(config.into())
339            }
340            ClientAuthenticationConfig::None => {
341                slim_config::grpc::client::AuthenticationConfig::None
342            }
343        }
344    }
345}
346
347impl From<slim_config::grpc::client::AuthenticationConfig> for ClientAuthenticationConfig {
348    fn from(config: slim_config::grpc::client::AuthenticationConfig) -> Self {
349        match config {
350            slim_config::grpc::client::AuthenticationConfig::None => {
351                ClientAuthenticationConfig::None
352            }
353            slim_config::grpc::client::AuthenticationConfig::Basic(basic) => {
354                ClientAuthenticationConfig::Basic {
355                    config: basic.into(),
356                }
357            }
358            slim_config::grpc::client::AuthenticationConfig::StaticJwt(jwt) => {
359                ClientAuthenticationConfig::StaticJwt { config: jwt.into() }
360            }
361            slim_config::grpc::client::AuthenticationConfig::Jwt(jwt) => {
362                ClientAuthenticationConfig::Jwt { config: jwt.into() }
363            }
364            #[cfg(not(target_family = "windows"))]
365            slim_config::grpc::client::AuthenticationConfig::Spire(spire) => {
366                ClientAuthenticationConfig::Spire {
367                    config: spire.into(),
368                }
369            }
370        }
371    }
372}
373
374/// Authentication configuration enum for server
375#[derive(uniffi::Enum, Clone, Debug, PartialEq)]
376pub enum ServerAuthenticationConfig {
377    Basic {
378        config: BasicAuth,
379    },
380    Jwt {
381        config: JwtAuth,
382    },
383    /// SPIRE/SPIFFE authentication (non-Windows only)
384    #[cfg(not(target_family = "windows"))]
385    Spire {
386        config: SpireConfig,
387    },
388    None,
389}
390
391impl From<ServerAuthenticationConfig> for slim_config::grpc::server::AuthenticationConfig {
392    fn from(config: ServerAuthenticationConfig) -> Self {
393        match config {
394            ServerAuthenticationConfig::Basic { config } => {
395                slim_config::grpc::server::AuthenticationConfig::Basic(config.into())
396            }
397            ServerAuthenticationConfig::Jwt { config } => {
398                slim_config::grpc::server::AuthenticationConfig::Jwt(config.into())
399            }
400            #[cfg(not(target_family = "windows"))]
401            ServerAuthenticationConfig::Spire { config } => {
402                slim_config::grpc::server::AuthenticationConfig::Spire(config.into())
403            }
404            ServerAuthenticationConfig::None => {
405                slim_config::grpc::server::AuthenticationConfig::None
406            }
407        }
408    }
409}
410
411impl From<slim_config::grpc::server::AuthenticationConfig> for ServerAuthenticationConfig {
412    fn from(config: slim_config::grpc::server::AuthenticationConfig) -> Self {
413        match config {
414            slim_config::grpc::server::AuthenticationConfig::None => {
415                ServerAuthenticationConfig::None
416            }
417            slim_config::grpc::server::AuthenticationConfig::Basic(basic) => {
418                ServerAuthenticationConfig::Basic {
419                    config: basic.into(),
420                }
421            }
422            slim_config::grpc::server::AuthenticationConfig::Jwt(jwt) => {
423                ServerAuthenticationConfig::Jwt { config: jwt.into() }
424            }
425            #[cfg(not(target_family = "windows"))]
426            slim_config::grpc::server::AuthenticationConfig::Spire(spire) => {
427                ServerAuthenticationConfig::Spire {
428                    config: spire.into(),
429                }
430            }
431        }
432    }
433}
434
435#[cfg(test)]
436mod tests {
437    use super::*;
438    use crate::identity_config::{
439        JwtAlgorithm, JwtKeyConfig, JwtKeyData, JwtKeyFormat, JwtKeyType,
440    };
441    use std::time::Duration;
442
443    // Test SpireConfig default
444    #[test]
445    fn test_spire_config_default() {
446        let config = SpireConfig::default();
447        assert_eq!(config.socket_path, None);
448        assert_eq!(config.target_spiffe_id, None);
449        assert_eq!(config.jwt_audiences, vec!["slim".to_string()]);
450        assert_eq!(config.trust_domains, Vec::<String>::new());
451    }
452
453    // Test SpireConfig conversions (non-Windows only)
454    #[cfg(not(target_family = "windows"))]
455    #[test]
456    fn test_spire_config_conversions() {
457        let config = SpireConfig {
458            socket_path: Some("/var/run/spire/socket".to_string()),
459            target_spiffe_id: Some("spiffe://example.com/service".to_string()),
460            jwt_audiences: vec!["audience1".to_string(), "audience2".to_string()],
461            trust_domains: vec!["example.com".to_string()],
462        };
463
464        let core_config: slim_config::auth::spire::SpireConfig = config.clone().into();
465        assert_eq!(core_config.socket_path, config.socket_path);
466        assert_eq!(core_config.target_spiffe_id, config.target_spiffe_id);
467        assert_eq!(core_config.jwt_audiences, config.jwt_audiences);
468        assert_eq!(core_config.trust_domains, config.trust_domains);
469
470        let back: SpireConfig = core_config.into();
471        assert_eq!(back, config);
472    }
473
474    // Test TlsSource conversions - Pem variant
475    #[test]
476    fn test_tls_source_pem_conversion() {
477        let source = TlsSource::Pem {
478            cert: "-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----".to_string(),
479            key: "-----BEGIN PRIVATE KEY-----\ntest\n-----END PRIVATE KEY-----".to_string(),
480        };
481
482        let core_source: slim_config::tls::common::TlsSource = source.clone().into();
483        let back: TlsSource = core_source.into();
484        assert_eq!(back, source);
485    }
486
487    // Test TlsSource conversions - File variant
488    #[test]
489    fn test_tls_source_file_conversion() {
490        let source = TlsSource::File {
491            cert: "/path/to/cert.pem".to_string(),
492            key: "/path/to/key.pem".to_string(),
493        };
494
495        let core_source: slim_config::tls::common::TlsSource = source.clone().into();
496        let back: TlsSource = core_source.into();
497        assert_eq!(back, source);
498    }
499
500    // Test TlsSource conversions - None variant
501    #[test]
502    fn test_tls_source_none_conversion() {
503        let source = TlsSource::None;
504        let core_source: slim_config::tls::common::TlsSource = source.clone().into();
505        let back: TlsSource = core_source.into();
506        assert_eq!(back, source);
507    }
508
509    // Test TlsSource conversions - Spire variant (non-Windows only)
510    #[cfg(not(target_family = "windows"))]
511    #[test]
512    fn test_tls_source_spire_conversion() {
513        let source = TlsSource::Spire {
514            config: SpireConfig::default(),
515        };
516
517        let core_source: slim_config::tls::common::TlsSource = source.clone().into();
518        let back: TlsSource = core_source.into();
519        assert_eq!(back, source);
520    }
521
522    // Test CaSource conversions - File variant
523    #[test]
524    fn test_ca_source_file_conversion() {
525        let source = CaSource::File {
526            path: "/path/to/ca.pem".to_string(),
527        };
528
529        let core_source: slim_config::tls::common::CaSource = source.clone().into();
530        let back: CaSource = core_source.into();
531        assert_eq!(back, source);
532    }
533
534    // Test CaSource conversions - Pem variant
535    #[test]
536    fn test_ca_source_pem_conversion() {
537        let source = CaSource::Pem {
538            data: "-----BEGIN CERTIFICATE-----\nCA\n-----END CERTIFICATE-----".to_string(),
539        };
540
541        let core_source: slim_config::tls::common::CaSource = source.clone().into();
542        let back: CaSource = core_source.into();
543        assert_eq!(back, source);
544    }
545
546    // Test CaSource conversions - None variant
547    #[test]
548    fn test_ca_source_none_conversion() {
549        let source = CaSource::None;
550        let core_source: slim_config::tls::common::CaSource = source.clone().into();
551        let back: CaSource = core_source.into();
552        assert_eq!(back, source);
553    }
554
555    // Test CaSource conversions - Spire variant (non-Windows only)
556    #[cfg(not(target_family = "windows"))]
557    #[test]
558    fn test_ca_source_spire_conversion() {
559        let source = CaSource::Spire {
560            config: SpireConfig::default(),
561        };
562
563        let core_source: slim_config::tls::common::CaSource = source.clone().into();
564        let back: CaSource = core_source.into();
565        assert_eq!(back, source);
566    }
567
568    // Test TlsClientConfig default
569    #[test]
570    fn test_tls_client_config_default() {
571        let config = TlsClientConfig::default();
572        assert!(!config.insecure);
573        assert!(!config.insecure_skip_verify);
574        assert_eq!(config.source, TlsSource::None);
575        assert_eq!(config.ca_source, CaSource::None);
576        assert!(config.include_system_ca_certs_pool);
577        assert_eq!(config.tls_version, "tls1.3");
578    }
579
580    // Test TlsClientConfig conversions
581    #[test]
582    fn test_tls_client_config_conversion() {
583        let config = TlsClientConfig {
584            insecure: false,
585            insecure_skip_verify: false,
586            source: TlsSource::File {
587                cert: "/path/to/cert.pem".to_string(),
588                key: "/path/to/key.pem".to_string(),
589            },
590            ca_source: CaSource::File {
591                path: "/path/to/ca.pem".to_string(),
592            },
593            include_system_ca_certs_pool: true,
594            tls_version: "tls1.3".to_string(),
595        };
596
597        let core_config: CoreTlsClientConfig = config.clone().into();
598        assert_eq!(core_config.insecure, config.insecure);
599        assert_eq!(
600            core_config.insecure_skip_verify,
601            config.insecure_skip_verify
602        );
603        assert_eq!(
604            core_config.config.include_system_ca_certs_pool,
605            config.include_system_ca_certs_pool
606        );
607        assert_eq!(core_config.config.tls_version, config.tls_version);
608
609        let back: TlsClientConfig = core_config.into();
610        assert_eq!(back, config);
611    }
612
613    // Test TlsClientConfig with insecure options
614    #[test]
615    fn test_tls_client_config_insecure() {
616        let config = TlsClientConfig {
617            insecure: true,
618            insecure_skip_verify: true,
619            source: TlsSource::None,
620            ca_source: CaSource::None,
621            include_system_ca_certs_pool: false,
622            tls_version: "tls1.2".to_string(),
623        };
624
625        let core_config: CoreTlsClientConfig = config.clone().into();
626        let back: TlsClientConfig = core_config.into();
627        assert!(back.insecure);
628        assert!(back.insecure_skip_verify);
629        assert!(!back.include_system_ca_certs_pool);
630        assert_eq!(back.tls_version, "tls1.2");
631    }
632
633    // Test TlsServerConfig default
634    #[test]
635    fn test_tls_server_config_default() {
636        let config = TlsServerConfig::default();
637        assert!(!config.insecure);
638        assert_eq!(config.source, TlsSource::None);
639        assert_eq!(config.client_ca, CaSource::None);
640        assert_eq!(config.include_system_ca_certs_pool, None);
641        assert_eq!(config.tls_version, None);
642        assert_eq!(config.reload_client_ca_file, None);
643
644        // Verify core defaults are applied when converting
645        let core: CoreTlsServerConfig = config.into();
646        assert!(core.config.include_system_ca_certs_pool);
647        assert_eq!(core.config.tls_version, "tls1.3");
648        assert!(!core.reload_client_ca_file);
649    }
650
651    // Test TlsServerConfig conversions
652    #[test]
653    fn test_tls_server_config_conversion() {
654        let config = TlsServerConfig {
655            insecure: false,
656            source: TlsSource::Pem {
657                cert: "cert-data".to_string(),
658                key: "key-data".to_string(),
659            },
660            client_ca: CaSource::Pem {
661                data: "ca-data".to_string(),
662            },
663            include_system_ca_certs_pool: Some(true),
664            tls_version: Some("tls1.3".to_string()),
665            reload_client_ca_file: Some(true),
666        };
667
668        let core_config: CoreTlsServerConfig = config.clone().into();
669        assert_eq!(core_config.insecure, config.insecure);
670        assert_eq!(
671            core_config.reload_client_ca_file,
672            config.reload_client_ca_file.unwrap()
673        );
674        assert_eq!(
675            core_config.config.include_system_ca_certs_pool,
676            config.include_system_ca_certs_pool.unwrap()
677        );
678        assert_eq!(
679            core_config.config.tls_version,
680            config.tls_version.clone().unwrap()
681        );
682
683        let back: TlsServerConfig = core_config.into();
684        assert_eq!(back, config);
685    }
686
687    // Test BasicAuth conversions
688    #[test]
689    fn test_basic_auth_conversion() {
690        let auth = BasicAuth {
691            username: "testuser".to_string(),
692            password: "testpassword".to_string(),
693        };
694
695        let core_auth: BasicAuthConfig = auth.clone().into();
696        assert_eq!(core_auth.username(), "testuser");
697        assert_eq!(core_auth.password().as_str(), "testpassword");
698
699        let back: BasicAuth = core_auth.into();
700        assert_eq!(back, auth);
701    }
702
703    // Test ClientAuthenticationConfig - Basic variant
704    #[test]
705    fn test_client_auth_config_basic() {
706        let config = ClientAuthenticationConfig::Basic {
707            config: BasicAuth {
708                username: "user".to_string(),
709                password: "pass".to_string(),
710            },
711        };
712
713        let core_config: slim_config::grpc::client::AuthenticationConfig = config.clone().into();
714        let back: ClientAuthenticationConfig = core_config.into();
715        assert_eq!(back, config);
716    }
717
718    // Test ClientAuthenticationConfig - StaticJwt variant
719    #[test]
720    fn test_client_auth_config_static_jwt() {
721        let config = ClientAuthenticationConfig::StaticJwt {
722            config: StaticJwtAuth {
723                token_file: "/path/to/token.jwt".to_string(),
724                duration: Duration::from_secs(3600),
725            },
726        };
727
728        let core_config: slim_config::grpc::client::AuthenticationConfig = config.clone().into();
729        let back: ClientAuthenticationConfig = core_config.into();
730        assert_eq!(back, config);
731    }
732
733    // Test ClientAuthenticationConfig - Jwt variant
734    #[test]
735    fn test_client_auth_config_jwt() {
736        let config = ClientAuthenticationConfig::Jwt {
737            config: ClientJwtAuth {
738                key: JwtKeyType::Autoresolve,
739                audience: Some(vec!["api".to_string()]),
740                issuer: None,
741                subject: None,
742                duration: Duration::from_secs(3600),
743            },
744        };
745
746        let core_config: slim_config::grpc::client::AuthenticationConfig = config.clone().into();
747        let back: ClientAuthenticationConfig = core_config.into();
748        assert_eq!(back, config);
749    }
750
751    // Test ClientAuthenticationConfig - None variant
752    #[test]
753    fn test_client_auth_config_none() {
754        let config = ClientAuthenticationConfig::None;
755        let core_config: slim_config::grpc::client::AuthenticationConfig = config.clone().into();
756        let back: ClientAuthenticationConfig = core_config.into();
757        assert_eq!(back, config);
758    }
759
760    // Test ServerAuthenticationConfig - Basic variant
761    #[test]
762    fn test_server_auth_config_basic() {
763        let config = ServerAuthenticationConfig::Basic {
764            config: BasicAuth {
765                username: "admin".to_string(),
766                password: "secret".to_string(),
767            },
768        };
769
770        let core_config: slim_config::grpc::server::AuthenticationConfig = config.clone().into();
771        let back: ServerAuthenticationConfig = core_config.into();
772        assert_eq!(back, config);
773    }
774
775    // Test ServerAuthenticationConfig - Jwt variant
776    #[test]
777    fn test_server_auth_config_jwt() {
778        let config = ServerAuthenticationConfig::Jwt {
779            config: JwtAuth {
780                key: JwtKeyType::Decoding {
781                    key: JwtKeyConfig {
782                        algorithm: JwtAlgorithm::RS256,
783                        format: JwtKeyFormat::Pem,
784                        key: JwtKeyData::File {
785                            path: "/path/to/key.pem".to_string(),
786                        },
787                    },
788                },
789                audience: Some(vec!["service".to_string()]),
790                issuer: Some("issuer".to_string()),
791                subject: None,
792                duration: Duration::from_secs(7200),
793            },
794        };
795
796        let core_config: slim_config::grpc::server::AuthenticationConfig = config.clone().into();
797        let back: ServerAuthenticationConfig = core_config.into();
798        assert_eq!(back, config);
799    }
800
801    // Test ServerAuthenticationConfig - None variant
802    #[test]
803    fn test_server_auth_config_none() {
804        let config = ServerAuthenticationConfig::None;
805        let core_config: slim_config::grpc::server::AuthenticationConfig = config.clone().into();
806        let back: ServerAuthenticationConfig = core_config.into();
807        assert_eq!(back, config);
808    }
809
810    // Test complex TlsClientConfig with all options
811    #[test]
812    fn test_complex_tls_client_config() {
813        let config = TlsClientConfig {
814            insecure: false,
815            insecure_skip_verify: false,
816            source: TlsSource::Pem {
817                cert: "-----BEGIN CERTIFICATE-----\ncert\n-----END CERTIFICATE-----".to_string(),
818                key: "-----BEGIN PRIVATE KEY-----\nkey\n-----END PRIVATE KEY-----".to_string(),
819            },
820            ca_source: CaSource::Pem {
821                data: "-----BEGIN CERTIFICATE-----\nCA\n-----END CERTIFICATE-----".to_string(),
822            },
823            include_system_ca_certs_pool: false,
824            tls_version: "tls1.2".to_string(),
825        };
826
827        let core_config: CoreTlsClientConfig = config.clone().into();
828        let back: TlsClientConfig = core_config.into();
829        assert_eq!(back, config);
830    }
831
832    // Test complex TlsServerConfig with all options
833    #[test]
834    fn test_complex_tls_server_config() {
835        let config = TlsServerConfig {
836            insecure: false,
837            source: TlsSource::File {
838                cert: "/etc/tls/server.crt".to_string(),
839                key: "/etc/tls/server.key".to_string(),
840            },
841            client_ca: CaSource::File {
842                path: "/etc/tls/ca.crt".to_string(),
843            },
844            include_system_ca_certs_pool: Some(false),
845            tls_version: Some("tls1.2".to_string()),
846            reload_client_ca_file: Some(true),
847        };
848
849        let core_config: CoreTlsServerConfig = config.clone().into();
850        let back: TlsServerConfig = core_config.into();
851        assert_eq!(back, config);
852    }
853
854    // Test all TlsSource variants
855    #[test]
856    fn test_all_tls_source_variants() {
857        let variants = vec![
858            TlsSource::Pem {
859                cert: "cert1".to_string(),
860                key: "key1".to_string(),
861            },
862            TlsSource::File {
863                cert: "/path1".to_string(),
864                key: "/path2".to_string(),
865            },
866            TlsSource::None,
867        ];
868
869        for variant in variants {
870            let core: slim_config::tls::common::TlsSource = variant.clone().into();
871            let back: TlsSource = core.into();
872            assert_eq!(back, variant);
873        }
874    }
875
876    // Test all CaSource variants
877    #[test]
878    fn test_all_ca_source_variants() {
879        let variants = vec![
880            CaSource::File {
881                path: "/ca/path".to_string(),
882            },
883            CaSource::Pem {
884                data: "ca-pem-data".to_string(),
885            },
886            CaSource::None,
887        ];
888
889        for variant in variants {
890            let core: slim_config::tls::common::CaSource = variant.clone().into();
891            let back: CaSource = core.into();
892            assert_eq!(back, variant);
893        }
894    }
895
896    // Test SpireConfig with minimal configuration
897    #[test]
898    fn test_spire_config_minimal() {
899        let config = SpireConfig {
900            socket_path: None,
901            target_spiffe_id: None,
902            jwt_audiences: vec![],
903            trust_domains: vec![],
904        };
905
906        assert_eq!(config.socket_path, None);
907        assert_eq!(config.target_spiffe_id, None);
908        assert!(config.jwt_audiences.is_empty());
909        assert!(config.trust_domains.is_empty());
910    }
911
912    // Test SpireConfig with full configuration
913    #[test]
914    fn test_spire_config_full() {
915        let config = SpireConfig {
916            socket_path: Some("/var/run/spire.sock".to_string()),
917            target_spiffe_id: Some("spiffe://example.com/workload".to_string()),
918            jwt_audiences: vec!["aud1".to_string(), "aud2".to_string(), "aud3".to_string()],
919            trust_domains: vec!["domain1.com".to_string(), "domain2.com".to_string()],
920        };
921
922        assert_eq!(config.socket_path, Some("/var/run/spire.sock".to_string()));
923        assert_eq!(
924            config.target_spiffe_id,
925            Some("spiffe://example.com/workload".to_string())
926        );
927        assert_eq!(config.jwt_audiences.len(), 3);
928        assert_eq!(config.trust_domains.len(), 2);
929    }
930}