Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.uid2</groupId>
<artifactId>uid2-core</artifactId>
<version>2.20.0</version>
<version>2.20.1-alpha-50-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand All @@ -24,7 +24,7 @@
<vertx.verticle>com.uid2.core.vertx.CoreVerticle</vertx.verticle>
<launcher.class>io.vertx.core.Launcher</launcher.class>

<uid2-shared.version>7.19.0</uid2-shared.version>
<uid2-shared.version>7.20.0</uid2-shared.version>
<image.version>${project.version}</image.version>
</properties>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.uid2.core.handler;

import com.uid2.core.Const;
import com.uid2.core.vertx.AttestationFailureReason;
import com.uid2.shared.auth.IAuthorizable;
import com.uid2.shared.auth.OperatorKey;
import com.uid2.shared.middleware.AuthMiddleware;
import com.uid2.shared.secure.AttestationFailure;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.core.net.SocketAddress;
Expand Down Expand Up @@ -40,14 +40,14 @@ private void logAttestationFailure(RoutingContext context) {
return;
}

final AttestationFailureReason attestationFailureReason = context.get(Const.RoutingContextData.ATTESTATION_FAILURE_REASON_PROP);
final AttestationFailure attestationFailure = context.get(Const.RoutingContextData.ATTESTATION_FAILURE_REASON_PROP);
final String attestationFailureDataJson = getAttestationFailureDataJson(context);

final String originatingIpAddress = getOriginatingIpAddress(context);

