Skip to content

Commit 6e5dce9

Browse files
authored
Merge pull request #1922 from IABTechLab/vse-IM-1827-fallback-to-base64-decode-if-binary-decode-fails
Fallback to base64 decode is binary decode fails
2 parents fbcf4e3 + 8b9e327 commit 6e5dce9

3 files changed

Lines changed: 65 additions & 4 deletions

File tree

pom.xml

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

77
<groupId>com.uid2</groupId>
88
<artifactId>uid2-operator</artifactId>
9-
<version>5.56.49</version>
9+
<version>5.56.49-alpha-204-SNAPSHOT</version>
1010

1111
<properties>
1212
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,31 @@ public boolean isValid() {
5858

5959
public static V2Request parseRequest(RoutingContext rc, ClientKey ck, IClock clock) {
6060
if (rc.request().headers().contains(HttpHeaders.CONTENT_TYPE, HttpMediaType.APPLICATION_OCTET_STREAM.getType(), true)) {
61-
return V2RequestUtil.parseRequestAsBuffer(rc.body().buffer(), ck, clock);
61+
V2Request requestAsBuffer = V2RequestUtil.parseRequestAsBuffer(rc.body().buffer(), ck, clock);
62+
63+
if (requestAsBuffer.isValid()) {
64+
// If the binary request is valid, use the binary request buffer
65+
return requestAsBuffer;
66+
} else {
67+
RoutingContextReader rcReader = new RoutingContextReader(rc);
68+
69+
// If the binary request is invalid, try to parse it as a base64 encoded string
70+
V2Request requestAsString = V2RequestUtil.parseRequestAsString(rc.body().asString(), ck, clock);
71+
if (requestAsString.isValid()) {
72+
// TODO: Delete this log line after fix is verified
73+
LOGGER.info("Fallback successful for {}, site ID: {}", rcReader.getContact(), rcReader.getSiteId());
74+
75+
// If the base64 request is valid, set the request content type to text/plain, use the base64 request string
76+
rc.request().headers().set(HttpHeaders.CONTENT_TYPE, HttpMediaType.TEXT_PLAIN.getType());
77+
return requestAsString;
78+
} else {
79+
// TODO: Delete this log line after fix is verified
80+
LOGGER.info("Fallback failed for {}, site ID: {}", rcReader.getContact(), rcReader.getSiteId());
81+
82+
// If both binary and base64 requests are invalid, return the original binary request buffer error
83+
return requestAsBuffer;
84+
}
85+
}
6286
} else {
6387
return V2RequestUtil.parseRequestAsString(rc.body().asString(), ck, clock);
6488
}

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

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -461,10 +461,14 @@ private void post(Vertx vertx, String endpoint, JsonObject body, Handler<AsyncRe
461461
}
462462

463463
private void postV2(ClientKey ck, Vertx vertx, String endpoint, JsonObject body, long nonce, String referer, Handler<AsyncResult<HttpResponse<Buffer>>> handler) {
464-
postV2(ck, vertx, endpoint, body, nonce, referer, handler, Collections.emptyMap());
464+
postV2(ck, vertx, endpoint, body, nonce, referer, handler, Collections.emptyMap(), false);
465465
}
466466

467467
private void postV2(ClientKey ck, Vertx vertx, String endpoint, JsonObject body, long nonce, String referer, Handler<AsyncResult<HttpResponse<Buffer>>> handler, Map<String, String> additionalHeaders) {
468+
postV2(ck, vertx, endpoint, body, nonce, referer, handler, additionalHeaders, false);
469+
}
470+
471+
private void postV2(ClientKey ck, Vertx vertx, String endpoint, JsonObject body, long nonce, String referer, Handler<AsyncResult<HttpResponse<Buffer>>> handler, Map<String, String> additionalHeaders, boolean forceBase64RequestBody) {
468472
WebClient client = WebClient.create(vertx);
469473
final String apiKey = ck == null ? "" : clientKey;
470474
HttpRequest<Buffer> request = client.postAbs(getUrlForEndpoint(endpoint))
@@ -492,7 +496,7 @@ private void postV2(ClientKey ck, Vertx vertx, String endpoint, JsonObject body,
492496
request.putHeader("Referer", referer);
493497
}
494498

495-
if (request.headers().contains(HttpHeaders.CONTENT_TYPE.toString(), HttpMediaType.APPLICATION_OCTET_STREAM.getType(), true)) {
499+
if (request.headers().contains(HttpHeaders.CONTENT_TYPE.toString(), HttpMediaType.APPLICATION_OCTET_STREAM.getType(), true) && !forceBase64RequestBody) {
496500
request.sendBuffer(bufBody, handler);
497501
} else {
498502
request.sendBuffer(Buffer.buffer(Utils.toBase64String(bufBody.getBytes()).getBytes(StandardCharsets.UTF_8)), handler);
@@ -962,6 +966,39 @@ void identityMapNewClientNoPolicySpecified(String apiVersion, String contentType
962966
}, Map.of(HttpHeaders.CONTENT_TYPE.toString(), contentType));
963967
}
964968

969+
@Test
970+
void fallbackToBase64DecodingIfBinaryEnvelopeDecodeFails(Vertx vertx, VertxTestContext testContext) {
971+
final int clientSiteId = 201;
972+
fakeAuth(clientSiteId, newClientCreationDateTime, Role.MAPPER);
973+
setupSalts();
974+
setupKeys();
975+
ClientKey ck = (ClientKey) clientKeyProvider.get("");
976+
long nonce = new BigInteger(Random.getBytes(8)).longValue();
977+
978+
JsonObject req = new JsonObject();
979+
JsonArray emails = new JsonArray();
980+
req.put("email", emails);
981+
emails.add("test1@uid2.com");
982+
983+
postV2(ck, vertx, "v2/identity/map", req, nonce, null, ar -> {
984+
assertTrue(ar.succeeded());
985+
assertEquals(200, ar.result().statusCode());
986+
987+
byte[] byteResp = Utils.decodeBase64String(ar.result().bodyAsString());
988+
byte[] decrypted = AesGcm.decrypt(byteResp, 0, ck.getSecretBytes());
989+
990+
JsonObject respJson = new JsonObject(new String(decrypted, 16, decrypted.length - 16, StandardCharsets.UTF_8));
991+
assertEquals("success", respJson.getString("status"));
992+
993+
// Check that response content type is text/plain
994+
assertEquals(HttpMediaType.TEXT_PLAIN.getType(), ar.result().getHeader(HttpHeaders.CONTENT_TYPE.toString()));
995+
996+
testContext.completeNow();
997+
998+
// Set request content type header to application/octet-stream, but force a base64 encoded request envelope
999+
}, Map.of(HttpHeaders.CONTENT_TYPE.toString(), "application/octet-stream"), true);
1000+
}
1001+
9651002
@ParameterizedTest
9661003
@MethodSource("versionAndPolicy")
9671004
void identityMapNewClientWrongPolicySpecified(String apiVersion, String policyParameterKey, Vertx vertx, VertxTestContext testContext) {

0 commit comments

Comments
 (0)