From fa444fefcdcc37d89b3ce05382af45c6f8d64d0a Mon Sep 17 00:00:00 2001 From: Dmitri Bourlatchkov Date: Thu, 9 Sep 2021 13:43:52 -0400 Subject: [PATCH] Support injecting OIDC WireMockServer into tests * Define a custom annotation: OidcWireMock for tests to indicate they want the WireMock Server injected. * Override inject(TestInjector) in OidcWiremockTestResource to allow tests to receive the WireMockServer used by OidcWiremockTestResource This is to allow (external) tests to mock extra URLs, that are not covered by OidcWiremockTestResource * Add bearer auth test for invalid token. Use a custom wiremock stub for generating responses for the invalid token. --- .../BearerTokenAuthorizationTest.java | 21 ++++++++++++ .../test/oidc/server/OidcWireMock.java | 24 ++++++++++++++ .../oidc/server/OidcWiremockTestResource.java | 11 +++++++ ...OidcWiremockTestResourceInjectionTest.java | 32 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 test-framework/oidc-server/src/main/java/io/quarkus/test/oidc/server/OidcWireMock.java create mode 100644 test-framework/oidc-server/src/test/java/io/quarkus/test/oidc/server/OidcWiremockTestResourceInjectionTest.java diff --git a/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java b/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java index 9c7cbc79dd8de..8e5fd8d02f1e1 100644 --- a/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java +++ b/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java @@ -1,5 +1,6 @@ package io.quarkus.it.keycloak; +import static com.github.tomakehurst.wiremock.client.WireMock.matching; import static org.hamcrest.Matchers.equalTo; import java.time.Instant; @@ -10,8 +11,12 @@ import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; + import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.oidc.server.OidcWireMock; import io.quarkus.test.oidc.server.OidcWiremockTestResource; import io.restassured.RestAssured; import io.smallrye.jwt.build.Jwt; @@ -20,6 +25,9 @@ @QuarkusTestResource(OidcWiremockTestResource.class) public class BearerTokenAuthorizationTest { + @OidcWireMock + WireMockServer wireMockServer; + @Test public void testSecureAccessSuccessPreferredUsername() { for (String username : Arrays.asList("alice", "admin")) { @@ -98,6 +106,19 @@ public void testBearerTokenWrongAudience() { .header("WWW-Authenticate", equalTo("Bearer")); } + @Test + public void testInvalidBearerToken() { + wireMockServer.stubFor(WireMock.post("/auth/realms/quarkus/protocol/openid-connect/token/introspect") + .withRequestBody(matching(".*token=invalid_token.*")) + .willReturn(WireMock.aResponse().withStatus(400))); + + RestAssured.given().auth().oauth2("invalid_token").when() + .get("/api/users/me/bearer") + .then() + .statusCode(401) + .header("WWW-Authenticate", equalTo("Bearer")); + } + private String getAccessToken(String userName, Set groups) { return Jwt.preferredUserName(userName) .groups(groups) diff --git a/test-framework/oidc-server/src/main/java/io/quarkus/test/oidc/server/OidcWireMock.java b/test-framework/oidc-server/src/main/java/io/quarkus/test/oidc/server/OidcWireMock.java new file mode 100644 index 0000000000000..1c16d48245af3 --- /dev/null +++ b/test-framework/oidc-server/src/main/java/io/quarkus/test/oidc/server/OidcWireMock.java @@ -0,0 +1,24 @@ +package io.quarkus.test.oidc.server; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.github.tomakehurst.wiremock.WireMockServer; + +/** + * Used to specify that the field should be injected with the {@link WireMockServer} + * server that provides mock HTTP API for OIDC clients. + *

+ * Note: for this injection to work the test must use {@link OidcWiremockTestResource}. + *

+ *

+ * The main purpose of injecting the {@link WireMockServer} is for tests to be able + * to mock extra URLs not covered by {@link OidcWiremockTestResource}. + *

+ */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface OidcWireMock { +} diff --git a/test-framework/oidc-server/src/main/java/io/quarkus/test/oidc/server/OidcWiremockTestResource.java b/test-framework/oidc-server/src/main/java/io/quarkus/test/oidc/server/OidcWiremockTestResource.java index dc6f082745f1e..45d7b126a4871 100644 --- a/test-framework/oidc-server/src/main/java/io/quarkus/test/oidc/server/OidcWiremockTestResource.java +++ b/test-framework/oidc-server/src/main/java/io/quarkus/test/oidc/server/OidcWiremockTestResource.java @@ -26,6 +26,11 @@ import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; import io.smallrye.jwt.build.Jwt; +/** + * Provides a mock OIDC server to tests. + * + * @see OidcWireMock + */ public class OidcWiremockTestResource implements QuarkusTestResourceLifecycleManager { private static final Logger LOG = Logger.getLogger(OidcWiremockTestResource.class); @@ -192,6 +197,12 @@ private String generateJwtToken(String userName, Set groups) { .sign("privateKey.jwk"); } + @Override + public void inject(TestInjector testInjector) { + testInjector.injectIntoFields(server, + new TestInjector.AnnotatedAndMatchesType(OidcWireMock.class, WireMockServer.class)); + } + @Override public synchronized void stop() { if (server != null) { diff --git a/test-framework/oidc-server/src/test/java/io/quarkus/test/oidc/server/OidcWiremockTestResourceInjectionTest.java b/test-framework/oidc-server/src/test/java/io/quarkus/test/oidc/server/OidcWiremockTestResourceInjectionTest.java new file mode 100644 index 0000000000000..12bfc5a0fb35c --- /dev/null +++ b/test-framework/oidc-server/src/test/java/io/quarkus/test/oidc/server/OidcWiremockTestResourceInjectionTest.java @@ -0,0 +1,32 @@ +package io.quarkus.test.oidc.server; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import com.github.tomakehurst.wiremock.WireMockServer; + +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.common.TestResourceManager; + +/** + * Validates the injection of {@link WireMockServer} objects into test instances by {@link OidcWiremockTestResource}. + */ +class OidcWiremockTestResourceInjectionTest { + + @Test + void testWireMockServerInjection() { + TestResourceManager manager = new TestResourceManager(CustomTest.class); + manager.start(); + + CustomTest test = new CustomTest(); + manager.inject(test); + assertNotNull(test.server); + } + + @QuarkusTestResource(OidcWiremockTestResource.class) + public static class CustomTest { + @OidcWireMock + WireMockServer server; + } +}