Skip to main content

nifi_rust_client/config/
credentials.rs

1//! Credential providers for NiFi authentication.
2//!
3//! The [`CredentialProvider`] trait abstracts how username/password pairs are
4//! obtained, enabling static credentials, environment-variable lookups, and
5//! custom strategies (vault, file-based, etc.).
6
7use std::fmt;
8
9use crate::error::NifiError;
10
11/// Wraps a value and masks it in [`fmt::Debug`] output as `[REDACTED]`.
12///
13/// Use this for sensitive fields (e.g. passwords) to prevent them from
14/// leaking into logs or debug output.
15#[derive(Clone)]
16pub struct Redacted<T>(T);
17
18impl<T> Redacted<T> {
19    /// Wrap `value` so its debug representation is hidden.
20    pub fn new(value: T) -> Self {
21        Self(value)
22    }
23
24    /// Return a reference to the wrapped value.
25    pub fn inner(&self) -> &T {
26        &self.0
27    }
28}
29
30impl<T> fmt::Debug for Redacted<T> {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        f.write_str("[REDACTED]")
33    }
34}
35
36/// Provides username/password credentials for NiFi authentication.
37///
38/// Implement this trait to supply credentials from any source — static values,
39/// environment variables, a secrets vault, or a rotating credential store.
40#[async_trait::async_trait]
41pub trait CredentialProvider: Send + Sync + fmt::Debug {
42    /// Returns a `(username, password)` pair, or an error if credentials
43    /// cannot be resolved.
44    async fn credentials(&self) -> Result<(String, String), NifiError>;
45}
46
47/// Fixed username/password credentials.
48///
49/// Useful for tests or simple deployments where credentials are known at
50/// build time.
51#[derive(Debug, Clone)]
52pub struct StaticCredentials {
53    username: String,
54    password: Redacted<String>,
55}
56
57impl StaticCredentials {
58    /// Create a new `StaticCredentials` with the given username and password.
59    pub fn new(username: impl Into<String>, password: impl Into<String>) -> Self {
60        Self {
61            username: username.into(),
62            password: Redacted::new(password.into()),
63        }
64    }
65}
66
67#[async_trait::async_trait]
68impl CredentialProvider for StaticCredentials {
69    async fn credentials(&self) -> Result<(String, String), NifiError> {
70        Ok((self.username.clone(), self.password.inner().clone()))
71    }
72}
73
74/// Credentials read from environment variables.
75///
76/// By default reads `NIFI_USERNAME` and `NIFI_PASSWORD`. Use
77/// [`EnvCredentials::with_vars`] to override the variable names.
78#[derive(Debug, Clone)]
79pub struct EnvCredentials {
80    username_var: String,
81    password_var: String,
82}
83
84impl EnvCredentials {
85    /// Create an `EnvCredentials` using the default environment variable
86    /// names (`NIFI_USERNAME` and `NIFI_PASSWORD`).
87    pub fn new() -> Self {
88        Self {
89            username_var: "NIFI_USERNAME".to_string(),
90            password_var: "NIFI_PASSWORD".to_string(),
91        }
92    }
93
94    /// Create an `EnvCredentials` using custom environment variable names.
95    pub fn with_vars(username_var: impl Into<String>, password_var: impl Into<String>) -> Self {
96        Self {
97            username_var: username_var.into(),
98            password_var: password_var.into(),
99        }
100    }
101
102    /// Returns the environment variable name used for the username.
103    pub fn username_var(&self) -> &str {
104        &self.username_var
105    }
106
107    /// Returns the environment variable name used for the password.
108    pub fn password_var(&self) -> &str {
109        &self.password_var
110    }
111}
112
113impl Default for EnvCredentials {
114    fn default() -> Self {
115        Self::new()
116    }
117}
118
119#[async_trait::async_trait]
120impl CredentialProvider for EnvCredentials {
121    async fn credentials(&self) -> Result<(String, String), NifiError> {
122        let username = std::env::var(&self.username_var).map_err(|_| NifiError::Auth {
123            message: format!("environment variable {} is not set", self.username_var),
124        })?;
125        let password = std::env::var(&self.password_var).map_err(|_| NifiError::Auth {
126            message: format!("environment variable {} is not set", self.password_var),
127        })?;
128        Ok((username, password))
129    }
130}