Skip to content

Commit 4592a76

Browse files
committed
fix: remove sensitive data when BoxAPIException logs request
1 parent ed82a13 commit 4592a76

File tree

3 files changed

+137
-1
lines changed

3 files changed

+137
-1
lines changed

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import okhttp3.OkHttpClient;
3535
import okhttp3.Request;
3636
import okhttp3.Response;
37+
import okhttp3.Headers;
3738

3839
/**
3940
* Represents an authenticated connection to the Box API.
@@ -1265,7 +1266,7 @@ 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" + toSanitizedRequest(request), e);
12691270
}
12701271
}
12711272

@@ -1298,4 +1299,12 @@ protected enum ResourceLinkType {
12981299
*/
12991300
SharedLink
13001301
}
1302+
1303+
private Request toSanitizedRequest(Request originalRequest) {
1304+
Headers sanitizedHeaders = BoxSensitiveDataSanitizer.sanitizeHeaders(originalRequest.headers());
1305+
1306+
return originalRequest.newBuilder()
1307+
.headers(sanitizedHeaders)
1308+
.build();
1309+
}
13011310
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.box.sdk;
2+
3+
import okhttp3.Headers;
4+
5+
import java.util.Set;
6+
import java.util.HashSet;
7+
import java.util.Arrays;
8+
9+
class BoxSensitiveDataSanitizer {
10+
private static final Set<String> sensitiveKeys = new HashSet<>(Arrays.asList(
11+
"authorization",
12+
"access_token",
13+
"refresh_token",
14+
"subject_token",
15+
"token",
16+
"client_id",
17+
"client_secret",
18+
"code",
19+
"shared_link",
20+
"download_url",
21+
"jwt_private_key",
22+
"jwt_private_key_passphrase",
23+
"password"
24+
));
25+
26+
public static Headers sanitizeHeaders(Headers originalHeaders) {
27+
Headers.Builder sanitizedHeadersBuilder = originalHeaders.newBuilder();
28+
29+
for (String originalHeaderName : originalHeaders.names()) {
30+
if (isSensitiveKey(originalHeaderName)) {
31+
sanitizedHeadersBuilder.set(originalHeaderName, "[REDACTED]");
32+
} else {
33+
String headerValue = originalHeaders.get(originalHeaderName);
34+
if(headerValue != null) {
35+
sanitizedHeadersBuilder.set(originalHeaderName, headerValue);
36+
}
37+
}
38+
}
39+
40+
return sanitizedHeadersBuilder.build();
41+
}
42+
43+
private static boolean isSensitiveKey(String key) {
44+
return sensitiveKeys.contains(key.toLowerCase());
45+
}
46+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.box.sdk;
2+
3+
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
4+
import static org.hamcrest.MatcherAssert.assertThat;
5+
import static org.hamcrest.Matchers.is;
6+
import com.github.tomakehurst.wiremock.junit.WireMockRule;
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
10+
import okhttp3.Headers;
11+
import org.junit.Rule;
12+
import org.junit.Test;
13+
14+
public class BoxSensitiveDataSanitizerTest {
15+
@Rule
16+
public WireMockRule wireMockRule = new WireMockRule(wireMockConfig().dynamicHttpsPort().httpDisabled(true));
17+
18+
@Test
19+
public void removeSensitiveDataFromHeaders() {
20+
Map<String, String> headersMap = new HashMap<>();
21+
headersMap.put("authorization", "token");
22+
headersMap.put("user-agent", "java-sdk");
23+
24+
Headers headers = Headers.of(headersMap);
25+
Headers sanitizedHeaders = BoxSensitiveDataSanitizer.sanitizeHeaders(headers);
26+
27+
assertThat(sanitizedHeaders.size(), is(2));
28+
assertThat(sanitizedHeaders.get("authorization"), is("[REDACTED]"));
29+
assertThat(sanitizedHeaders.get("user-agent"), is("java-sdk"));
30+
}
31+
32+
@Test
33+
public void removeAllHeadersWhenOnlySensitiveData() {
34+
Map<String, String> headersMap = new HashMap<>();
35+
headersMap.put("authorization", "token");
36+
headersMap.put("password", "123");
37+
38+
Headers headers = Headers.of(headersMap);
39+
Headers sanitizedHeaders = BoxSensitiveDataSanitizer.sanitizeHeaders(headers);
40+
41+
assertThat(sanitizedHeaders.size(), is(2));
42+
assertThat(sanitizedHeaders.get("authorization"), is("[REDACTED]"));
43+
assertThat(sanitizedHeaders.get("password"), is("[REDACTED]"));
44+
}
45+
46+
@Test
47+
public void removeSensitiveDataFromHeadersWhenUppercase() {
48+
Map<String, String> headersMap = new HashMap<>();
49+
headersMap.put("Authorization", "token");
50+
headersMap.put("user-agent", "java-sdk");
51+
52+
Headers headers = Headers.of(headersMap);
53+
Headers sanitizedHeaders = BoxSensitiveDataSanitizer.sanitizeHeaders(headers);
54+
55+
assertThat(sanitizedHeaders.size(), is(2));
56+
assertThat(sanitizedHeaders.get("Authorization"), is("[REDACTED]"));
57+
assertThat(sanitizedHeaders.get("user-agent"), is("java-sdk"));
58+
}
59+
60+
@Test
61+
public void headersNotRemovedWhenNoSensitiveData() {
62+
Map<String, String> headersMap = new HashMap<>();
63+
headersMap.put("accept", "application/json");
64+
headersMap.put("user-agent", "java-sdk");
65+
66+
Headers headers = Headers.of(headersMap);
67+
Headers sanitizedHeaders = BoxSensitiveDataSanitizer.sanitizeHeaders(headers);
68+
69+
assertThat(sanitizedHeaders.size(), is(2));
70+
assertThat(sanitizedHeaders.get("accept"), is("application/json"));
71+
assertThat(sanitizedHeaders.get("user-agent"), is("java-sdk"));
72+
}
73+
74+
@Test
75+
public void returnEmptyHeadersWhenEmptyHeadersPassed() {
76+
Headers headers = Headers.of(new HashMap<>());
77+
Headers sanitizedHeaders = BoxSensitiveDataSanitizer.sanitizeHeaders(headers);
78+
79+
assertThat(sanitizedHeaders.size(), is(0));
80+
}
81+
}

0 commit comments

Comments
 (0)