camel_test/
security_fixture.rs1use std::sync::Arc;
15
16use camel_auth::native_auth::{NativeCredential, NativeCredentialSecret, NativeCredentialStore};
17use camel_auth::{Principal, ProviderEntry, ProviderRegistry, StaticTokenAuthenticator};
18use camel_config::config::{NativeAuthConfig, NativeCredentialEntry, SecurityConfig};
19
20pub struct SecurityConfigFixture {
26 name: String,
27}
28
29impl SecurityConfigFixture {
30 pub fn single_static_provider(name: &str) -> Self {
31 Self {
32 name: name.to_string(),
33 }
34 }
35
36 fn subject(&self) -> String {
37 format!("test-user-{}", self.name)
38 }
39
40 fn token(&self) -> String {
41 format!("test-token-{}", self.name) }
43
44 pub fn to_config(&self) -> SecurityConfig {
47 SecurityConfig {
48 native: Some(NativeAuthConfig {
49 subject: self.subject(),
50 issuer: None,
51 bearer_token: None,
52 api_key: None,
53 roles: vec![],
54 scopes: vec![],
55 credentials: vec![NativeCredentialEntry {
56 subject: self.subject(),
57 secret_env: None,
58 secret: Some(self.token()),
59 roles: vec!["test-role".to_string()],
60 scopes: vec![],
61 }],
62 }),
63 ..Default::default()
64 }
65 }
66
67 pub fn providers(&self) -> ProviderRegistry {
71 let credential = NativeCredential {
72 secret: NativeCredentialSecret::Plaintext {
73 value: self.token().into(),
74 },
75 principal: Principal {
76 subject: self.subject(),
77 issuer: "native".into(),
78 audience: vec![],
79 scopes: vec![],
80 roles: vec!["test-role".into()],
81 claims: serde_json::Value::Object(Default::default()),
82 },
83 };
84 let store = NativeCredentialStore::try_new(vec![credential])
85 .expect("fixture credential is structurally valid"); let registry = ProviderRegistry::new();
87 registry.register(
88 &self.name,
89 ProviderEntry {
90 authenticator: Arc::new(StaticTokenAuthenticator::new(store)),
91 audience_binding: None,
92 },
93 );
94 registry
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn fixture_serializes_without_env_placeholders() {
104 let fixture = SecurityConfigFixture::single_static_provider("idp-test");
105 let toml = toml::to_string(&fixture.to_config().native.expect("native section"))
106 .expect("serializes"); assert!(
108 toml.contains("test-token-idp-test"),
109 "inline token must serialize for inspection: {toml}"
110 );
111 assert!(
112 !toml.contains("{{env:"),
113 "no env placeholders in a deterministic fixture: {toml}"
114 );
115 }
116
117 #[tokio::test]
118 async fn fixture_principal_shape_matches_cli_mapping() {
119 let fixture = SecurityConfigFixture::single_static_provider("idp-test");
122 let registry = fixture.providers();
123 let entry = registry.resolve("idp-test").expect("registered"); let principal = entry
125 .authenticator
126 .authenticate_bearer("test-token-idp-test")
127 .await
128 .expect("fixture token authenticates"); assert_eq!(principal.subject, "test-user-idp-test");
130 assert_eq!(principal.issuer, "native");
131 assert_eq!(principal.roles, vec!["test-role".to_string()]);
132 assert_eq!(principal.claims, serde_json::json!({}));
133 }
134
135 #[test]
136 fn fixture_registry_resolves() {
137 let fixture = SecurityConfigFixture::single_static_provider("idp-test");
138 let registry = fixture.providers();
139 assert!(registry.resolve("idp-test").is_some());
140 assert!(registry.resolve("ghost").is_none());
141 }
142}