Skip to content

Commit f1e226f

Browse files
authored
fix: remove sensitive data when BoxAPIException logs request (#1284)
* fix: remove sensitive data when BoxAPIException logs request * remove wiremock setup * checkstyle * checkstyle test * allow customizing sanitization keys
1 parent ed82a13 commit f1e226f

File tree

3 files changed

+149
-1
lines changed

3 files changed

+149
-1
lines changed

src/main/java/com/box/sdk/BoxAPIConnection.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import okhttp3.Authenticator;
3232
import okhttp3.Call;
3333
import okhttp3.Credentials;
34+
import okhttp3.Headers;
3435
import okhttp3.OkHttpClient;
3536
import okhttp3.Request;
3637
import okhttp3.Response;
@@ -1265,7 +1266,8 @@ private Response executeOnClient(OkHttpClient httpClient, Request request) {
12651266
try {
12661267
return createNewCall(httpClient, request).execute();
12671268
} catch (IOException e) {
1268-
throw new BoxAPIException("Couldn't connect to the Box API due to a network error. Request\n" + request, e);
1269+
throw new BoxAPIException("Couldn't connect to the Box API due to a network error. Request\n"
1270+
+ toSanitizedRequest(request), e);
12691271
}
12701272
}
12711273

@@ -1298,4 +1300,12 @@ protected enum ResourceLinkType {
12981300
*/
12991301
SharedLink
13001302
}
1303+
1304+
private Request toSanitizedRequest(Request originalRequest) {
1305+
Headers sanitizedHeaders = BoxSensitiveDataSanitizer.sanitizeHeaders(originalRequest.headers());
1306+
1307+
return originalRequest.newBuilder()
1308+
.headers(sanitizedHeaders)
1309+
.build();
1310+
}
13011311
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.box.sdk;
2+
3+
import java.util.Arrays;
4+
import java.util.HashSet;
5+
import java.util.Set;
6+
import okhttp3.Headers;
7+
import org.jetbrains.annotations.NotNull;
8+
9+
/**
10+
* Class used to sanitize sensitive data from payload.
11+
*/
12+
public final class BoxSensitiveDataSanitizer {
13+
private static final Set<String> SENSITIVE_KEYS = new HashSet<>(Arrays.asList("authorization", "access_token",
14+
"refresh_token", "subject_token", "token", "client_id", "client_secret", "code", "shared_link", "download_url",
15+
"jwt_private_key", "jwt_private_key_passphrase", "password"));
16+
17+
private BoxSensitiveDataSanitizer() {
18+
}
19+
20+
/**
21+
* Add key that should be sanitized
22+
*
23+
* @param key key to be sanitized
24+
*/
25+
public static void addKeyToSanitize(String key) {
26+
SENSITIVE_KEYS.add(key);
27+
}
28+
29+
@NotNull
30+
static Headers sanitizeHeaders(Headers originalHeaders) {
31+
Headers.Builder sanitizedHeadersBuilder = originalHeaders.newBuilder();
32+
33+
for (String originalHeaderName : originalHeaders.names()) {
34+
if (isSensitiveKey(originalHeaderName)) {
35+
sanitizedHeadersBuilder.set(originalHeaderName, "[REDACTED]");
36+
} else {
37+
String headerValue = originalHeaders.get(originalHeaderName);
38+
if (headerValue != null) {
39+
sanitizedHeadersBuilder.set(originalHeaderName, headerValue);
40+
}
41+
}
42+
}
43+
44+
return sanitizedHeadersBuilder.build();
45+
}
46+
47+
private static boolean isSensitiveKey(@NotNull String key) {
48+
return SENSITIVE_KEYS.contains(key.toLowerCase());
49+
}
50+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.box.sdk;
2+
3+
import static org.hamcrest.MatcherAssert.assertThat;
4+
import static org.hamcrest.Matchers.is;
5+
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
import okhttp3.Headers;
9+
import org.junit.Test;
10+
11+
public class BoxSensitiveDataSanitizerTest {
12+
@Test
13+
public void removeSensitiveDataFromHeaders() {
14+
Map<String, String> headersMap = new HashMap<>();
15+
headersMap.put("authorization", "token");
16+
headersMap.put("user-agent", "java-sdk");
17+
18+
Headers headers = Headers.of(headersMap);
19+
Headers sanitizedHeaders = BoxSensitiveDataSanitizer.sanitizeHeaders(headers);
20+
21+
assertThat(sanitizedHeaders.size(), is(2));
22+
assertThat(sanitizedHeaders.get("authorization"), is("[REDACTED]"));
23+
assertThat(sanitizedHeaders.get("user-agent"), is("java-sdk"));
24+
}
25+
26+
@Test
27+
public void removeAllHeadersWhenOnlySensitiveData() {
28+
Map<String, String> headersMap = new HashMap<>();
29+
headersMap.put("authorization", "token");
30+
headersMap.put("password", "123");
31+
32+
Headers headers = Headers.of(headersMap);
33+
Headers sanitizedHeaders = BoxSensitiveDataSanitizer.sanitizeHeaders(headers);
34+
35+
assertThat(sanitizedHeaders.size(), is(2));
36+
assertThat(sanitizedHeaders.get("authorization"), is("[REDACTED]"));
37+
assertThat(sanitizedHeaders.get("password"), is("[REDACTED]"));
38+
}
39+
40+
@Test
41+
public void removeSensitiveDataFromHeadersWhenUppercase() {
42+
Map<String, String> headersMap = new HashMap<>();
43+
headersMap.put("Authorization", "token");
44+
headersMap.put("user-agent", "java-sdk");
45+
46+
Headers headers = Headers.of(headersMap);
47+
Headers sanitizedHeaders = BoxSensitiveDataSanitizer.sanitizeHeaders(headers);
48+
49+
assertThat(sanitizedHeaders.size(), is(2));
50+
assertThat(sanitizedHeaders.get("Authorization"), is("[REDACTED]"));
51+
assertThat(sanitizedHeaders.get("user-agent"), is("java-sdk"));
52+
}
53+
54+
@Test
55+
public void headersNotRemovedWhenNoSensitiveData() {
56+
Map<String, String> headersMap = new HashMap<>();
57+
headersMap.put("accept", "application/json");
58+
headersMap.put("user-agent", "java-sdk");
59+
60+
Headers headers = Headers.of(headersMap);
61+
Headers sanitizedHeaders = BoxSensitiveDataSanitizer.sanitizeHeaders(headers);
62+
63+
assertThat(sanitizedHeaders.size(), is(2));
64+
assertThat(sanitizedHeaders.get("accept"), is("application/json"));
65+
assertThat(sanitizedHeaders.get("user-agent"), is("java-sdk"));
66+
}
67+
68+
@Test
69+
public void returnEmptyHeadersWhenEmptyHeadersPassed() {
70+
Headers headers = Headers.of(new HashMap<>());
71+
Headers sanitizedHeaders = BoxSensitiveDataSanitizer.sanitizeHeaders(headers);
72+
73+
assertThat(sanitizedHeaders.size(), is(0));
74+
}
75+
76+
@Test
77+
public void sanitizeAddedKeys() {
78+
Map<String, String> headersMap = new HashMap<>();
79+
headersMap.put("x-auth", "token");
80+
81+
Headers headers = Headers.of(headersMap);
82+
BoxSensitiveDataSanitizer.addKeyToSanitize("x-auth");
83+
Headers sanitizedHeaders = BoxSensitiveDataSanitizer.sanitizeHeaders(headers);
84+
85+
assertThat(sanitizedHeaders.size(), is(1));
86+
assertThat(sanitizedHeaders.get("x-auth"), is("[REDACTED]"));
87+
}
88+
}

0 commit comments

Comments
 (0)