2222//!
2323//! [librdkafka-config]: https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md
2424
25- use std:: collections:: HashMap ;
25+ use std:: collections:: { BTreeMap , HashMap } ;
2626use std:: ffi:: CString ;
27+ use std:: fmt:: Debug ;
2728use std:: iter:: FromIterator ;
2829use std:: os:: raw:: c_char;
2930use std:: ptr;
@@ -36,6 +37,16 @@ use crate::error::{IsError, KafkaError, KafkaResult};
3637use crate :: log:: { log_enabled, DEBUG , INFO , WARN } ;
3738use crate :: util:: { ErrBuf , KafkaDrop , NativePtr } ;
3839
40+ const SENSITIVE_CONFIG_KEYS : & [ & str ] = & [
41+ "sasl.password" ,
42+ "ssl.key.password" ,
43+ "ssl.keystore.password" ,
44+ "ssl.truststore.password" ,
45+ "sasl.oauthbearer.client.secret" ,
46+ ] ;
47+
48+ const SANITIZED_VALUE_PLACEHOLDER : & str = "[sanitized for safety]" ;
49+
3950/// The log levels supported by librdkafka.
4051#[ derive( Copy , Clone , Debug ) ]
4152pub enum RDKafkaLogLevel {
@@ -181,14 +192,35 @@ impl NativeClientConfig {
181192}
182193
183194/// Client configuration.
184- #[ derive( Clone , Debug ) ]
195+ #[ derive( Clone ) ]
185196pub struct ClientConfig {
186197 conf_map : HashMap < String , String > ,
187198 /// The librdkafka logging level. Refer to [`RDKafkaLogLevel`] for the list
188199 /// of available levels.
189200 pub log_level : RDKafkaLogLevel ,
190201}
191202
203+ impl Debug for ClientConfig {
204+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
205+ let sanitized: BTreeMap < & str , & str > = self
206+ . conf_map
207+ . iter ( )
208+ . filter_map ( |( key, value) | {
209+ if SENSITIVE_CONFIG_KEYS . contains ( & key. as_str ( ) ) {
210+ None
211+ } else {
212+ Some ( ( key. as_str ( ) , value. as_str ( ) ) )
213+ }
214+ } )
215+ . collect ( ) ;
216+
217+ let mut debug_struct = f. debug_struct ( "ClientConfig" ) ;
218+ debug_struct. field ( "log_level" , & self . log_level ) ;
219+ debug_struct. field ( "conf_map" , & sanitized) ;
220+ debug_struct. finish ( )
221+ }
222+ }
223+
192224impl Default for ClientConfig {
193225 fn default ( ) -> Self {
194226 Self :: new ( )
@@ -204,9 +236,21 @@ impl ClientConfig {
204236 }
205237 }
206238
207- /// Gets a reference to the underlying config map
208- pub fn config_map ( & self ) -> & HashMap < String , String > {
209- & self . conf_map
239+ /// Returns a sanitized view of the underlying config map.
240+ ///
241+ /// Sensitive keys have their values replaced with a placeholder string so they never appear in
242+ /// clear text when inspected.
243+ pub fn config_map ( & self ) -> BTreeMap < & str , & str > {
244+ self . conf_map
245+ . iter ( )
246+ . map ( |( key, value) | {
247+ if SENSITIVE_CONFIG_KEYS . contains ( & key. as_str ( ) ) {
248+ ( key. as_str ( ) , SANITIZED_VALUE_PLACEHOLDER )
249+ } else {
250+ ( key. as_str ( ) , value. as_str ( ) )
251+ }
252+ } )
253+ . collect ( )
210254 }
211255
212256 /// Gets the value of a parameter in the configuration.
0 commit comments