diff --git a/pom.xml b/pom.xml index be44138..fc9feb3 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ 4.5.13 1.1.0 - 9.2.9 + 9.5.3 ${project.version} 5.10.1 5.10.1 @@ -132,6 +132,12 @@ logback-classic 1.5.8 + + org.mockito + mockito-junit-jupiter + 5.12.0 + test + diff --git a/src/main/java/com/uid2/optout/auth/InternalAuthMiddleware.java b/src/main/java/com/uid2/optout/auth/InternalAuthMiddleware.java index 8ca8116..7f9912d 100644 --- a/src/main/java/com/uid2/optout/auth/InternalAuthMiddleware.java +++ b/src/main/java/com/uid2/optout/auth/InternalAuthMiddleware.java @@ -1,5 +1,7 @@ package com.uid2.optout.auth; +import com.uid2.shared.audit.Audit; +import com.uid2.shared.audit.AuditParams; import com.uid2.shared.auth.OperatorKey; import com.uid2.shared.middleware.AuthMiddleware; import io.vertx.core.Handler; @@ -48,15 +50,25 @@ public void handle(RoutingContext rc) { } } } - + private final Audit audit; private final String internalApiToken; - public InternalAuthMiddleware(String internalApiToken) { + private Handler logAndHandle(Handler handler, AuditParams auditParams) { + return ctx -> { + ctx.addBodyEndHandler(v -> this.audit.log(ctx, auditParams)); + handler.handle(ctx); + }; + } + + public InternalAuthMiddleware(String internalApiToken, String auditSource) { this.internalApiToken = internalApiToken; + this.audit = new Audit(auditSource); } - public Handler handle(Handler handler) { - final InternalAuthHandler h = new InternalAuthHandler(handler, this.internalApiToken); + public Handler handleWithAudit(Handler handler) { + InternalAuthHandler h; + final Handler loggedHandler = logAndHandle(handler, new AuditParams()); + h = new InternalAuthHandler(loggedHandler, this.internalApiToken); return h::handle; } } diff --git a/src/main/java/com/uid2/optout/vertx/OptOutServiceVerticle.java b/src/main/java/com/uid2/optout/vertx/OptOutServiceVerticle.java index ffa1926..1dab316 100644 --- a/src/main/java/com/uid2/optout/vertx/OptOutServiceVerticle.java +++ b/src/main/java/com/uid2/optout/vertx/OptOutServiceVerticle.java @@ -35,12 +35,11 @@ import java.net.URL; import java.time.Instant; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; -import static com.uid2.optout.vertx.Endpoints.*; - public class OptOutServiceVerticle extends AbstractVerticle { public static final String IDENTITY_HASH = "identity_hash"; public static final String ADVERTISING_ID = "advertising_id"; @@ -68,7 +67,7 @@ public OptOutServiceVerticle(Vertx vertx, this.healthComponent.setHealthStatus(false, "not started"); this.cloudStorage = cloudStorage; - this.auth = new AuthMiddleware(clientKeyProvider); + this.auth = new AuthMiddleware(clientKeyProvider, "optout"); final String attestEncKey = jsonConfig.getString(Const.Config.AttestationEncryptionKeyName); final String attestEncSalt = jsonConfig.getString(Const.Config.AttestationEncryptionSaltName); @@ -102,7 +101,7 @@ public OptOutServiceVerticle(Vertx vertx, this.defaultDeliveryOptions.setSendTimeout(addEntryTimeoutMs); this.internalApiKey = jsonConfig.getString(Const.Config.OptOutInternalApiTokenProp); - this.internalAuth = new InternalAuthMiddleware(this.internalApiKey); + this.internalAuth = new InternalAuthMiddleware(this.internalApiKey, "optout"); this.enableOptOutPartnerMock = jsonConfig.getBoolean(Const.Config.OptOutPartnerEndpointMockProp); } @@ -167,11 +166,11 @@ private Router createRouter() { .allowedHeader("Content-Type")); router.route(Endpoints.OPTOUT_WRITE.toString()) - .handler(internalAuth.handle(this::handleWrite)); + .handler(internalAuth.handleWithAudit(this::handleWrite)); router.route(Endpoints.OPTOUT_REPLICATE.toString()) - .handler(auth.handle(this::handleReplicate, Role.OPTOUT)); + .handler(auth.handleWithAudit(this::handleReplicate, Arrays.asList(Role.OPTOUT))); router.route(Endpoints.OPTOUT_REFRESH.toString()) - .handler(auth.handle(attest.handle(this::handleRefresh, Role.OPERATOR), Role.OPERATOR)); + .handler(auth.handleWithAudit(attest.handle(this::handleRefresh, Role.OPERATOR), Arrays.asList(Role.OPERATOR))); router.get(Endpoints.OPS_HEALTHCHECK.toString()) .handler(this::handleHealthCheck); diff --git a/src/test/java/com/uid2/optout/auth/InternalAuthMiddlewareTest.java b/src/test/java/com/uid2/optout/auth/InternalAuthMiddlewareTest.java new file mode 100644 index 0000000..0d0d5ad --- /dev/null +++ b/src/test/java/com/uid2/optout/auth/InternalAuthMiddlewareTest.java @@ -0,0 +1,70 @@ +package com.uid2.optout.auth; + +import org.junit.jupiter.api.BeforeEach; +import io.vertx.core.Handler; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class InternalAuthMiddlewareTest { + @Mock + private RoutingContext routingContext; + @Mock + private HttpServerRequest request; + @Mock + private Handler nextHandler; + private InternalAuthMiddleware internalAuth; + + @BeforeEach + public void setup(){ + internalAuth = new InternalAuthMiddleware("apiToken", "test"); + when(routingContext.request()).thenReturn(request); + } + + @Test + public void internalAuthHandlerSucceed() { + when(request.getHeader("Authorization")).thenReturn("Bearer apiToken"); + Handler handler = internalAuth.handleWithAudit(nextHandler); + handler.handle(routingContext); + verify(nextHandler).handle(routingContext); + verify(routingContext, times(0)).fail(any()); + verify(routingContext, times(1)).addBodyEndHandler(ArgumentMatchers.>any()); + } + + @Test + public void internalAuthHandlerNoAuthorizationHeader() { + Handler handler = internalAuth.handleWithAudit(nextHandler); + handler.handle(routingContext); + verifyNoInteractions(nextHandler); + verify(routingContext).fail(401); + verify(routingContext, times(0)).addBodyEndHandler(ArgumentMatchers.>any()); + } + + @Test public void authHandlerInvalidAuthorizationHeader() { + when(request.getHeader("Authorization")).thenReturn("Bogus Header Value"); + Handler handler = internalAuth.handleWithAudit(nextHandler); + handler.handle(routingContext); + verifyNoInteractions(nextHandler); + verify(routingContext).fail(401); + verify(routingContext, times(0)).addBodyEndHandler(ArgumentMatchers.>any()); + } + + @Test public void authHandlerUnknownKey() { + when(request.getHeader("Authorization")).thenReturn("Bearer unknown-key"); + Handler handler = internalAuth.handleWithAudit(nextHandler); + handler.handle(routingContext); + verifyNoInteractions(nextHandler); + verify(routingContext).fail(401); + verify(routingContext, times(0)).addBodyEndHandler(ArgumentMatchers.>any()); + } +}