1use slim_auth::auth_provider::{AuthProvider, AuthVerifier};
5use slim_config::auth::identity::{
6 IdentityProviderConfig as CoreIdentityProviderConfig,
7 IdentityVerifierConfig as CoreIdentityVerifierConfig,
8};
9use slim_config::auth::jwt::Config as JwtAuthConfig;
10use slim_config::auth::jwt::{Claims as JwtClaims, JwtKey};
11use slim_config::auth::static_jwt::Config as StaticJwtConfig;
12use std::time::Duration;
13
14#[cfg_attr(target_family = "windows", allow(unused_imports))]
15use crate::common_config::SpireConfig;
16use crate::errors::SlimError;
17
18#[derive(uniffi::Record, Clone, Debug, PartialEq)]
21pub struct StaticJwtAuth {
22 pub token_file: String,
24 pub duration: Duration,
26}
27
28impl From<StaticJwtAuth> for StaticJwtConfig {
29 fn from(config: StaticJwtAuth) -> Self {
30 StaticJwtConfig::with_file(&config.token_file).with_duration(config.duration)
31 }
32}
33
34impl From<StaticJwtConfig> for StaticJwtAuth {
35 fn from(config: StaticJwtConfig) -> Self {
36 StaticJwtAuth {
37 token_file: config.source().file.clone(),
38 duration: config.duration(),
39 }
40 }
41}
42
43#[derive(uniffi::Enum, Clone, Debug, PartialEq)]
45pub enum JwtAlgorithm {
46 HS256,
47 HS384,
48 HS512,
49 ES256,
50 ES384,
51 RS256,
52 RS384,
53 RS512,
54 PS256,
55 PS384,
56 PS512,
57 EdDSA,
58}
59
60impl From<JwtAlgorithm> for slim_auth::jwt::Algorithm {
61 fn from(algo: JwtAlgorithm) -> Self {
62 match algo {
63 JwtAlgorithm::HS256 => slim_auth::jwt::Algorithm::HS256,
64 JwtAlgorithm::HS384 => slim_auth::jwt::Algorithm::HS384,
65 JwtAlgorithm::HS512 => slim_auth::jwt::Algorithm::HS512,
66 JwtAlgorithm::ES256 => slim_auth::jwt::Algorithm::ES256,
67 JwtAlgorithm::ES384 => slim_auth::jwt::Algorithm::ES384,
68 JwtAlgorithm::RS256 => slim_auth::jwt::Algorithm::RS256,
69 JwtAlgorithm::RS384 => slim_auth::jwt::Algorithm::RS384,
70 JwtAlgorithm::RS512 => slim_auth::jwt::Algorithm::RS512,
71 JwtAlgorithm::PS256 => slim_auth::jwt::Algorithm::PS256,
72 JwtAlgorithm::PS384 => slim_auth::jwt::Algorithm::PS384,
73 JwtAlgorithm::PS512 => slim_auth::jwt::Algorithm::PS512,
74 JwtAlgorithm::EdDSA => slim_auth::jwt::Algorithm::EdDSA,
75 }
76 }
77}
78
79impl From<slim_auth::jwt::Algorithm> for JwtAlgorithm {
80 fn from(algo: slim_auth::jwt::Algorithm) -> Self {
81 match algo {
82 slim_auth::jwt::Algorithm::HS256 => JwtAlgorithm::HS256,
83 slim_auth::jwt::Algorithm::HS384 => JwtAlgorithm::HS384,
84 slim_auth::jwt::Algorithm::HS512 => JwtAlgorithm::HS512,
85 slim_auth::jwt::Algorithm::ES256 => JwtAlgorithm::ES256,
86 slim_auth::jwt::Algorithm::ES384 => JwtAlgorithm::ES384,
87 slim_auth::jwt::Algorithm::RS256 => JwtAlgorithm::RS256,
88 slim_auth::jwt::Algorithm::RS384 => JwtAlgorithm::RS384,
89 slim_auth::jwt::Algorithm::RS512 => JwtAlgorithm::RS512,
90 slim_auth::jwt::Algorithm::PS256 => JwtAlgorithm::PS256,
91 slim_auth::jwt::Algorithm::PS384 => JwtAlgorithm::PS384,
92 slim_auth::jwt::Algorithm::PS512 => JwtAlgorithm::PS512,
93 slim_auth::jwt::Algorithm::EdDSA => JwtAlgorithm::EdDSA,
94 }
95 }
96}
97
98#[derive(uniffi::Enum, Clone, Debug, PartialEq)]
100pub enum JwtKeyFormat {
101 Pem,
102 Jwk,
103 Jwks,
104}
105
106impl From<JwtKeyFormat> for slim_auth::jwt::KeyFormat {
107 fn from(format: JwtKeyFormat) -> Self {
108 match format {
109 JwtKeyFormat::Pem => slim_auth::jwt::KeyFormat::Pem,
110 JwtKeyFormat::Jwk => slim_auth::jwt::KeyFormat::Jwk,
111 JwtKeyFormat::Jwks => slim_auth::jwt::KeyFormat::Jwks,
112 }
113 }
114}
115
116impl From<slim_auth::jwt::KeyFormat> for JwtKeyFormat {
117 fn from(format: slim_auth::jwt::KeyFormat) -> Self {
118 match format {
119 slim_auth::jwt::KeyFormat::Pem => JwtKeyFormat::Pem,
120 slim_auth::jwt::KeyFormat::Jwk => JwtKeyFormat::Jwk,
121 slim_auth::jwt::KeyFormat::Jwks => JwtKeyFormat::Jwks,
122 }
123 }
124}
125
126#[derive(uniffi::Enum, Clone, Debug, PartialEq)]
128pub enum JwtKeyData {
129 Data { value: String },
131 File { path: String },
133}
134
135impl From<JwtKeyData> for slim_auth::jwt::KeyData {
136 fn from(data: JwtKeyData) -> Self {
137 match data {
138 JwtKeyData::Data { value } => slim_auth::jwt::KeyData::Data(value),
139 JwtKeyData::File { path } => slim_auth::jwt::KeyData::File(path),
140 }
141 }
142}
143
144impl From<slim_auth::jwt::KeyData> for JwtKeyData {
145 fn from(data: slim_auth::jwt::KeyData) -> Self {
146 match data {
147 slim_auth::jwt::KeyData::Data(value) => JwtKeyData::Data { value },
148 slim_auth::jwt::KeyData::File(path) => JwtKeyData::File { path },
149 }
150 }
151}
152
153#[derive(uniffi::Record, Clone, Debug, PartialEq)]
155pub struct JwtKeyConfig {
156 pub algorithm: JwtAlgorithm,
158 pub format: JwtKeyFormat,
160 pub key: JwtKeyData,
162}
163
164impl From<JwtKeyConfig> for slim_auth::jwt::Key {
165 fn from(config: JwtKeyConfig) -> Self {
166 slim_auth::jwt::Key {
167 algorithm: config.algorithm.into(),
168 format: config.format.into(),
169 key: config.key.into(),
170 }
171 }
172}
173
174impl From<slim_auth::jwt::Key> for JwtKeyConfig {
175 fn from(key: slim_auth::jwt::Key) -> Self {
176 JwtKeyConfig {
177 algorithm: key.algorithm.into(),
178 format: key.format.into(),
179 key: key.key.into(),
180 }
181 }
182}
183
184#[derive(uniffi::Enum, Clone, Debug, PartialEq)]
186pub enum JwtKeyType {
187 Encoding { key: JwtKeyConfig },
189 Decoding { key: JwtKeyConfig },
191 Autoresolve,
193}
194
195impl From<JwtKeyType> for JwtKey {
196 fn from(key_type: JwtKeyType) -> Self {
197 match key_type {
198 JwtKeyType::Encoding { key } => JwtKey::Encoding(key.into()),
199 JwtKeyType::Decoding { key } => JwtKey::Decoding(key.into()),
200 JwtKeyType::Autoresolve => JwtKey::Autoresolve,
201 }
202 }
203}
204
205impl From<JwtKey> for JwtKeyType {
206 fn from(key: JwtKey) -> Self {
207 match key {
208 JwtKey::Encoding(k) => JwtKeyType::Encoding { key: k.into() },
209 JwtKey::Decoding(k) => JwtKeyType::Decoding { key: k.into() },
210 JwtKey::Autoresolve => JwtKeyType::Autoresolve,
211 }
212 }
213}
214
215#[derive(uniffi::Record, Clone, Debug, PartialEq)]
217pub struct ClientJwtAuth {
218 pub key: JwtKeyType,
220 pub audience: Option<Vec<String>>,
222 pub issuer: Option<String>,
224 pub subject: Option<String>,
226 pub duration: Duration,
228}
229
230impl From<ClientJwtAuth> for JwtAuthConfig {
231 fn from(config: ClientJwtAuth) -> Self {
232 let mut claims = JwtClaims::default();
233
234 if let Some(audience) = config.audience {
235 claims = claims.with_audience(&audience);
236 }
237
238 if let Some(issuer) = config.issuer {
239 claims = claims.with_issuer(issuer);
240 }
241
242 if let Some(subject) = config.subject {
243 claims = claims.with_subject(subject);
244 }
245
246 JwtAuthConfig::new(claims, config.duration, config.key.into())
247 }
248}
249
250impl From<JwtAuthConfig> for ClientJwtAuth {
251 fn from(config: JwtAuthConfig) -> Self {
252 let claims = config.claims();
253 ClientJwtAuth {
254 key: config.key().clone().into(),
255 audience: claims.audience().clone(),
256 issuer: claims.issuer().clone(),
257 subject: claims.subject().clone(),
258 duration: config.duration(),
259 }
260 }
261}
262
263#[derive(uniffi::Record, Clone, Debug, PartialEq)]
265pub struct JwtAuth {
266 pub key: JwtKeyType,
268 pub audience: Option<Vec<String>>,
270 pub issuer: Option<String>,
272 pub subject: Option<String>,
274 pub duration: Duration,
276}
277
278impl From<JwtAuth> for JwtAuthConfig {
279 fn from(config: JwtAuth) -> Self {
280 let mut claims = JwtClaims::default();
281
282 if let Some(audience) = config.audience {
283 claims = claims.with_audience(&audience);
284 }
285
286 if let Some(issuer) = config.issuer {
287 claims = claims.with_issuer(issuer);
288 }
289
290 if let Some(subject) = config.subject {
291 claims = claims.with_subject(subject);
292 }
293
294 JwtAuthConfig::new(claims, config.duration, config.key.into())
295 }
296}
297
298impl From<JwtAuthConfig> for JwtAuth {
299 fn from(config: JwtAuthConfig) -> Self {
300 let claims = config.claims();
301 JwtAuth {
302 key: config.key().clone().into(),
303 audience: claims.audience().clone(),
304 issuer: claims.issuer().clone(),
305 subject: claims.subject().clone(),
306 duration: config.duration(),
307 }
308 }
309}
310
311#[derive(uniffi::Enum, Clone, Debug, PartialEq)]
313pub enum IdentityProviderConfig {
314 SharedSecret { id: String, data: String },
316 StaticJwt { config: StaticJwtAuth },
318 Jwt { config: ClientJwtAuth },
320 #[cfg(not(target_family = "windows"))]
322 Spire { config: SpireConfig },
323 None,
325}
326
327impl From<IdentityProviderConfig> for CoreIdentityProviderConfig {
328 fn from(config: IdentityProviderConfig) -> Self {
329 match config {
330 IdentityProviderConfig::SharedSecret { id, data } => {
331 CoreIdentityProviderConfig::SharedSecret { id, data }
332 }
333 IdentityProviderConfig::StaticJwt { config } => {
334 CoreIdentityProviderConfig::StaticJwt(config.into())
335 }
336 IdentityProviderConfig::Jwt { config } => {
337 CoreIdentityProviderConfig::Jwt(config.into())
338 }
339 #[cfg(not(target_family = "windows"))]
340 IdentityProviderConfig::Spire { config } => {
341 CoreIdentityProviderConfig::Spire(config.into())
342 }
343 IdentityProviderConfig::None => CoreIdentityProviderConfig::None,
344 }
345 }
346}
347
348impl From<CoreIdentityProviderConfig> for IdentityProviderConfig {
349 fn from(config: CoreIdentityProviderConfig) -> Self {
350 match config {
351 CoreIdentityProviderConfig::SharedSecret { id, data } => {
352 IdentityProviderConfig::SharedSecret { id, data }
353 }
354 CoreIdentityProviderConfig::StaticJwt(config) => IdentityProviderConfig::StaticJwt {
355 config: config.into(),
356 },
357 CoreIdentityProviderConfig::Jwt(config) => IdentityProviderConfig::Jwt {
358 config: config.into(),
359 },
360 #[cfg(not(target_family = "windows"))]
361 CoreIdentityProviderConfig::Spire(config) => IdentityProviderConfig::Spire {
362 config: config.into(),
363 },
364 CoreIdentityProviderConfig::None => IdentityProviderConfig::None,
365 }
366 }
367}
368
369#[derive(uniffi::Enum, Clone, Debug, PartialEq)]
371pub enum IdentityVerifierConfig {
372 SharedSecret { id: String, data: String },
374 Jwt { config: JwtAuth },
376 #[cfg(not(target_family = "windows"))]
378 Spire { config: SpireConfig },
379 None,
381}
382
383impl From<IdentityVerifierConfig> for CoreIdentityVerifierConfig {
384 fn from(config: IdentityVerifierConfig) -> Self {
385 match config {
386 IdentityVerifierConfig::SharedSecret { id, data } => {
387 CoreIdentityVerifierConfig::SharedSecret { id, data }
388 }
389 IdentityVerifierConfig::Jwt { config } => {
390 CoreIdentityVerifierConfig::Jwt(config.into())
391 }
392 #[cfg(not(target_family = "windows"))]
393 IdentityVerifierConfig::Spire { config } => {
394 CoreIdentityVerifierConfig::Spire(config.into())
395 }
396 IdentityVerifierConfig::None => CoreIdentityVerifierConfig::None,
397 }
398 }
399}
400
401impl From<CoreIdentityVerifierConfig> for IdentityVerifierConfig {
402 fn from(config: CoreIdentityVerifierConfig) -> Self {
403 match config {
404 CoreIdentityVerifierConfig::SharedSecret { id, data } => {
405 IdentityVerifierConfig::SharedSecret { id, data }
406 }
407 CoreIdentityVerifierConfig::Jwt(config) => IdentityVerifierConfig::Jwt {
408 config: config.into(),
409 },
410 #[cfg(not(target_family = "windows"))]
411 CoreIdentityVerifierConfig::Spire(config) => IdentityVerifierConfig::Spire {
412 config: config.into(),
413 },
414 CoreIdentityVerifierConfig::None => IdentityVerifierConfig::None,
415 }
416 }
417}
418
419impl TryFrom<IdentityProviderConfig> for AuthProvider {
420 type Error = SlimError;
421
422 fn try_from(config: IdentityProviderConfig) -> Result<Self, Self::Error> {
423 match config {
424 IdentityProviderConfig::SharedSecret { id, data } => {
425 Ok(AuthProvider::shared_secret_from_str(&id, &data)?)
426 }
427 IdentityProviderConfig::StaticJwt { config } => {
428 let core_config: StaticJwtConfig = config.into();
429 let provider = core_config.build_static_token_provider()?;
430 Ok(AuthProvider::static_token(provider))
431 }
432 IdentityProviderConfig::Jwt { config } => {
433 let core_config: JwtAuthConfig = config.into();
434 let provider = core_config.get_provider()?;
435 Ok(AuthProvider::jwt_signer(provider))
436 }
437 #[cfg(not(target_family = "windows"))]
438 IdentityProviderConfig::Spire { config } => {
439 let mut builder = slim_auth::spire::SpireIdentityManager::builder();
440
441 if let Some(socket_path) = config.socket_path {
442 builder = builder.with_socket_path(socket_path);
443 }
444
445 if let Some(target_spiffe_id) = config.target_spiffe_id {
446 builder = builder.with_target_spiffe_id(target_spiffe_id);
447 }
448
449 if !config.jwt_audiences.is_empty() {
450 builder = builder.with_jwt_audiences(config.jwt_audiences);
451 }
452
453 let manager = builder.build()?;
454 Ok(AuthProvider::spire(manager))
455 }
456 IdentityProviderConfig::None => Err(SlimError::InvalidArgument {
457 message: "Cannot create AuthProvider from None variant".to_string(),
458 }),
459 }
460 }
461}
462
463impl TryFrom<IdentityVerifierConfig> for AuthVerifier {
464 type Error = SlimError;
465
466 fn try_from(config: IdentityVerifierConfig) -> Result<Self, Self::Error> {
467 match config {
468 IdentityVerifierConfig::SharedSecret { id, data } => {
469 Ok(AuthVerifier::shared_secret_from_str(&id, &data)?)
470 }
471 IdentityVerifierConfig::Jwt { config } => {
472 let core_config: JwtAuthConfig = config.into();
473 let verifier = core_config.get_verifier()?;
474 Ok(AuthVerifier::jwt_verifier(verifier))
475 }
476 #[cfg(not(target_family = "windows"))]
477 IdentityVerifierConfig::Spire { config } => {
478 let mut builder = slim_auth::spire::SpireIdentityManager::builder();
479
480 if let Some(socket_path) = config.socket_path {
481 builder = builder.with_socket_path(socket_path);
482 }
483
484 if let Some(target_spiffe_id) = config.target_spiffe_id {
485 builder = builder.with_target_spiffe_id(target_spiffe_id);
486 }
487
488 if !config.jwt_audiences.is_empty() {
489 builder = builder.with_jwt_audiences(config.jwt_audiences);
490 }
491
492 let manager = builder.build()?;
493 Ok(AuthVerifier::spire(manager))
494 }
495 IdentityVerifierConfig::None => Err(SlimError::InvalidArgument {
496 message: "Cannot create AuthVerifier from None variant".to_string(),
497 }),
498 }
499 }
500}
501
502#[cfg(test)]
503mod tests {
504 use super::*;
505 use std::time::Duration;
506
507 #[test]
509 fn test_static_jwt_auth_conversion() {
510 let auth = StaticJwtAuth {
511 token_file: "/path/to/token.jwt".to_string(),
512 duration: Duration::from_secs(7200),
513 };
514
515 let core_config: StaticJwtConfig = auth.clone().into();
516 assert_eq!(core_config.source().file, auth.token_file);
517 assert_eq!(core_config.duration(), auth.duration);
518
519 let back_to_auth: StaticJwtAuth = core_config.into();
520 assert_eq!(back_to_auth, auth);
521 }
522
523 #[test]
525 fn test_jwt_algorithm_conversions() {
526 let algorithms = vec![
527 JwtAlgorithm::HS256,
528 JwtAlgorithm::HS384,
529 JwtAlgorithm::HS512,
530 JwtAlgorithm::ES256,
531 JwtAlgorithm::ES384,
532 JwtAlgorithm::RS256,
533 JwtAlgorithm::RS384,
534 JwtAlgorithm::RS512,
535 JwtAlgorithm::PS256,
536 JwtAlgorithm::PS384,
537 JwtAlgorithm::PS512,
538 JwtAlgorithm::EdDSA,
539 ];
540
541 for algo in algorithms {
542 let core_algo: slim_auth::jwt::Algorithm = algo.clone().into();
543 let back: JwtAlgorithm = core_algo.into();
544 assert_eq!(back, algo);
545 }
546 }
547
548 #[test]
550 fn test_jwt_key_format_conversions() {
551 let formats = vec![JwtKeyFormat::Pem, JwtKeyFormat::Jwk, JwtKeyFormat::Jwks];
552
553 for format in formats {
554 let core_format: slim_auth::jwt::KeyFormat = format.clone().into();
555 let back: JwtKeyFormat = core_format.into();
556 assert_eq!(back, format);
557 }
558 }
559
560 #[test]
562 fn test_jwt_key_data_conversions() {
563 let data_value = JwtKeyData::Data {
564 value: "test-key-data".to_string(),
565 };
566 let core_data: slim_auth::jwt::KeyData = data_value.clone().into();
567 let back: JwtKeyData = core_data.into();
568 assert_eq!(back, data_value);
569
570 let file_path = JwtKeyData::File {
571 path: "/path/to/key.pem".to_string(),
572 };
573 let core_file: slim_auth::jwt::KeyData = file_path.clone().into();
574 let back_file: JwtKeyData = core_file.into();
575 assert_eq!(back_file, file_path);
576 }
577
578 #[test]
580 fn test_jwt_key_config_conversions() {
581 let key_config = JwtKeyConfig {
582 algorithm: JwtAlgorithm::RS256,
583 format: JwtKeyFormat::Pem,
584 key: JwtKeyData::File {
585 path: "/path/to/key.pem".to_string(),
586 },
587 };
588
589 let core_key: slim_auth::jwt::Key = key_config.clone().into();
590 let back: JwtKeyConfig = core_key.into();
591 assert_eq!(back, key_config);
592 }
593
594 #[test]
596 fn test_jwt_key_type_conversions() {
597 let encoding_key = JwtKeyType::Encoding {
598 key: JwtKeyConfig {
599 algorithm: JwtAlgorithm::RS256,
600 format: JwtKeyFormat::Pem,
601 key: JwtKeyData::Data {
602 value: "encoding-key".to_string(),
603 },
604 },
605 };
606
607 let core_encoding: JwtKey = encoding_key.clone().into();
608 let back_encoding: JwtKeyType = core_encoding.into();
609 assert_eq!(back_encoding, encoding_key);
610
611 let decoding_key = JwtKeyType::Decoding {
612 key: JwtKeyConfig {
613 algorithm: JwtAlgorithm::ES256,
614 format: JwtKeyFormat::Jwk,
615 key: JwtKeyData::File {
616 path: "/path/to/key.jwk".to_string(),
617 },
618 },
619 };
620
621 let core_decoding: JwtKey = decoding_key.clone().into();
622 let back_decoding: JwtKeyType = core_decoding.into();
623 assert_eq!(back_decoding, decoding_key);
624
625 let autoresolve = JwtKeyType::Autoresolve;
626 let core_auto: JwtKey = autoresolve.clone().into();
627 let back_auto: JwtKeyType = core_auto.into();
628 assert_eq!(back_auto, autoresolve);
629 }
630
631 #[test]
633 fn test_client_jwt_auth_conversions() {
634 let client_auth = ClientJwtAuth {
635 key: JwtKeyType::Autoresolve,
636 audience: Some(vec!["api.example.com".to_string()]),
637 issuer: Some("auth.example.com".to_string()),
638 subject: Some("user@example.com".to_string()),
639 duration: Duration::from_secs(1800),
640 };
641
642 let core_config: JwtAuthConfig = client_auth.clone().into();
643 assert_eq!(core_config.duration(), client_auth.duration);
644
645 let back: ClientJwtAuth = core_config.into();
646 assert_eq!(back, client_auth);
647 }
648
649 #[test]
651 fn test_client_jwt_auth_with_none_fields() {
652 let client_auth = ClientJwtAuth {
653 key: JwtKeyType::Autoresolve,
654 audience: None,
655 issuer: None,
656 subject: None,
657 duration: Duration::from_secs(3600),
658 };
659
660 let core_config: JwtAuthConfig = client_auth.clone().into();
661 let back: ClientJwtAuth = core_config.into();
662 assert_eq!(back.audience, None);
663 assert_eq!(back.issuer, None);
664 assert_eq!(back.subject, None);
665 }
666
667 #[test]
669 fn test_jwt_auth_conversions() {
670 let jwt_auth = JwtAuth {
671 key: JwtKeyType::Decoding {
672 key: JwtKeyConfig {
673 algorithm: JwtAlgorithm::RS256,
674 format: JwtKeyFormat::Pem,
675 key: JwtKeyData::File {
676 path: "/path/to/key.pem".to_string(),
677 },
678 },
679 },
680 audience: Some(vec!["service.example.com".to_string()]),
681 issuer: Some("issuer.example.com".to_string()),
682 subject: Some("subject".to_string()),
683 duration: Duration::from_secs(900),
684 };
685
686 let core_config: JwtAuthConfig = jwt_auth.clone().into();
687 let back: JwtAuth = core_config.into();
688 assert_eq!(back, jwt_auth);
689 }
690
691 #[test]
693 fn test_identity_provider_config_shared_secret() {
694 let config = IdentityProviderConfig::SharedSecret {
695 id: "test-id".to_string(),
696 data: "secret-data".to_string(),
697 };
698
699 let core_config: CoreIdentityProviderConfig = config.clone().into();
700 let back: IdentityProviderConfig = core_config.into();
701 assert_eq!(back, config);
702 }
703
704 #[test]
705 fn test_identity_provider_config_static_jwt() {
706 let config = IdentityProviderConfig::StaticJwt {
707 config: StaticJwtAuth {
708 token_file: "/path/to/token.jwt".to_string(),
709 duration: Duration::from_secs(3600),
710 },
711 };
712
713 let core_config: CoreIdentityProviderConfig = config.clone().into();
714 let back: IdentityProviderConfig = core_config.into();
715 assert_eq!(back, config);
716 }
717
718 #[test]
719 fn test_identity_provider_config_jwt() {
720 let config = IdentityProviderConfig::Jwt {
721 config: ClientJwtAuth {
722 key: JwtKeyType::Autoresolve,
723 audience: Some(vec!["test".to_string()]),
724 issuer: None,
725 subject: None,
726 duration: Duration::from_secs(3600),
727 },
728 };
729
730 let core_config: CoreIdentityProviderConfig = config.clone().into();
731 let back: IdentityProviderConfig = core_config.into();
732 assert_eq!(back, config);
733 }
734
735 #[test]
736 fn test_identity_provider_config_none() {
737 let config = IdentityProviderConfig::None;
738 let core_config: CoreIdentityProviderConfig = config.clone().into();
739 let back: IdentityProviderConfig = core_config.into();
740 assert_eq!(back, config);
741 }
742
743 #[test]
745 fn test_identity_verifier_config_shared_secret() {
746 let config = IdentityVerifierConfig::SharedSecret {
747 id: "verifier-id".to_string(),
748 data: "verifier-secret".to_string(),
749 };
750
751 let core_config: CoreIdentityVerifierConfig = config.clone().into();
752 let back: IdentityVerifierConfig = core_config.into();
753 assert_eq!(back, config);
754 }
755
756 #[test]
757 fn test_identity_verifier_config_jwt() {
758 let config = IdentityVerifierConfig::Jwt {
759 config: JwtAuth {
760 key: JwtKeyType::Autoresolve,
761 audience: Some(vec!["verifier".to_string()]),
762 issuer: Some("auth".to_string()),
763 subject: None,
764 duration: Duration::from_secs(7200),
765 },
766 };
767
768 let core_config: CoreIdentityVerifierConfig = config.clone().into();
769 let back: IdentityVerifierConfig = core_config.into();
770 assert_eq!(back, config);
771 }
772
773 #[test]
774 fn test_identity_verifier_config_none() {
775 let config = IdentityVerifierConfig::None;
776 let core_config: CoreIdentityVerifierConfig = config.clone().into();
777 let back: IdentityVerifierConfig = core_config.into();
778 assert_eq!(back, config);
779 }
780
781 #[test]
783 fn test_identity_provider_to_auth_provider_shared_secret() {
784 let config = IdentityProviderConfig::SharedSecret {
785 id: "test-id".to_string(),
786 data: "shared-secret-value-0123456789abcdef".to_string(), };
788
789 let result: Result<AuthProvider, SlimError> = config.try_into();
790 assert!(result.is_ok());
791 }
792
793 #[test]
794 fn test_identity_provider_to_auth_provider_none_fails() {
795 let config = IdentityProviderConfig::None;
796 let result: Result<AuthProvider, SlimError> = config.try_into();
797 assert!(result.is_err());
798 if let Err(SlimError::InvalidArgument { message }) = result {
799 assert!(message.contains("Cannot create AuthProvider from None variant"));
800 }
801 }
802
803 #[test]
805 fn test_identity_verifier_to_auth_verifier_shared_secret() {
806 let config = IdentityVerifierConfig::SharedSecret {
807 id: "verifier-id".to_string(),
808 data: "verifier-shared-secret-0123456789abcdef".to_string(), };
810
811 let result: Result<AuthVerifier, SlimError> = config.try_into();
812 assert!(result.is_ok());
813 }
814
815 #[test]
816 fn test_identity_verifier_to_auth_verifier_none_fails() {
817 let config = IdentityVerifierConfig::None;
818 let result: Result<AuthVerifier, SlimError> = config.try_into();
819 assert!(result.is_err());
820 if let Err(SlimError::InvalidArgument { message }) = result {
821 assert!(message.contains("Cannot create AuthVerifier from None variant"));
822 }
823 }
824
825 #[test]
827 fn test_identity_provider_invalid_shared_secret() {
828 let config = IdentityProviderConfig::SharedSecret {
829 id: "test-id".to_string(),
830 data: "tooshort".to_string(), };
832
833 let result: Result<AuthProvider, SlimError> = config.try_into();
834 assert!(result.is_err());
835 if let Err(SlimError::InvalidArgument { message }) = result {
836 assert!(message.contains("Failed to create SharedSecret provider"));
837 }
838 }
839
840 #[test]
841 fn test_identity_verifier_invalid_shared_secret() {
842 let config = IdentityVerifierConfig::SharedSecret {
843 id: "test-id".to_string(),
844 data: "tooshort".to_string(), };
846
847 let result: Result<AuthVerifier, SlimError> = config.try_into();
848 assert!(result.is_err());
849 if let Err(SlimError::InvalidArgument { message }) = result {
850 assert!(message.contains("Failed to create SharedSecret verifier"));
851 }
852 }
853
854 #[cfg(not(target_family = "windows"))]
856 #[test]
857 fn test_identity_provider_config_spire() {
858 let spire_config = SpireConfig {
859 socket_path: Some("/tmp/spire.sock".to_string()),
860 target_spiffe_id: Some("spiffe://example.com/service".to_string()),
861 jwt_audiences: vec!["audience1".to_string(), "audience2".to_string()],
862 trust_domains: vec![],
863 };
864
865 let config = IdentityProviderConfig::Spire {
866 config: spire_config.clone(),
867 };
868
869 let core_config: CoreIdentityProviderConfig = config.clone().into();
870 let back: IdentityProviderConfig = core_config.into();
871
872 if let IdentityProviderConfig::Spire {
873 config: back_config,
874 } = back
875 {
876 assert_eq!(back_config.socket_path, spire_config.socket_path);
877 assert_eq!(back_config.target_spiffe_id, spire_config.target_spiffe_id);
878 assert_eq!(back_config.jwt_audiences, spire_config.jwt_audiences);
879 } else {
880 panic!("Expected Spire variant");
881 }
882 }
883
884 #[cfg(not(target_family = "windows"))]
885 #[test]
886 fn test_identity_verifier_config_spire() {
887 let spire_config = SpireConfig {
888 socket_path: None,
889 target_spiffe_id: None,
890 jwt_audiences: vec!["slim".to_string()],
891 trust_domains: vec!["example.com".to_string()],
892 };
893
894 let config = IdentityVerifierConfig::Spire {
895 config: spire_config.clone(),
896 };
897
898 let core_config: CoreIdentityVerifierConfig = config.clone().into();
899 let back: IdentityVerifierConfig = core_config.into();
900
901 if let IdentityVerifierConfig::Spire {
902 config: back_config,
903 } = back
904 {
905 assert_eq!(back_config.socket_path, spire_config.socket_path);
906 assert_eq!(back_config.jwt_audiences, spire_config.jwt_audiences);
907 } else {
908 panic!("Expected Spire variant");
909 }
910 }
911
912 #[test]
914 fn test_complex_jwt_key_configurations() {
915 let configurations = vec![
916 JwtKeyConfig {
917 algorithm: JwtAlgorithm::HS256,
918 format: JwtKeyFormat::Pem,
919 key: JwtKeyData::Data {
920 value: "secret-key".to_string(),
921 },
922 },
923 JwtKeyConfig {
924 algorithm: JwtAlgorithm::ES384,
925 format: JwtKeyFormat::Jwk,
926 key: JwtKeyData::File {
927 path: "/etc/keys/ec-key.jwk".to_string(),
928 },
929 },
930 JwtKeyConfig {
931 algorithm: JwtAlgorithm::PS512,
932 format: JwtKeyFormat::Jwks,
933 key: JwtKeyData::File {
934 path: "/etc/keys/jwks.json".to_string(),
935 },
936 },
937 ];
938
939 for config in configurations {
940 let core_key: slim_auth::jwt::Key = config.clone().into();
941 let back: JwtKeyConfig = core_key.into();
942 assert_eq!(back, config);
943 }
944 }
945
946 #[test]
948 fn test_all_jwt_algorithms_covered() {
949 let all_algorithms = vec![
950 (JwtAlgorithm::HS256, slim_auth::jwt::Algorithm::HS256),
951 (JwtAlgorithm::HS384, slim_auth::jwt::Algorithm::HS384),
952 (JwtAlgorithm::HS512, slim_auth::jwt::Algorithm::HS512),
953 (JwtAlgorithm::ES256, slim_auth::jwt::Algorithm::ES256),
954 (JwtAlgorithm::ES384, slim_auth::jwt::Algorithm::ES384),
955 (JwtAlgorithm::RS256, slim_auth::jwt::Algorithm::RS256),
956 (JwtAlgorithm::RS384, slim_auth::jwt::Algorithm::RS384),
957 (JwtAlgorithm::RS512, slim_auth::jwt::Algorithm::RS512),
958 (JwtAlgorithm::PS256, slim_auth::jwt::Algorithm::PS256),
959 (JwtAlgorithm::PS384, slim_auth::jwt::Algorithm::PS384),
960 (JwtAlgorithm::PS512, slim_auth::jwt::Algorithm::PS512),
961 (JwtAlgorithm::EdDSA, slim_auth::jwt::Algorithm::EdDSA),
962 ];
963
964 for (adapter_algo, core_algo) in all_algorithms {
965 let converted_core: slim_auth::jwt::Algorithm = adapter_algo.clone().into();
966 let converted_back: JwtAlgorithm = converted_core.into();
967 assert_eq!(converted_back, adapter_algo);
968
969 let direct_back: JwtAlgorithm = core_algo.into();
970 assert_eq!(direct_back, adapter_algo);
971 }
972 }
973}