Skip to content

Commit e5d7708

Browse files
MatKuhra-d
andauthored
[Destinations] Improve Detection and Masking of Secrets in Debug Logs (#798)
Co-authored-by: Alexander Dümont <alexander_duemont@web.de>
1 parent 3b353a9 commit e5d7708

4 files changed

Lines changed: 28 additions & 19 deletions

File tree

cloudplatform/cloudplatform-connectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/DefaultDestination.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import java.util.Map;
88
import java.util.TreeMap;
99
import java.util.function.Function;
10+
import java.util.function.Predicate;
11+
import java.util.stream.Stream;
1012

1113
import javax.annotation.Nonnull;
1214

@@ -63,9 +65,11 @@ public Iterable<String> getPropertyNames()
6365
public String toString()
6466
{
6567
final Map<String, Object> nonSensitiveProperties = Maps.newHashMap(properties);
68+
final Predicate<String> sensitivePropertyFilter =
69+
key -> Stream.of("password", "secret").anyMatch(key::contains);
6670

6771
for( final Map.Entry<String, Object> entry : nonSensitiveProperties.entrySet() ) {
68-
if( entry.getKey().toLowerCase(Locale.ENGLISH).contains("password") ) {
72+
if( sensitivePropertyFilter.test(entry.getKey().toLowerCase(Locale.ENGLISH)) ) {
6973
entry.setValue("(hidden)");
7074
}
7175
}

cloudplatform/cloudplatform-connectivity/src/test/java/com/sap/cloud/sdk/cloudplatform/connectivity/DefaultDestinationTest.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,20 @@ void testIdentity()
4343
@Test
4444
void testToString()
4545
{
46-
final Destination dest = DefaultDestination.builder().name("foo").property("some_password", "bar").build();
47-
assertThat(dest).hasToString("DefaultDestination(properties={some_password=(hidden), Name=foo})");
46+
final Destination dest =
47+
DefaultDestination
48+
.builder()
49+
.name("foo")
50+
.property("some_password", "bar")
51+
.property("some_secret", "baz")
52+
.build();
53+
54+
assertThat(dest.toString())
55+
.startsWith("DefaultDestination(properties={")
56+
.contains("some_password=(hidden)")
57+
.contains("some_secret=(hidden)")
58+
.contains("Name=foo")
59+
.endsWith("})");
4860
}
4961

5062
@Test

cloudplatform/connectivity-destination-service/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/DestinationServiceAdapter.java

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import org.apache.http.StatusLine;
1919
import org.apache.http.client.methods.HttpGet;
2020
import org.apache.http.client.methods.HttpUriRequest;
21-
import org.slf4j.event.Level;
2221

2322
import com.google.common.base.Strings;
2423
import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor;
@@ -146,37 +145,31 @@ private static String handleResponse( final HttpUriRequest request, final HttpRe
146145
final int statusCode = status.getStatusCode();
147146
final String reasonPhrase = status.getReasonPhrase();
148147

148+
log.debug("Destination service returned HTTP status {} ({})", statusCode, reasonPhrase);
149+
149150
Try<String> maybeBody = Try.of(() -> HttpEntityUtil.getResponseBody(response));
150-
String logMessage = "Destination service returned HTTP status %s (%s)";
151151
if( maybeBody.isFailure() ) {
152152
final var ex =
153153
new DestinationAccessException("Failed to read body from HTTP response", maybeBody.getCause());
154154
maybeBody = Try.failure(ex);
155-
logMessage = String.format(logMessage, statusCode, reasonPhrase);
156-
} else {
157-
logMessage = String.format(logMessage + "and body '%s'", statusCode, reasonPhrase, maybeBody.get());
158155
}
159156

160157
if( statusCode == HttpStatus.SC_OK ) {
161158
final var ex = new DestinationAccessException("Failed to get destinations: no body returned in response.");
162159
maybeBody = maybeBody.filter(it -> !Strings.isNullOrEmpty(it), () -> ex);
163-
log.atLevel(maybeBody.isSuccess() ? Level.DEBUG : Level.ERROR).log(logMessage);
164160
return maybeBody.get();
165161
}
166162

167-
log.error(logMessage);
168163
final String requestUri = request.getURI().getPath();
169164
if( statusCode == HttpStatus.SC_NOT_FOUND ) {
170165
throw new DestinationNotFoundException(null, "Destination could not be found for path " + requestUri + ".");
171166
}
172-
throw new DestinationAccessException(
173-
String
174-
.format(
175-
"Failed to get destinations: destination service returned HTTP status %s (%S) at '%s'.,",
176-
statusCode,
177-
reasonPhrase,
178-
requestUri));
179-
167+
final String message =
168+
"Failed to get destinations: destination service responded with HTTP status %s (%S) at '%s'."
169+
.formatted(statusCode, reasonPhrase, requestUri);
170+
final String messageWithBody = message + " Body: %s".formatted(maybeBody.getOrElseGet(Throwable::getMessage));
171+
log.error(messageWithBody);
172+
throw new DestinationAccessException(message);
180173
}
181174

182175
private HttpUriRequest prepareRequest( final String servicePath, final DestinationRetrievalStrategy strategy )

release_notes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
### 📈 Improvements
1818

19-
-
19+
- Improve the detection and masking of secrets when logging data to debug.
2020

2121
### 🐛 Fixed Issues
2222

0 commit comments

Comments
 (0)