faucet_common_elasticsearch/
lib.rs1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3use faucet_core::{Credential, FaucetError};
16use schemars::JsonSchema;
17use serde::{Deserialize, Serialize};
18
19#[derive(Clone, Serialize, Deserialize, JsonSchema)]
25#[serde(tag = "type", content = "config", rename_all = "snake_case")]
26pub enum ElasticsearchAuth {
27 None,
29 Basic { username: String, password: String },
31 Bearer { token: String },
33 ApiKey { key: String },
35}
36
37pub fn credential_to_auth(cred: Credential) -> Result<ElasticsearchAuth, FaucetError> {
44 match cred {
45 Credential::Bearer(token) => Ok(ElasticsearchAuth::Bearer { token }),
46 Credential::Basic { username, password } => {
47 Ok(ElasticsearchAuth::Basic { username, password })
48 }
49 other => Err(FaucetError::Auth(format!(
50 "Elasticsearch auth provider must yield a bearer or basic credential, got {other:?}"
51 ))),
52 }
53}
54
55impl std::fmt::Debug for ElasticsearchAuth {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 match self {
58 Self::None => write!(f, "None"),
59 Self::Basic { username, .. } => f
60 .debug_struct("Basic")
61 .field("username", username)
62 .field("password", &"***")
63 .finish(),
64 Self::Bearer { .. } => write!(f, "Bearer(***)"),
65 Self::ApiKey { .. } => write!(f, "ApiKey(***)"),
66 }
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn debug_masks_basic_password() {
76 let auth = ElasticsearchAuth::Basic {
77 username: "user".into(),
78 password: "secret".into(),
79 };
80 let debug = format!("{auth:?}");
81 assert!(debug.contains("user"));
82 assert!(debug.contains("***"));
83 assert!(!debug.contains("secret"));
84 }
85
86 #[test]
87 fn debug_masks_bearer_token() {
88 let auth = ElasticsearchAuth::Bearer {
89 token: "my-token".into(),
90 };
91 let debug = format!("{auth:?}");
92 assert!(debug.contains("***"));
93 assert!(!debug.contains("my-token"));
94 }
95
96 #[test]
97 fn debug_masks_api_key() {
98 let auth = ElasticsearchAuth::ApiKey {
99 key: "my-key".into(),
100 };
101 let debug = format!("{auth:?}");
102 assert!(debug.contains("***"));
103 assert!(!debug.contains("my-key"));
104 }
105
106 #[test]
107 fn debug_none_renders_unit() {
108 let auth = ElasticsearchAuth::None;
109 assert_eq!(format!("{auth:?}"), "None");
110 }
111
112 #[test]
113 fn serde_round_trip_basic() {
114 let auth = ElasticsearchAuth::Basic {
115 username: "u".into(),
116 password: "p".into(),
117 };
118 let json = serde_json::to_string(&auth).unwrap();
119 assert_eq!(
120 json,
121 r#"{"type":"basic","config":{"username":"u","password":"p"}}"#
122 );
123 let parsed: ElasticsearchAuth = serde_json::from_str(&json).unwrap();
124 assert!(matches!(parsed, ElasticsearchAuth::Basic { .. }));
125 }
126
127 #[test]
128 fn serde_round_trip_none() {
129 let json = serde_json::to_string(&ElasticsearchAuth::None).unwrap();
130 assert_eq!(json, r#"{"type":"none"}"#);
131 let parsed: ElasticsearchAuth = serde_json::from_str(&json).unwrap();
132 assert!(matches!(parsed, ElasticsearchAuth::None));
133 }
134
135 #[test]
136 fn serde_round_trip_bearer() {
137 let auth = ElasticsearchAuth::Bearer { token: "t".into() };
138 let json = serde_json::to_string(&auth).unwrap();
139 assert_eq!(json, r#"{"type":"bearer","config":{"token":"t"}}"#);
140 let parsed: ElasticsearchAuth = serde_json::from_str(&json).unwrap();
141 assert!(matches!(parsed, ElasticsearchAuth::Bearer { .. }));
142 }
143
144 #[test]
145 fn serde_round_trip_api_key() {
146 let auth = ElasticsearchAuth::ApiKey { key: "k".into() };
147 let json = serde_json::to_string(&auth).unwrap();
148 assert_eq!(json, r#"{"type":"api_key","config":{"key":"k"}}"#);
149 let parsed: ElasticsearchAuth = serde_json::from_str(&json).unwrap();
150 assert!(matches!(parsed, ElasticsearchAuth::ApiKey { .. }));
151 }
152}