Skip to content

Commit 36593fe

Browse files
committed
#16 - Obfuscate Authorization header and suppress logging payloads for AuthToken request and via request.suppressLogging()
1 parent 17a7ae3 commit 36593fe

File tree

7 files changed

+90
-3
lines changed

7 files changed

+90
-3
lines changed

client/src/main/java/io/avaje/http/client/DHttpClientContext.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313

1414
class DHttpClientContext implements HttpClientContext {
1515

16+
/**
17+
* HTTP Authorization header.
18+
*/
19+
static final String AUTHORIZATION = "Authorization";
20+
private static final String BEARER = "Bearer ";
21+
1622
private final HttpClient httpClient;
1723
private final String baseUrl;
1824
private final Duration requestTimeout;
@@ -172,7 +178,7 @@ void afterResponse(DHttpClientRequest request) {
172178

173179
void beforeRequest(DHttpClientRequest request) {
174180
if (withAuthToken && !request.isSkipAuthToken()) {
175-
request.header("Authorization", "Bearer " + authToken());
181+
request.header(AUTHORIZATION, BEARER + authToken());
176182
}
177183
if (requestIntercept != null) {
178184
requestIntercept.beforeRequest(request);

client/src/main/java/io/avaje/http/client/DHttpClientRequest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class DHttpClientRequest implements HttpClientRequest, HttpClientResponse {
4848
private BodyContent encodedResponseBody;
4949
private boolean loggableResponseBody;
5050
private boolean skipAuthToken;
51+
private boolean suppressLogging;
5152

5253
DHttpClientRequest(DHttpClientContext context, Duration requestTimeout) {
5354
this.context = context;
@@ -58,6 +59,13 @@ class DHttpClientRequest implements HttpClientRequest, HttpClientResponse {
5859
@Override
5960
public HttpClientRequest skipAuthToken() {
6061
this.skipAuthToken = true;
62+
this.suppressLogging = true;
63+
return this;
64+
}
65+
66+
@Override
67+
public HttpClientRequest suppressLogging() {
68+
this.suppressLogging = true;
6169
return this;
6270
}
6371

@@ -471,6 +479,9 @@ public HttpRequest request() {
471479

472480
@Override
473481
public String requestBody() {
482+
if (suppressLogging) {
483+
return "<suppressed request body>";
484+
}
474485
if (encodedRequestBody != null) {
475486
return new String(encodedRequestBody.content(), StandardCharsets.UTF_8);
476487
} else if (bodyFormEncoded) {
@@ -485,6 +496,9 @@ public String requestBody() {
485496

486497
@Override
487498
public String responseBody() {
499+
if (suppressLogging) {
500+
return "<suppressed response body>";
501+
}
488502
if (encodedResponseBody != null) {
489503
return new String(encodedResponseBody.content(), StandardCharsets.UTF_8);
490504
} else if (httpResponse != null && loggableResponseBody) {

client/src/main/java/io/avaje/http/client/HttpClientRequest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ public interface HttpClientRequest {
3434
*/
3535
HttpClientRequest skipAuthToken();
3636

37+
/**
38+
* For this request suppress payload logging.
39+
* <p>
40+
* The payload contains sensitive content and the request and response content
41+
* should be suppressed and not included in request logging.
42+
*/
43+
HttpClientRequest suppressLogging();
44+
3745
/**
3846
* Set the request timeout to use for this request. When not set the default
3947
* request timeout will be used.

client/src/main/java/io/avaje/http/client/RequestListener.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ interface Event {
5050
* This will return null if the response is not String or byte array
5151
* encoded string content. For example, when requests use response
5252
* handlers for InputStream, Path, Stream etc this will return null.
53-
* <p>
5453
*/
5554
String responseBody();
5655

client/src/main/java/io/avaje/http/client/RequestLogger.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,17 @@ private void headers(StringBuilder sb, String label, HttpHeaders headers) {
6161
if (!entries.isEmpty()) {
6262
sb.append(delimiter).append(label);
6363
for (Map.Entry<String, List<String>> entry : entries) {
64-
sb.append(entry.getKey()).append("=").append(entry.getValue()).append(", ");
64+
final String key = entry.getKey();
65+
if (obfuscate(key)) {
66+
sb.append(key).append("=<obfuscated>, ");
67+
} else {
68+
sb.append(key).append("=").append(entry.getValue()).append(", ");
69+
}
6570
}
6671
}
6772
}
73+
74+
boolean obfuscate(String key) {
75+
return DHttpClientContext.AUTHORIZATION.equals(key);
76+
}
6877
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package io.avaje.http.client;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import java.time.Duration;
6+
7+
import static org.assertj.core.api.Assertions.assertThat;
8+
import static org.mockito.Mockito.mock;
9+
10+
class DHttpClientRequestTest {
11+
12+
@Test
13+
void suppressLogging_listenerEvent_expect_suppressedPayloadContent() {
14+
15+
final DHttpClientRequest request = new DHttpClientRequest(mock(DHttpClientContext.class), Duration.ZERO);
16+
17+
request.suppressLogging();
18+
final RequestListener.Event event = request.listenerEvent();
19+
20+
assertThat(event.requestBody()).isEqualTo("<suppressed request body>");
21+
assertThat(event.responseBody()).isEqualTo("<suppressed response body>");
22+
}
23+
24+
@Test
25+
void skipAuthToken_listenerEvent_expect_suppressedPayloadContent() {
26+
27+
final DHttpClientRequest request = new DHttpClientRequest(mock(DHttpClientContext.class), Duration.ZERO);
28+
29+
request.skipAuthToken();
30+
final RequestListener.Event event = request.listenerEvent();
31+
32+
assertThat(event.requestBody()).isEqualTo("<suppressed request body>");
33+
assertThat(event.responseBody()).isEqualTo("<suppressed response body>");
34+
}
35+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.avaje.http.client;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import static org.junit.jupiter.api.Assertions.*;
6+
7+
class RequestLoggerTest {
8+
9+
private final RequestLogger requestLogger = new RequestLogger();
10+
11+
@Test
12+
void obfuscate() {
13+
assertTrue(requestLogger.obfuscate("Authorization"));
14+
assertFalse(requestLogger.obfuscate("Foo"));
15+
}
16+
}

0 commit comments

Comments
 (0)