This is an automated email from the ASF dual-hosted git repository.

jerryshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 37343112c4 [#13218] fix(common): exclude credentials from 
OAuth2TokenResponse and SecretsResponse toString (#13221)
37343112c4 is described below

commit 37343112c48759bb058b798723f338ef387cee2a
Author: YangJie <[email protected]>
AuthorDate: Sun Sep 20 05:42:16 2026 -0400

    [#13218] fix(common): exclude credentials from OAuth2TokenResponse and 
SecretsResponse toString (#13221)
    
    ### What changes were proposed in this pull request?
    
    `@ToString.Exclude` is added to the credential fields on
    `OAuth2TokenResponse` (`accessToken`/`refreshToken`) and
    `SecretsResponse` (the secrets map). Jackson serialization,
    `equals`/`hashCode`, and `validate()` are unchanged.
    
    ### Why are the changes needed?
    
    Lombok `@ToString` rendered the bearer credentials and the secrets map
    in plaintext, so any log statement printing these response objects
    leaked secret material.
    
    Fix: #13218
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes, in log output: `toString()` on `OAuth2TokenResponse` and
    `SecretsResponse` no longer includes the credential values, so log
    statements that print these objects no longer leak them. Jackson
    serialization, `equals`/`hashCode`, and `validate()` are unchanged.
    
    ### How was this patch tested?
    
    Added `TestSecretBearingResponsesToString`, which pins that `toString()`
    on both responses does not contain the credential values; it fails on
    the pre-fix tree (plaintext visible) and passes after the fix.
---
 .../dto/responses/OAuth2TokenResponse.java         |  4 ++
 .../gravitino/dto/responses/SecretsResponse.java   |  3 ++
 .../TestSecretBearingResponsesToString.java        | 54 ++++++++++++++++++++++
 3 files changed, 61 insertions(+)

diff --git 
a/common/src/main/java/org/apache/gravitino/dto/responses/OAuth2TokenResponse.java
 
b/common/src/main/java/org/apache/gravitino/dto/responses/OAuth2TokenResponse.java
index 796295e205..5d5eba9de5 100644
--- 
a/common/src/main/java/org/apache/gravitino/dto/responses/OAuth2TokenResponse.java
+++ 
b/common/src/main/java/org/apache/gravitino/dto/responses/OAuth2TokenResponse.java
@@ -35,6 +35,9 @@ import org.apache.commons.lang3.StringUtils;
 @EqualsAndHashCode(callSuper = true)
 @ToString
 public class OAuth2TokenResponse extends BaseResponse {
+  // Excluded from toString: these are bearer credentials, and the response 
object ending up in
+  // a log line must not leak them.
+  @ToString.Exclude
   @JsonProperty("access_token")
   private final String accessToken;
 
@@ -51,6 +54,7 @@ public class OAuth2TokenResponse extends BaseResponse {
   @JsonProperty("scope")
   private final String scope;
 
+  @ToString.Exclude
   @Nullable
   @JsonProperty("refresh_token")
   private final String refreshToken;
diff --git 
a/common/src/main/java/org/apache/gravitino/dto/responses/SecretsResponse.java 
b/common/src/main/java/org/apache/gravitino/dto/responses/SecretsResponse.java
index ebef221da0..a2a31e0322 100644
--- 
a/common/src/main/java/org/apache/gravitino/dto/responses/SecretsResponse.java
+++ 
b/common/src/main/java/org/apache/gravitino/dto/responses/SecretsResponse.java
@@ -31,6 +31,9 @@ import lombok.ToString;
 @EqualsAndHashCode(callSuper = true)
 public class SecretsResponse extends BaseResponse {
 
+  // Excluded from toString: the map holds secret material, and the response 
object ending up in
+  // a log line must not leak it.
+  @ToString.Exclude
   @JsonProperty("secrets")
   private final Map<String, String> secrets;
 
diff --git 
a/common/src/test/java/org/apache/gravitino/dto/responses/TestSecretBearingResponsesToString.java
 
b/common/src/test/java/org/apache/gravitino/dto/responses/TestSecretBearingResponsesToString.java
new file mode 100644
index 0000000000..039a7b21ca
--- /dev/null
+++ 
b/common/src/test/java/org/apache/gravitino/dto/responses/TestSecretBearingResponsesToString.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.gravitino.dto.responses;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestSecretBearingResponsesToString {
+
+  @Test
+  public void testOAuth2TokenResponseDoesNotLeakTokens() {
+    OAuth2TokenResponse response =
+        new OAuth2TokenResponse(
+            "secret-access-token-123",
+            "access_token",
+            "bearer",
+            3600,
+            "read write",
+            "secret-refresh-token-456");
+
+    // Before the fix, Lombok @ToString rendered the bearer credentials in 
plaintext, so logging
+    // the response leaked them.
+    
Assertions.assertFalse(response.toString().contains("secret-access-token-123"));
+    
Assertions.assertFalse(response.toString().contains("secret-refresh-token-456"));
+    // Non-secret fields stay visible so the string remains useful for 
debugging.
+    Assertions.assertTrue(response.toString().contains("3600"));
+    Assertions.assertTrue(response.toString().contains("read write"));
+  }
+
+  @Test
+  public void testSecretsResponseDoesNotLeakSecretValues() {
+    SecretsResponse response =
+        new SecretsResponse(ImmutableMap.of("kms.key", 
"super-secret-material"));
+
+    
Assertions.assertFalse(response.toString().contains("super-secret-material"));
+  }
+}

Reply via email to