Skip to content

Commit e8ab42a

Browse files
committed
Logging content type on invalid version for debugging IM-1827
1 parent d6f864d commit e8ab42a

File tree

2 files changed

+213
-5
lines changed

2 files changed

+213
-5
lines changed

src/main/java/com/uid2/operator/service/V2RequestUtil.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,22 +57,32 @@ public boolean isValid() {
5757
private static final Logger LOGGER = LoggerFactory.getLogger(V2RequestUtil.class);
5858

5959
public static V2Request parseRequest(RoutingContext rc, ClientKey ck, IClock clock) {
60+
String contentType = rc.request().getHeader(HttpHeaders.CONTENT_TYPE);
6061
if (rc.request().headers().contains(HttpHeaders.CONTENT_TYPE, HttpMediaType.APPLICATION_OCTET_STREAM.getType(), true)) {
61-
return V2RequestUtil.parseRequestAsBuffer(rc.body().buffer(), ck, clock);
62+
return V2RequestUtil.parseRequestAsBuffer(rc.body().buffer(), ck, clock, contentType);
6263
} else {
63-
return V2RequestUtil.parseRequestAsString(rc.body().asString(), ck, clock);
64+
return V2RequestUtil.parseRequestAsString(rc.body().asString(), ck, clock, contentType);
6465
}
6566
}
6667

6768
public static V2Request parseRequestAsBuffer(Buffer bodyBuffer, ClientKey ck, IClock clock) {
69+
return parseRequestAsBuffer(bodyBuffer, ck, clock, null);
70+
}
71+
72+
public static V2Request parseRequestAsBuffer(Buffer bodyBuffer, ClientKey ck, IClock clock, String contentType) {
6873
if (bodyBuffer == null) {
6974
return new V2Request("Invalid body: Body is missing.");
7075
}
71-
return parseRequestCommon(bodyBuffer.getBytes(), ck, clock);
76+
return parseRequestCommon(bodyBuffer.getBytes(), ck, clock, contentType);
7277
}
7378

7479
// clock is passed in to test V2_REQUEST_TIMESTAMP_DRIFT_THRESHOLD_IN_MINUTES in unit tests
7580
public static V2Request parseRequestAsString(String bodyString, ClientKey ck, IClock clock) {
81+
return parseRequestAsString(bodyString, ck, clock, null);
82+
}
83+
84+
// clock is passed in to test V2_REQUEST_TIMESTAMP_DRIFT_THRESHOLD_IN_MINUTES in unit tests
85+
public static V2Request parseRequestAsString(String bodyString, ClientKey ck, IClock clock, String contentType) {
7686
if (bodyString == null) {
7787
return new V2Request("Invalid body: Body is missing.");
7888
}
@@ -82,10 +92,10 @@ public static V2Request parseRequestAsString(String bodyString, ClientKey ck, IC
8292
} catch (IllegalArgumentException ex) {
8393
return new V2Request("Invalid body: Body is not valid base64.");
8494
}
85-
return parseRequestCommon(bodyBytes, ck, clock);
95+
return parseRequestCommon(bodyBytes, ck, clock, contentType);
8696
}
8797

88-
private static V2Request parseRequestCommon(byte[] bodyBytes, ClientKey ck, IClock clock) {
98+
private static V2Request parseRequestCommon(byte[] bodyBytes, ClientKey ck, IClock clock, String contentType) {
8999
// Payload envelop format:
90100
// byte 0: version
91101
// byte 1-12: GCM IV
@@ -99,6 +109,8 @@ private static V2Request parseRequestCommon(byte[] bodyBytes, ClientKey ck, IClo
99109
}
100110

101111
if (bodyBytes[0] != VERSION) {
112+
LOGGER.warn("Version mismatch detected. Content-Type: {}",
113+
contentType != null ? contentType : "null");
102114
return new V2Request("Invalid body: Version mismatch.");
103115
}
104116

src/test/java/com/uid2/operator/V2RequestUtilTest.java

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import static org.junit.jupiter.api.Assertions.assertEquals;
3030
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
3131
import static org.mockito.Mockito.when;
32+
import org.mockito.Mockito;
3233

3334
@ExtendWith(MockitoExtension.class)
3435
@MockitoSettings(strictness = Strictness.LENIENT)
@@ -154,6 +155,201 @@ public void testParseRequestWithMalformedJson() {
154155
assertThat(memoryAppender.checkNoThrowableLogged().size()).isEqualTo(1);
155156
}
156157

158+
@Test
159+
public void testParseRequestWithVersionMismatchLogsContentType() {
160+
IClock mockClock = Mockito.mock(IClock.class);
161+
when(mockClock.now()).thenReturn(MOCK_NOW);
162+
163+
// Create a body with version 2 instead of expected version 1
164+
// Just need enough bytes to pass the MIN_PAYLOAD_LENGTH check (45 bytes)
165+
byte[] bodyBytes = new byte[45];
166+
bodyBytes[0] = 2; // Wrong version - should be 1
167+
// Fill rest with dummy data to meet minimum length requirement
168+
for (int i = 1; i < 45; i++) {
169+
bodyBytes[i] = (byte) i;
170+
}
171+
String bodyString = java.util.Base64.getEncoder().encodeToString(bodyBytes);
172+
173+
ClientKey ck = new ClientKey(
174+
"hash",
175+
"salt",
176+
"YGdzZw9oM2RzBgB8THMyAEe408lvdfsTsGteaLAGayY=",
177+
"name",
178+
"contact",
179+
MOCK_NOW,
180+
Set.of(),
181+
113,
182+
false,
183+
"key-id"
184+
);
185+
186+
// Create a new memory appender for this test
187+
Logger logger = (Logger)LoggerFactory.getLogger("com.uid2.operator.service.V2RequestUtil");
188+
MemoryAppender testAppender = new MemoryAppender();
189+
testAppender.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
190+
logger.setLevel(Level.DEBUG);
191+
logger.addAppender(testAppender);
192+
testAppender.start();
193+
194+
try {
195+
// Test with content type
196+
V2RequestUtil.V2Request res = V2RequestUtil.parseRequestAsString(bodyString, ck, mockClock, "application/json");
197+
198+
assertEquals("Invalid body: Version mismatch.", res.errorMessage);
199+
assertThat(testAppender.countEventsForLogger("com.uid2.operator.service.V2RequestUtil")).isEqualTo(1);
200+
assertThat(testAppender.search("[WARN] Version mismatch detected. Content-Type: application/json").size()).isEqualTo(1);
201+
} finally {
202+
testAppender.stop();
203+
logger.detachAppender(testAppender);
204+
}
205+
}
206+
207+
@Test
208+
public void testParseRequestWithVersionMismatchLogsUnknownContentType() {
209+
IClock mockClock = Mockito.mock(IClock.class);
210+
when(mockClock.now()).thenReturn(MOCK_NOW);
211+
212+
// Create a body with version 2 instead of expected version 1
213+
byte[] bodyBytes = new byte[45];
214+
bodyBytes[0] = 2; // Wrong version - should be 1
215+
// Fill rest with dummy data to meet minimum length requirement
216+
for (int i = 1; i < 45; i++) {
217+
bodyBytes[i] = (byte) i;
218+
}
219+
String bodyString = java.util.Base64.getEncoder().encodeToString(bodyBytes);
220+
221+
ClientKey ck = new ClientKey(
222+
"hash",
223+
"salt",
224+
"YGdzZw9oM2RzBgB8THMyAEe408lvdfsTsGteaLAGayY=",
225+
"name",
226+
"contact",
227+
MOCK_NOW,
228+
Set.of(),
229+
113,
230+
false,
231+
"key-id"
232+
);
233+
234+
// Create a new memory appender for this test
235+
Logger logger = (Logger)LoggerFactory.getLogger("com.uid2.operator.service.V2RequestUtil");
236+
MemoryAppender testAppender = new MemoryAppender();
237+
testAppender.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
238+
logger.setLevel(Level.DEBUG);
239+
logger.addAppender(testAppender);
240+
testAppender.start();
241+
242+
try {
243+
// Test with null content type
244+
V2RequestUtil.V2Request res = V2RequestUtil.parseRequestAsString(bodyString, ck, mockClock, null);
245+
246+
assertEquals("Invalid body: Version mismatch.", res.errorMessage);
247+
assertThat(testAppender.countEventsForLogger("com.uid2.operator.service.V2RequestUtil")).isEqualTo(1);
248+
assertThat(testAppender.search("[WARN] Version mismatch detected. Content-Type: null").size()).isEqualTo(1);
249+
} finally {
250+
testAppender.stop();
251+
logger.detachAppender(testAppender);
252+
}
253+
}
254+
255+
@Test
256+
public void testParseRequestWithCorrectVersionDoesNotLogVersionMismatch() {
257+
IClock mockClock = Mockito.mock(IClock.class);
258+
when(mockClock.now()).thenReturn(MOCK_NOW);
259+
260+
// Create a body with correct version 1
261+
byte[] bodyBytes = new byte[45];
262+
bodyBytes[0] = 1; // Correct version
263+
// Fill rest with dummy data to meet minimum length requirement
264+
for (int i = 1; i < 45; i++) {
265+
bodyBytes[i] = (byte) i;
266+
}
267+
String bodyString = java.util.Base64.getEncoder().encodeToString(bodyBytes);
268+
269+
ClientKey ck = new ClientKey(
270+
"hash",
271+
"salt",
272+
"YGdzZw9oM2RzBgB8THMyAEe408lvdfsTsGteaLAGayY=",
273+
"name",
274+
"contact",
275+
MOCK_NOW,
276+
Set.of(),
277+
113,
278+
false,
279+
"key-id"
280+
);
281+
282+
// Create a new memory appender for this test
283+
Logger logger = (Logger)LoggerFactory.getLogger("com.uid2.operator.service.V2RequestUtil");
284+
MemoryAppender testAppender = new MemoryAppender();
285+
testAppender.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
286+
logger.setLevel(Level.DEBUG);
287+
logger.addAppender(testAppender);
288+
testAppender.start();
289+
290+
try {
291+
// Test with content type - should not log version mismatch since version is correct
292+
V2RequestUtil.V2Request res = V2RequestUtil.parseRequestAsString(bodyString, ck, mockClock, "application/json");
293+
294+
// Should fail with decryption error, not version mismatch
295+
assertThat(res.errorMessage).contains("Check encryption key");
296+
// Should have no version mismatch log entries
297+
assertThat(testAppender.search("Version mismatch detected").size()).isEqualTo(0);
298+
} finally {
299+
testAppender.stop();
300+
logger.detachAppender(testAppender);
301+
}
302+
}
303+
304+
@Test
305+
public void testParseRequestWithCorrectVersionAndNullContentTypeDoesNotLogVersionMismatch() {
306+
IClock mockClock = Mockito.mock(IClock.class);
307+
when(mockClock.now()).thenReturn(MOCK_NOW);
308+
309+
// Create a body with correct version 1
310+
byte[] bodyBytes = new byte[45];
311+
bodyBytes[0] = 1; // Correct version
312+
// Fill rest with dummy data to meet minimum length requirement
313+
for (int i = 1; i < 45; i++) {
314+
bodyBytes[i] = (byte) i;
315+
}
316+
String bodyString = java.util.Base64.getEncoder().encodeToString(bodyBytes);
317+
318+
ClientKey ck = new ClientKey(
319+
"hash",
320+
"salt",
321+
"YGdzZw9oM2RzBgB8THMyAEe408lvdfsTsGteaLAGayY=",
322+
"name",
323+
"contact",
324+
MOCK_NOW,
325+
Set.of(),
326+
113,
327+
false,
328+
"key-id"
329+
);
330+
331+
// Create a new memory appender for this test
332+
Logger logger = (Logger)LoggerFactory.getLogger("com.uid2.operator.service.V2RequestUtil");
333+
MemoryAppender testAppender = new MemoryAppender();
334+
testAppender.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
335+
logger.setLevel(Level.DEBUG);
336+
logger.addAppender(testAppender);
337+
testAppender.start();
338+
339+
try {
340+
// Test with null content type - should not log version mismatch since version is correct
341+
V2RequestUtil.V2Request res = V2RequestUtil.parseRequestAsString(bodyString, ck, mockClock, null);
342+
343+
// Should fail with decryption error, not version mismatch
344+
assertThat(res.errorMessage).contains("Check encryption key");
345+
// Should have no version mismatch log entries
346+
assertThat(testAppender.search("Version mismatch detected").size()).isEqualTo(0);
347+
} finally {
348+
testAppender.stop();
349+
logger.detachAppender(testAppender);
350+
}
351+
}
352+
157353
@Test
158354
public void testHandleRefreshTokenInResponseBody() {
159355
when(keyManager.getRefreshKey()).thenReturn(refreshKey);

0 commit comments

Comments
 (0)