Skip to content

Commit 4c2d787

Browse files
authored
[rust] Redact credentials in the reqwest Configuration and ApiKey Debug output (#25019)
* [rust] Redact credentials in the reqwest Configuration and ApiKey Debug output * [rust] Redact the token source in Configuration Debug and test every credential
1 parent ec4430e commit 4c2d787

25 files changed

Lines changed: 689 additions & 47 deletions

File tree

‎modules/openapi-generator/src/main/resources/rust/reqwest-trait/configuration.mustache‎

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use async_trait::async_trait;
1313
{{/supportTokenSource}}
1414
pub use {{#supportMiddleware}}reqwest_middleware::ClientWithMiddleware{{/supportMiddleware}}{{^supportMiddleware}}reqwest::Client{{/supportMiddleware}};
1515

16-
#[derive(Debug, Clone)]
16+
#[derive(Clone)]
1717
pub struct Configuration {
1818
pub base_path: String,
1919
pub user_agent: Option<String>,
@@ -35,11 +35,20 @@ pub struct Configuration {
3535

3636
pub type BasicAuth = (String, Option<String>);
3737

38-
#[derive(Debug, Clone)]
38+
#[derive(Clone)]
3939
pub struct ApiKey {
4040
pub prefix: Option<String>,
4141
pub key: String,
4242
}
43+
44+
impl std::fmt::Debug for ApiKey {
45+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46+
f.debug_struct("ApiKey")
47+
.field("prefix", &self.prefix)
48+
.field("key", &"[REDACTED]")
49+
.finish()
50+
}
51+
}
4352
{{/supportTokenSource}}
4453
4554
{{#withAWSV4Signature}}
@@ -81,6 +90,30 @@ impl AWSv4Key {
8190
}
8291
{{/withAWSV4Signature}}
8392
93+
impl std::fmt::Debug for Configuration {
94+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95+
let mut debug = f.debug_struct("Configuration");
96+
debug
97+
.field("base_path", &self.base_path)
98+
.field("user_agent", &self.user_agent)
99+
.field("client", &self.client);
100+
{{^supportTokenSource}}
101+
debug
102+
.field("basic_auth", &self.basic_auth.as_ref().map(|(username, password)| (username, password.as_ref().map(|_| "[REDACTED]"))))
103+
.field("oauth_access_token", &self.oauth_access_token.as_ref().map(|_| "[REDACTED]"))
104+
.field("bearer_access_token", &self.bearer_access_token.as_ref().map(|_| "[REDACTED]"))
105+
.field("api_key", &self.api_key);
106+
{{/supportTokenSource}}
107+
{{#withAWSV4Signature}}
108+
debug.field("aws_v4_key", &self.aws_v4_key);
109+
{{/withAWSV4Signature}}
110+
{{#supportTokenSource}}
111+
debug.field("token_source", &"[REDACTED]");
112+
{{/supportTokenSource}}
113+
debug.finish()
114+
}
115+
}
116+
84117
impl Configuration {
85118
pub fn new() -> Configuration {
86119
Configuration::default()

‎modules/openapi-generator/src/main/resources/rust/reqwest/configuration.mustache‎

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use async_trait::async_trait;
1313
{{/supportTokenSource}}
1414
pub use {{#supportMiddleware}}reqwest_middleware::ClientWithMiddleware{{/supportMiddleware}}{{^supportMiddleware}}reqwest{{^supportAsync}}::blocking{{/supportAsync}}::Client{{/supportMiddleware}};
1515

16-
#[derive(Debug, Clone)]
16+
#[derive(Clone)]
1717
pub struct Configuration {
1818
pub base_path: String,
1919
pub user_agent: Option<String>,
@@ -37,11 +37,20 @@ pub struct Configuration {
3737

3838
pub type BasicAuth = (String, Option<String>);
3939

40-
#[derive(Debug, Clone)]
40+
#[derive(Clone)]
4141
pub struct ApiKey {
4242
pub prefix: Option<String>,
4343
pub key: String,
4444
}
45+
46+
impl std::fmt::Debug for ApiKey {
47+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48+
f.debug_struct("ApiKey")
49+
.field("prefix", &self.prefix)
50+
.field("key", &"[REDACTED]")
51+
.finish()
52+
}
53+
}
4554
{{/supportTokenSource}}
4655
4756
{{#withAWSV4Signature}}
@@ -83,6 +92,32 @@ impl AWSv4Key {
8392
}
8493
{{/withAWSV4Signature}}
8594
95+
impl std::fmt::Debug for Configuration {
96+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97+
let mut debug = f.debug_struct("Configuration");
98+
debug
99+
.field("base_path", &self.base_path)
100+
.field("user_agent", &self.user_agent)
101+
.field("client", &self.client);
102+
{{^supportTokenSource}}
103+
debug
104+
.field("basic_auth", &self.basic_auth.as_ref().map(|(username, password)| (username, password.as_ref().map(|_| "[REDACTED]"))))
105+
.field("oauth_access_token", &self.oauth_access_token.as_ref().map(|_| "[REDACTED]"))
106+
.field("bearer_access_token", &self.bearer_access_token.as_ref().map(|_| "[REDACTED]"))
107+
.field("api_key", &self.api_key);
108+
{{/supportTokenSource}}
109+
{{#withAWSV4Signature}}
110+
debug.field("aws_v4_key", &self.aws_v4_key);
111+
{{/withAWSV4Signature}}
112+
{{#supportAsync}}
113+
{{#supportTokenSource}}
114+
debug.field("token_source", &"[REDACTED]");
115+
{{/supportTokenSource}}
116+
{{/supportAsync}}
117+
debug.finish()
118+
}
119+
}
120+
86121
impl Configuration {
87122
pub fn new() -> Configuration {
88123
Configuration::default()

‎modules/openapi-generator/src/test/java/org/openapitools/codegen/rust/RustClientCodegenTest.java‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,4 +413,40 @@ public void testReqwestTraitUuidParamsUseNamedLifetimes() throws IOException {
413413
"async fn list_widget_items<'id, 'run_id>(&self, id: &'id str, run_id: Option<&'run_id str>)");
414414
TestUtils.assertFileNotContains(outputPath, "Option<&str>");
415415
}
416+
417+
@Test
418+
public void testReqwestConfigurationDebugRedactsCredentials() throws IOException {
419+
for (String library : new String[]{"reqwest", "reqwest-trait"}) {
420+
Path outputPath = generateReqwestConfiguration(library, false);
421+
TestUtils.assertFileNotContains(outputPath, "#[derive(Debug, Clone)]");
422+
TestUtils.assertFileContains(outputPath,
423+
".field(\"basic_auth\", &self.basic_auth.as_ref().map(|(username, password)| (username, password.as_ref().map(|_| \"[REDACTED]\"))))",
424+
".field(\"oauth_access_token\", &self.oauth_access_token.as_ref().map(|_| \"[REDACTED]\"))",
425+
".field(\"bearer_access_token\", &self.bearer_access_token.as_ref().map(|_| \"[REDACTED]\"))",
426+
".field(\"api_key\", &self.api_key)",
427+
".field(\"key\", &\"[REDACTED]\")");
428+
429+
Path tokenSourcePath = generateReqwestConfiguration(library, true);
430+
TestUtils.assertFileNotContains(tokenSourcePath, "#[derive(Debug, Clone)]", "&self.token_source");
431+
TestUtils.assertFileContains(tokenSourcePath, ".field(\"token_source\", &\"[REDACTED]\")");
432+
}
433+
}
434+
435+
private Path generateReqwestConfiguration(String library, boolean supportTokenSource) throws IOException {
436+
Path target = Files.createTempDirectory("test");
437+
target.toFile().deleteOnExit();
438+
final CodegenConfigurator configurator = new CodegenConfigurator()
439+
.setGeneratorName("rust")
440+
.setLibrary(library)
441+
.addAdditionalProperty("supportAsync", true)
442+
.addAdditionalProperty("supportTokenSource", supportTokenSource)
443+
.setInputSpec("src/test/resources/3_0/rust/petstore.yaml")
444+
.setSkipOverwrite(false)
445+
.setOutputDir(target.toAbsolutePath().toString().replace("\\", "/"));
446+
List<File> files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate();
447+
files.forEach(File::deleteOnExit);
448+
Path outputPath = Path.of(target.toString(), "/src/apis/configuration.rs");
449+
TestUtils.assertFileExists(outputPath);
450+
return outputPath;
451+
}
416452
}

‎samples/client/others/rust/reqwest-regression-16119/src/apis/configuration.rs‎

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
pub use reqwest::blocking::Client;
1313

14-
#[derive(Debug, Clone)]
14+
#[derive(Clone)]
1515
pub struct Configuration {
1616
pub base_path: String,
1717
pub user_agent: Option<String>,
@@ -24,12 +24,37 @@ pub struct Configuration {
2424

2525
pub type BasicAuth = (String, Option<String>);
2626

27-
#[derive(Debug, Clone)]
27+
#[derive(Clone)]
2828
pub struct ApiKey {
2929
pub prefix: Option<String>,
3030
pub key: String,
3131
}
3232

33+
impl std::fmt::Debug for ApiKey {
34+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35+
f.debug_struct("ApiKey")
36+
.field("prefix", &self.prefix)
37+
.field("key", &"[REDACTED]")
38+
.finish()
39+
}
40+
}
41+
42+
43+
impl std::fmt::Debug for Configuration {
44+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45+
let mut debug = f.debug_struct("Configuration");
46+
debug
47+
.field("base_path", &self.base_path)
48+
.field("user_agent", &self.user_agent)
49+
.field("client", &self.client);
50+
debug
51+
.field("basic_auth", &self.basic_auth.as_ref().map(|(username, password)| (username, password.as_ref().map(|_| "[REDACTED]"))))
52+
.field("oauth_access_token", &self.oauth_access_token.as_ref().map(|_| "[REDACTED]"))
53+
.field("bearer_access_token", &self.bearer_access_token.as_ref().map(|_| "[REDACTED]"))
54+
.field("api_key", &self.api_key);
55+
debug.finish()
56+
}
57+
}
3358

3459
impl Configuration {
3560
pub fn new() -> Configuration {

‎samples/client/others/rust/reqwest/api-with-ref-param/src/apis/configuration.rs‎

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
pub use reqwest::Client;
1313

14-
#[derive(Debug, Clone)]
14+
#[derive(Clone)]
1515
pub struct Configuration {
1616
pub base_path: String,
1717
pub user_agent: Option<String>,
@@ -24,12 +24,37 @@ pub struct Configuration {
2424

2525
pub type BasicAuth = (String, Option<String>);
2626

27-
#[derive(Debug, Clone)]
27+
#[derive(Clone)]
2828
pub struct ApiKey {
2929
pub prefix: Option<String>,
3030
pub key: String,
3131
}
3232

33+
impl std::fmt::Debug for ApiKey {
34+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35+
f.debug_struct("ApiKey")
36+
.field("prefix", &self.prefix)
37+
.field("key", &"[REDACTED]")
38+
.finish()
39+
}
40+
}
41+
42+
43+
impl std::fmt::Debug for Configuration {
44+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45+
let mut debug = f.debug_struct("Configuration");
46+
debug
47+
.field("base_path", &self.base_path)
48+
.field("user_agent", &self.user_agent)
49+
.field("client", &self.client);
50+
debug
51+
.field("basic_auth", &self.basic_auth.as_ref().map(|(username, password)| (username, password.as_ref().map(|_| "[REDACTED]"))))
52+
.field("oauth_access_token", &self.oauth_access_token.as_ref().map(|_| "[REDACTED]"))
53+
.field("bearer_access_token", &self.bearer_access_token.as_ref().map(|_| "[REDACTED]"))
54+
.field("api_key", &self.api_key);
55+
debug.finish()
56+
}
57+
}
3358

3459
impl Configuration {
3560
pub fn new() -> Configuration {

‎samples/client/others/rust/reqwest/composed-oneof/src/apis/configuration.rs‎

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
pub use reqwest::blocking::Client;
1313

14-
#[derive(Debug, Clone)]
14+
#[derive(Clone)]
1515
pub struct Configuration {
1616
pub base_path: String,
1717
pub user_agent: Option<String>,
@@ -24,12 +24,37 @@ pub struct Configuration {
2424

2525
pub type BasicAuth = (String, Option<String>);
2626

27-
#[derive(Debug, Clone)]
27+
#[derive(Clone)]
2828
pub struct ApiKey {
2929
pub prefix: Option<String>,
3030
pub key: String,
3131
}
3232

33+
impl std::fmt::Debug for ApiKey {
34+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35+
f.debug_struct("ApiKey")
36+
.field("prefix", &self.prefix)
37+
.field("key", &"[REDACTED]")
38+
.finish()
39+
}
40+
}
41+
42+
43+
impl std::fmt::Debug for Configuration {
44+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45+
let mut debug = f.debug_struct("Configuration");
46+
debug
47+
.field("base_path", &self.base_path)
48+
.field("user_agent", &self.user_agent)
49+
.field("client", &self.client);
50+
debug
51+
.field("basic_auth", &self.basic_auth.as_ref().map(|(username, password)| (username, password.as_ref().map(|_| "[REDACTED]"))))
52+
.field("oauth_access_token", &self.oauth_access_token.as_ref().map(|_| "[REDACTED]"))
53+
.field("bearer_access_token", &self.bearer_access_token.as_ref().map(|_| "[REDACTED]"))
54+
.field("api_key", &self.api_key);
55+
debug.finish()
56+
}
57+
}
3358

3459
impl Configuration {
3560
pub fn new() -> Configuration {

‎samples/client/others/rust/reqwest/emptyObject/src/apis/configuration.rs‎

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
pub use reqwest::blocking::Client;
1313

14-
#[derive(Debug, Clone)]
14+
#[derive(Clone)]
1515
pub struct Configuration {
1616
pub base_path: String,
1717
pub user_agent: Option<String>,
@@ -24,12 +24,37 @@ pub struct Configuration {
2424

2525
pub type BasicAuth = (String, Option<String>);
2626

27-
#[derive(Debug, Clone)]
27+
#[derive(Clone)]
2828
pub struct ApiKey {
2929
pub prefix: Option<String>,
3030
pub key: String,
3131
}
3232

33+
impl std::fmt::Debug for ApiKey {
34+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35+
f.debug_struct("ApiKey")
36+
.field("prefix", &self.prefix)
37+
.field("key", &"[REDACTED]")
38+
.finish()
39+
}
40+
}
41+
42+
43+
impl std::fmt::Debug for Configuration {
44+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45+
let mut debug = f.debug_struct("Configuration");
46+
debug
47+
.field("base_path", &self.base_path)
48+
.field("user_agent", &self.user_agent)
49+
.field("client", &self.client);
50+
debug
51+
.field("basic_auth", &self.basic_auth.as_ref().map(|(username, password)| (username, password.as_ref().map(|_| "[REDACTED]"))))
52+
.field("oauth_access_token", &self.oauth_access_token.as_ref().map(|_| "[REDACTED]"))
53+
.field("bearer_access_token", &self.bearer_access_token.as_ref().map(|_| "[REDACTED]"))
54+
.field("api_key", &self.api_key);
55+
debug.finish()
56+
}
57+
}
3358

3459
impl Configuration {
3560
pub fn new() -> Configuration {

0 commit comments

Comments
 (0)