Skip to main content

static_authn_plugin/
config.rs

1//! Configuration for the static `AuthN` resolver plugin.
2
3use secrecy::SecretString;
4use serde::Deserialize;
5use uuid::Uuid;
6
7use modkit_security::constants::{DEFAULT_SUBJECT_ID, DEFAULT_TENANT_ID};
8
9/// Plugin configuration.
10#[derive(Debug, Clone, Deserialize)]
11#[serde(default, deny_unknown_fields)]
12pub struct StaticAuthNPluginConfig {
13    /// Vendor name for GTS instance registration.
14    pub vendor: String,
15
16    /// Plugin priority (lower = higher priority).
17    pub priority: i16,
18
19    /// Authentication mode.
20    pub mode: AuthNMode,
21
22    /// Default identity returned in `accept_all` mode.
23    pub default_identity: IdentityConfig,
24
25    /// Static token-to-identity mappings for `static_tokens` mode.
26    pub tokens: Vec<TokenMapping>,
27
28    /// S2S credential-to-identity mappings for `exchange_client_credentials`.
29    pub s2s_credentials: Vec<S2sCredentialMapping>,
30}
31
32impl Default for StaticAuthNPluginConfig {
33    fn default() -> Self {
34        Self {
35            vendor: "hyperspot".to_owned(),
36            priority: 100,
37            mode: AuthNMode::AcceptAll,
38            default_identity: IdentityConfig::default(),
39            tokens: Vec::new(),
40            s2s_credentials: Vec::new(),
41        }
42    }
43}
44
45/// Authentication mode.
46#[derive(Debug, Clone, Deserialize, Default)]
47#[serde(rename_all = "snake_case")]
48pub enum AuthNMode {
49    /// Accept any non-empty token and return the default identity.
50    #[default]
51    AcceptAll,
52    /// Map specific tokens to specific identities.
53    StaticTokens,
54}
55
56/// Identity configuration for a subject.
57#[derive(Debug, Clone, Deserialize)]
58#[serde(default, deny_unknown_fields)]
59pub struct IdentityConfig {
60    /// Subject ID (user/service).
61    pub subject_id: Uuid,
62
63    /// Subject's home tenant.
64    pub subject_tenant_id: Uuid,
65
66    /// Token scopes. `["*"]` means first-party / unrestricted.
67    pub token_scopes: Vec<String>,
68
69    /// Subject type — opaque metadata passed through to PDP via `EvaluationRequest.Subject`.
70    /// Recommended format: GTS type identifier (e.g. `"gts.x.core.security.subject_user.v1~"`).
71    /// The platform does not interpret this value; PDP policies may use it for role/permission mapping.
72    pub subject_type: Option<String>,
73}
74
75impl Default for IdentityConfig {
76    fn default() -> Self {
77        Self {
78            subject_id: DEFAULT_SUBJECT_ID,
79            subject_tenant_id: DEFAULT_TENANT_ID,
80            token_scopes: vec!["*".to_owned()],
81            subject_type: None,
82        }
83    }
84}
85
86/// Maps a static token to a specific identity.
87#[derive(Debug, Clone, Deserialize)]
88#[serde(deny_unknown_fields)]
89pub struct TokenMapping {
90    /// The bearer token value to match.
91    pub token: String,
92    /// The identity to return when this token is presented.
93    pub identity: IdentityConfig,
94}
95
96/// Maps S2S client credentials to a specific identity.
97#[derive(Clone, Deserialize)]
98#[serde(deny_unknown_fields)]
99pub struct S2sCredentialMapping {
100    /// `OAuth2` client identifier.
101    pub client_id: String,
102    /// Client secret (redacted in `Debug` output).
103    pub client_secret: SecretString,
104    /// The identity to return when these credentials are presented.
105    /// When omitted, uses the default identity (`DEFAULT_SUBJECT_ID` / `DEFAULT_TENANT_ID`).
106    #[serde(default)]
107    pub identity: IdentityConfig,
108}
109
110impl std::fmt::Debug for S2sCredentialMapping {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        f.debug_struct("S2sCredentialMapping")
113            .field("client_id", &self.client_id)
114            .field("client_secret", &"[REDACTED]")
115            .field("identity", &self.identity)
116            .finish()
117    }
118}