LOG.warn("Attestation failed. StatusCode={} Reason={} Data={} OperatorKeyHash={} OperatorKeyName={} SiteId={} Protocol={} OperatorType={} OriginatingIpAddress={}",
context.response().getStatusCode(),
attestationFailureReason,
attestationFailure,
attestationFailureDataJson,
operatorKey.getKeyHash(),
operatorKey.getName(),
Expand Down
29 changes: 0 additions & 29 deletions src/main/java/com/uid2/core/vertx/AttestationFailureReason.java

This file was deleted.

69 changes: 46 additions & 23 deletions src/main/java/com/uid2/core/vertx/CoreVerticle.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import java.security.spec.X509EncodedKeySpec;
import java.time.Instant;
import java.util.*;

import com.uid2.shared.store.reader.RotatingS3KeyProvider;
import com.uid2.shared.model.S3Key;

Expand Down Expand Up @@ -78,7 +79,6 @@ public class CoreVerticle extends AbstractVerticle {
private final ISaltMetadataProvider saltMetadataProvider;
private final IPartnerMetadataProvider partnerMetadataProvider;
private final OperatorJWTTokenProvider operatorJWTTokenProvider;
private final JwtService jwtService;
private final RotatingS3KeyProvider s3KeyProvider;

public CoreVerticle(ICloudStorage cloudStorage,
Expand All @@ -96,7 +96,6 @@ public CoreVerticle(ICloudStorage cloudStorage,

this.attestationService = attestationService;
this.attestationTokenService = attestationTokenService;
this.jwtService = jwtService;
this.enclaveIdentifierProvider = enclaveIdentifierProvider;
this.enclaveIdentifierProvider.addListener(this.attestationService);
this.s3KeyProvider = s3KeyProvider;
Expand All @@ -108,7 +107,7 @@ public CoreVerticle(ICloudStorage cloudStorage,
enforceJwt = false;
}

this.attestationMiddleware = new AttestationMiddleware(this.attestationTokenService, this.jwtService, jwtAudience, jwtIssuer, enforceJwt);
this.attestationMiddleware = new AttestationMiddleware(this.attestationTokenService, jwtService, jwtAudience, jwtIssuer, enforceJwt);

this.auth = new AuthMiddleware(authProvider);

Expand Down Expand Up @@ -225,15 +224,15 @@ private void handleAttestAsync(RoutingContext rc) {
try {
json = rc.body().asJsonObject();
} catch (DecodeException e) {
setAttestationFailureReason(rc, AttestationFailureReason.REQUEST_BODY_IS_NOT_VALID_JSON);
setAttestationFailureReason(rc, AttestationFailure.BAD_PAYLOAD, Collections.singletonMap("cause", AttestationFailure.BAD_PAYLOAD.explain()));
Error("request body is not a valid json", 400, rc, null);
return;
}

String request = json == null ? null : json.getString("attestation_request");

if (request == null || request.isEmpty()) {
setAttestationFailureReason(rc, AttestationFailureReason.NO_ATTESTATION_REQUEST_ATTACHED);
setAttestationFailureReason(rc, AttestationFailure.BAD_PAYLOAD, Collections.singletonMap("cause", AttestationFailure.BAD_PAYLOAD.explain()));
Error("no attestation_request attached", 400, rc, null);
return;
}
Expand All @@ -243,22 +242,44 @@ private void handleAttestAsync(RoutingContext rc) {
try {
attestationService.attest(protocol, request, clientPublicKey, ar -> {
if (!ar.succeeded()) {
setAttestationFailureReason(rc, AttestationFailureReason.ATTESTATION_FAILURE, Collections.singletonMap("cause", ar.cause().getMessage()));
if (ar.cause() instanceof AttestationClientException ace && ace.IsClientError()) {
setAttestationFailureReason(rc, ace.getAttestationFailure(), Collections.singletonMap("reason", ace.getAttestationFailure().explain()));
logger.warn("attestation failure: ", ace);
Error("attestation failure", 400, rc, ace.getAttestationFailure().explain());
return;
}

// 500 is only for unknown errors in the attestation processing
setAttestationFailureReason(rc, AttestationFailure.INTERNAL_ERROR, Collections.singletonMap("cause", ar.cause().getMessage()));
logger.warn("attestation failure: ", ar.cause());
Error("attestation failure", 500, rc, null);
return;
}

final AttestationResult attestationResult = ar.result();
if (!attestationResult.isSuccess()) {
setAttestationFailureReason(rc, AttestationFailureReason.ATTESTATION_FAILURE, Collections.singletonMap("reason", attestationResult.getReason()));
Error(attestationResult.getReason(), 401, rc, null);
return;
AttestationFailure failure = attestationResult.getFailure();
switch (failure) {
case AttestationFailure.BAD_FORMAT:
case AttestationFailure.INVALID_PROTOCOL:
case AttestationFailure.BAD_CERTIFICATE:
case AttestationFailure.BAD_PAYLOAD:
case AttestationFailure.UNKNOWN_ATTESTATION_URL:
case AttestationFailure.FORBIDDEN_ENCLAVE:
setAttestationFailureReason(rc, failure, Collections.singletonMap("reason", attestationResult.getReason()));
Error(attestationResult.getReason(), 403, rc, failure.explain());
return;
case AttestationFailure.UNKNOWN:
case AttestationFailure.INTERNAL_ERROR:
setAttestationFailureReason(rc, failure, Collections.singletonMap("reason", attestationResult.getReason()));
Error(attestationResult.getReason(), 500, rc, failure.explain());
return;
}
}

if (json.containsKey("operator_type") && !operator.getOperatorType().name().equalsIgnoreCase(json.getString("operator_type"))) {
setAttestationFailureReason(rc, AttestationFailureReason.ATTESTATION_FAILURE);
Error("attestation failure; invalid operator type", 400, rc, null);
setAttestationFailureReason(rc, AttestationFailure.INVALID_TYPE, Collections.singletonMap("reason", AttestationFailure.INVALID_TYPE.explain()));
Error("attestation failure; invalid operator type", 403, rc, null);
return;
}

Expand Down Expand Up @@ -294,16 +315,16 @@ private void handleAttestAsync(RoutingContext rc) {
}
}
} catch (Exception e) {
Error("attestation failure", 500, rc, null);
Error("attestation failure", 500, rc, AttestationFailure.INTERNAL_ERROR.explain());
return;
}

logger.info("attestation successful for SiteId: {}, Operator name: {}, protocol: {}", operator.getSiteId(), operator.getName(), protocol);
Success(rc, responseObj);
});
} catch (AttestationService.NotFound e) {
setAttestationFailureReason(rc, AttestationFailureReason.INVALID_PROTOCOL);
Error("protocol not found", 500, rc, null);
setAttestationFailureReason(rc, AttestationFailure.INVALID_PROTOCOL, Collections.singletonMap("cause", AttestationFailure.INVALID_PROTOCOL.explain()));
Error("protocol not found", 403, rc, null);
}
}

Expand All @@ -316,7 +337,7 @@ private static String encodeAttestationToken(RoutingContext rc, AttestationResul
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(encodedAttestationToken.getBytes(StandardCharsets.UTF_8)));
} catch (Exception e) {
setAttestationFailureReason(rc, AttestationFailureReason.RESPONSE_ENCRYPTION_EXCEPTION, Collections.singletonMap("exception", e.getMessage()));
setAttestationFailureReason(rc, AttestationFailure.RESPONSE_ENCRYPTION_ERROR, Collections.singletonMap("exception", e.getMessage()));
logger.warn("attestation failure: exception while encrypting response", e);
throw e;
}
Expand All @@ -333,10 +354,9 @@ private Map.Entry<String, String> getJWTTokens(RoutingContext rc, IAuthorizable
String optOutJwtToken = this.operatorJWTTokenProvider.getOptOutJWTToken(operator.getKeyHash(), operator.getName(), operator.getRoles(), operator.getSiteId(), enclaveId, operator.getProtocol(), clientVersion, expiresAt);
String coreJwtToken = this.operatorJWTTokenProvider.getCoreJWTToken(operator.getKeyHash(), operator.getName(), operator.getRoles(), operator.getSiteId(), enclaveId, operator.getProtocol(), clientVersion, expiresAt);

Map.Entry<String, String> tokens = new AbstractMap.SimpleEntry<>(optOutJwtToken, coreJwtToken);
return tokens;
return new AbstractMap.SimpleEntry<>(optOutJwtToken, coreJwtToken);
} catch (JWTTokenProvider.JwtSigningException e) {
setAttestationFailureReason(rc, AttestationFailureReason.INTERNAL_ERROR, Collections.singletonMap("exception", e.getMessage()));
setAttestationFailureReason(rc, AttestationFailure.INTERNAL_ERROR, Collections.singletonMap("exception", e.getMessage()));
logger.error("OptOut JWT token generation failed", e);
throw e;
}
Expand All @@ -346,11 +366,11 @@ private Map.Entry<String, String> getJWTTokens(RoutingContext rc, IAuthorizable
return null;
}

private static void setAttestationFailureReason(RoutingContext context, AttestationFailureReason reason) {
private static void setAttestationFailureReason(RoutingContext context, AttestationFailure reason) {
setAttestationFailureReason(context, reason, null);
}

private static void setAttestationFailureReason(RoutingContext context, AttestationFailureReason reason, Map<String, Object> data) {
private static void setAttestationFailureReason(RoutingContext context, AttestationFailure reason, Map<String, Object> data) {
context.put(com.uid2.core.Const.RoutingContextData.ATTESTATION_FAILURE_REASON_PROP, reason);
context.put(com.uid2.core.Const.RoutingContextData.ATTESTATION_FAILURE_DATA_PROP, data);
}
Expand Down Expand Up @@ -523,14 +543,13 @@ JsonObject make(String name, String failReason) {
}

Object enclavesObj = main.getValue("enclaves");
if (!(enclavesObj instanceof JsonArray)) {
if (!(enclavesObj instanceof JsonArray enclaves)) {
logger.info("enclave register has been called without .enclaves key");
Error("error", 400, rc, ".enclaves needs to be an array");
return;
}

JsonArray res = new JsonArray();
JsonArray enclaves = (JsonArray) enclavesObj;
for (int i = 0; i < enclaves.size(); i++) {
Result result = new Result();
JsonObject item = enclaves.getJsonObject(i);
Expand Down Expand Up @@ -573,7 +592,11 @@ private static String getClientVersionFromHeader(RoutingContext rc, IAuthorizabl
String clientVersion = "unknown client version";
if (rc.request().headers().contains(Const.Http.AppVersionHeader)) {
var client = VertxUtils.parseClientAppVersion(rc.request().headers().get(Const.Http.AppVersionHeader));
clientVersion = profile.getContact() + "|" + client.getKey() + "|" + client.getValue();
if (client != null) {
clientVersion = profile.getContact() + "|" + client.getKey() + "|" + client.getValue();
} else {
clientVersion = profile.getContact() + "|null client key";
}
}
return clientVersion;
}
Expand Down
Loading