use std::sync::Arc;
use camel_auth::native_auth::{NativeCredential, NativeCredentialSecret, NativeCredentialStore};
use camel_auth::{Principal, ProviderEntry, ProviderRegistry, StaticTokenAuthenticator};
use camel_config::config::{NativeAuthConfig, NativeCredentialEntry, SecurityConfig};
pub struct SecurityConfigFixture {
name: String,
}
impl SecurityConfigFixture {
pub fn single_static_provider(name: &str) -> Self {
Self {
name: name.to_string(),
}
}
fn subject(&self) -> String {
format!("test-user-{}", self.name)
}
fn token(&self) -> String {
format!("test-token-{}", self.name) }
pub fn to_config(&self) -> SecurityConfig {
SecurityConfig {
native: Some(NativeAuthConfig {
subject: self.subject(),
issuer: None,
bearer_token: None,
api_key: None,
roles: vec![],
scopes: vec![],
credentials: vec![NativeCredentialEntry {
subject: self.subject(),
secret_env: None,
secret: Some(self.token()),
roles: vec!["test-role".to_string()],
scopes: vec![],
}],
}),
..Default::default()
}
}
pub fn providers(&self) -> ProviderRegistry {
let credential = NativeCredential {
secret: NativeCredentialSecret::Plaintext {
value: self.token().into(),
},
principal: Principal {
subject: self.subject(),
issuer: "native".into(),
audience: vec![],
scopes: vec![],
roles: vec!["test-role".into()],
claims: serde_json::Value::Object(Default::default()),
},
};
let store = NativeCredentialStore::try_new(vec![credential])
.expect("fixture credential is structurally valid"); let registry = ProviderRegistry::new();
registry.register(
&self.name,
ProviderEntry {
authenticator: Arc::new(StaticTokenAuthenticator::new(store)),
audience_binding: None,
},
);
registry
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fixture_serializes_without_env_placeholders() {
let fixture = SecurityConfigFixture::single_static_provider("idp-test");
let toml = toml::to_string(&fixture.to_config().native.expect("native section"))
.expect("serializes"); assert!(
toml.contains("test-token-idp-test"),
"inline token must serialize for inspection: {toml}"
);
assert!(
!toml.contains("{{env:"),
"no env placeholders in a deterministic fixture: {toml}"
);
}
#[tokio::test]
async fn fixture_principal_shape_matches_cli_mapping() {
let fixture = SecurityConfigFixture::single_static_provider("idp-test");
let registry = fixture.providers();
let entry = registry.resolve("idp-test").expect("registered"); let principal = entry
.authenticator
.authenticate_bearer("test-token-idp-test")
.await
.expect("fixture token authenticates"); assert_eq!(principal.subject, "test-user-idp-test");
assert_eq!(principal.issuer, "native");
assert_eq!(principal.roles, vec!["test-role".to_string()]);
assert_eq!(principal.claims, serde_json::json!({}));
}
#[test]
fn fixture_registry_resolves() {
let fixture = SecurityConfigFixture::single_static_provider("idp-test");
let registry = fixture.providers();
assert!(registry.resolve("idp-test").is_some());
assert!(registry.resolve("ghost").is_none());
}
}