From 3c0f5aef449b06c76afb3b2f984d5a99587cd233 Mon Sep 17 00:00:00 2001 From: Carles Arnal Date: Fri, 12 Jan 2024 14:07:26 +0100 Subject: [PATCH] Adapt mock and tests to vertx auth --- .../auth/AuthTestAnonymousCredentials.java | 10 ++-- .../registry/auth/AuthTestNoRoles.java | 3 +- .../registry/auth/SimpleAuthTest.java | 2 +- .../storage/impl/sql/MssqlStorageTest.java | 3 ++ .../client/auth/VertXAuthFactory.java | 48 +++++-------------- .../io/apicurio/tests/auth/SimpleAuthIT.java | 3 +- .../registry/utils/tests/JWKSMockServer.java | 48 +++++++++++++++++-- 7 files changed, 71 insertions(+), 46 deletions(-) diff --git a/app/src/test/java/io/apicurio/registry/auth/AuthTestAnonymousCredentials.java b/app/src/test/java/io/apicurio/registry/auth/AuthTestAnonymousCredentials.java index fa21f82333..8fd2527509 100644 --- a/app/src/test/java/io/apicurio/registry/auth/AuthTestAnonymousCredentials.java +++ b/app/src/test/java/io/apicurio/registry/auth/AuthTestAnonymousCredentials.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; import static io.apicurio.registry.client.auth.VertXAuthFactory.buildOIDCWebClient; +import static org.junit.jupiter.api.Assertions.assertTrue; @QuarkusTest @TestProfile(AuthTestProfileAnonymousCredentials.class) @@ -32,12 +33,15 @@ public class AuthTestAnonymousCredentials extends AbstractResourceTestBase { @Test public void testWrongCreds() throws Exception { - var adapter = new VertXRequestAdapter(buildOIDCWebClient(authServerUrl, JWKSMockServer.WRONG_CREDS_CLIENT_ID, "secret")); + var adapter = new VertXRequestAdapter(buildOIDCWebClient(authServerUrl, JWKSMockServer.WRONG_CREDS_CLIENT_ID, "test55")); adapter.setBaseUrl(registryV3ApiUrl); RegistryClient client = new RegistryClient(adapter); - assertNotAuthorized(Assertions.assertThrows(Exception.class, () -> { + + var exception = Assertions.assertThrows(Exception.class, () -> { client.groups().byGroupId(groupId).artifacts().get(); - })); + }); + + assertTrue(exception.getMessage().contains("Unauthorized")); } @Test diff --git a/app/src/test/java/io/apicurio/registry/auth/AuthTestNoRoles.java b/app/src/test/java/io/apicurio/registry/auth/AuthTestNoRoles.java index b36ac92270..45443fc80e 100644 --- a/app/src/test/java/io/apicurio/registry/auth/AuthTestNoRoles.java +++ b/app/src/test/java/io/apicurio/registry/auth/AuthTestNoRoles.java @@ -24,6 +24,7 @@ import static io.apicurio.registry.client.auth.VertXAuthFactory.buildOIDCWebClient; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; @QuarkusTest @TestProfile(AuthTestProfile.class) @@ -51,7 +52,7 @@ public void testWrongCreds() throws Exception { var exception = Assertions.assertThrows(Exception.class, () -> { client.groups().byGroupId(groupId).artifacts().get(); }); - assertNotAuthorized(exception); + assertTrue(exception.getMessage().contains("Unauthorized")); } @Test diff --git a/app/src/test/java/io/apicurio/registry/auth/SimpleAuthTest.java b/app/src/test/java/io/apicurio/registry/auth/SimpleAuthTest.java index 349d20951e..c21de4f151 100644 --- a/app/src/test/java/io/apicurio/registry/auth/SimpleAuthTest.java +++ b/app/src/test/java/io/apicurio/registry/auth/SimpleAuthTest.java @@ -75,7 +75,7 @@ public void testWrongCreds() throws Exception { var exception = Assertions.assertThrows(Exception.class, () -> { client.groups().byGroupId(groupId).artifacts().get(); }); - assertNotAuthorized(exception); + assertTrue(exception.getMessage().contains("Unauthorized")); } @Test diff --git a/app/src/test/java/io/apicurio/registry/storage/impl/sql/MssqlStorageTest.java b/app/src/test/java/io/apicurio/registry/storage/impl/sql/MssqlStorageTest.java index 0836b1ae90..2408c5c784 100644 --- a/app/src/test/java/io/apicurio/registry/storage/impl/sql/MssqlStorageTest.java +++ b/app/src/test/java/io/apicurio/registry/storage/impl/sql/MssqlStorageTest.java @@ -6,10 +6,13 @@ import io.quarkus.test.junit.TestProfile; import jakarta.enterprise.inject.Typed; import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; @QuarkusTest @Tag(ApicurioTestTags.SLOW) @TestProfile(MssqlTestProfile.class) @Typed(MssqlStorageTest.class) +@DisabledOnOs(OS.MAC) public class MssqlStorageTest extends DefaultRegistryStorageTest { } diff --git a/client/src/main/java/io/apicurio/registry/client/auth/VertXAuthFactory.java b/client/src/main/java/io/apicurio/registry/client/auth/VertXAuthFactory.java index 3cfc7131c5..7e998dc1fe 100644 --- a/client/src/main/java/io/apicurio/registry/client/auth/VertXAuthFactory.java +++ b/client/src/main/java/io/apicurio/registry/client/auth/VertXAuthFactory.java @@ -28,42 +28,20 @@ public static WebClient buildOIDCWebClient(String tokenUrl, String clientId, Str } public static WebClient buildOIDCWebClient(Vertx vertx, String tokenUrl, String clientId, String clientSecret, String scope) { - OAuth2Options options = - new OAuth2Options() - .setFlow(OAuth2FlowType.CLIENT) - .setClientId(clientId) - .setTokenPath(tokenUrl) - .setClientSecret(clientSecret); - OAuth2Auth oAuth2Auth = OAuth2Auth.create(VertXAuthFactory.defaultVertx, options); - Oauth2Credentials oauth2Credentials = new Oauth2Credentials(); - if (scope != null) { - oauth2Credentials.addScope(scope); - } + WebClient webClient = WebClient.create(vertx); + + OAuth2Auth oAuth2Options = OAuth2Auth.create(vertx, new OAuth2Options() + .setFlow(OAuth2FlowType.CLIENT) + .setClientId(clientId) + .setClientSecret(clientSecret) + .setTokenPath(tokenUrl)); - OAuth2WebClient oAuth2WebClient = - OAuth2WebClient.create(WebClient.create(vertx), oAuth2Auth) - .withCredentials(oauth2Credentials); + Oauth2Credentials oauth2Credentials = new Oauth2Credentials(); - // Carles: This doesn't look correct the performed request look like: -// { -// "method" : "POST", -// "path" : "/", -// "headers" : { -// "host" : [ "localhost:1080" ], -// "content-length" : [ "29" ], -// "Content-Type" : [ "application/x-www-form-urlencoded" ], -// "Authorization" : [ "Basic YWRtaW4tY2xpZW50OnRlc3Qx" ], -// "Accept" : [ "application/json,application/x-www-form-urlencoded;q=0.9" ] -// }, -// "keepAlive" : true, -// "secure" : false, -// "protocol" : "HTTP_1_1", -// "localAddress" : "dc83711c2da5/172.17.0.2:1080", -// "remoteAddress" : "172.17.0.1:44646", -// "body" : "grant_type=client_credentials" -// } + OAuth2WebClient oauth2WebClient = OAuth2WebClient.create(webClient, oAuth2Options); + oauth2WebClient.withCredentials(oauth2Credentials); - return oAuth2WebClient; + return oauth2WebClient; } public static WebClient buildSimpleAuthWebClient(String username, String password) { @@ -71,9 +49,7 @@ public static WebClient buildSimpleAuthWebClient(String username, String passwor } public static WebClient buildSimpleAuthWebClient(Vertx vertx, String username, String password) { - String usernameAndPassword = Base64.getEncoder().encodeToString("user:pw".getBytes()); - - // TODO: ask Carles if there is a more "idiomatic way" to do this + String usernameAndPassword = Base64.getEncoder().encodeToString((username + ":" + password).getBytes()); return WebClientSession .create(WebClient.create(vertx)) .addHeader("Authorization", "Basic " + usernameAndPassword); diff --git a/integration-tests/src/test/java/io/apicurio/tests/auth/SimpleAuthIT.java b/integration-tests/src/test/java/io/apicurio/tests/auth/SimpleAuthIT.java index 47cc866068..f014a04a2b 100644 --- a/integration-tests/src/test/java/io/apicurio/tests/auth/SimpleAuthIT.java +++ b/integration-tests/src/test/java/io/apicurio/tests/auth/SimpleAuthIT.java @@ -23,6 +23,7 @@ import static io.apicurio.registry.client.auth.VertXAuthFactory.buildOIDCWebClient; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; @Tag(Constants.AUTH) @TestProfile(AuthTestProfile.class) @@ -61,7 +62,7 @@ public void testWrongCreds() throws Exception { var exception = Assertions.assertThrows(Exception.class, () -> { client.groups().byGroupId("foo").artifacts().get(); }); - assertNotAuthorized(exception); + assertTrue(exception.getMessage().contains("Unauthorized")); } @Test diff --git a/utils/tests/src/main/java/io/apicurio/registry/utils/tests/JWKSMockServer.java b/utils/tests/src/main/java/io/apicurio/registry/utils/tests/JWKSMockServer.java index 8ec789206a..721b398975 100644 --- a/utils/tests/src/main/java/io/apicurio/registry/utils/tests/JWKSMockServer.java +++ b/utils/tests/src/main/java/io/apicurio/registry/utils/tests/JWKSMockServer.java @@ -5,7 +5,9 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static io.vertx.ext.auth.impl.Codec.base64Encode; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -76,13 +78,21 @@ public Map start() { //Admin user stub stubForClient(ADMIN_CLIENT_ID); + //Stub for clients with credentials as header + stubForClient(ADMIN_CLIENT_ID, "test1"); //Developer user stub - stubForClient(DEVELOPER_CLIENT_ID); - stubForClient(DEVELOPER_2_CLIENT_ID); + stubForClient(DEVELOPER_CLIENT_ID, "test1"); + stubForClient(DEVELOPER_2_CLIENT_ID, "test1"); + stubForClient(DEVELOPER_CLIENT_ID, "test1"); + stubForClient(DEVELOPER_2_CLIENT_ID, "test1"); //Read only user stub - stubForClient(READONLY_CLIENT_ID); + stubForClient(READONLY_CLIENT_ID, "test1"); + stubForClient(READONLY_CLIENT_ID, "test1"); + //Token without roles stub - stubForClient(NO_ROLE_CLIENT_ID); + stubForClient(NO_ROLE_CLIENT_ID, "test1"); + stubForClient(NO_ROLE_CLIENT_ID, "test1"); + //Stub for basic user server.stubFor(WireMock.post("/auth/realms/" + realm + "/protocol/openid-connect/token/") @@ -135,6 +145,8 @@ public Map start() { .withHeader("Content-Type", "application/json") .withStatus(401))); + stubForClientWithWrongCreds(WRONG_CREDS_CLIENT_ID, "test55"); + this.authServerUrl = server.baseUrl() + "/auth"; LOGGER.info("Keycloak started in mock mode: {}", authServerUrl); this.tokenEndpoint = authServerUrl + "/realms/" + realm + "/protocol/openid-connect/token"; @@ -199,6 +211,34 @@ private void stubForClient(String client) { "}"))); } + private void stubForClient(String client, String clientSecret) { + server.stubFor(WireMock.post("/auth/realms/" + realm + "/protocol/openid-connect/token/") + .withHeader("Authorization", WireMock.containing(buildBasicAuthHeader(client, clientSecret))) + .withRequestBody(WireMock.containing("grant_type=client_credentials")) + .willReturn(WireMock.aResponse() + .withHeader("Content-Type", "application/json") + .withBody("{\n" + + " \"access_token\": \"" + + generateJwtToken(client, null) + "\",\n" + + " \"refresh_token\": \"07e08903-1263-4dd1-9fd1-4a59b0db5283\",\n" + + " \"token_type\": \"bearer\"\n" + + "}"))); + } + + private void stubForClientWithWrongCreds(String client, String clientSecret) { + server.stubFor(WireMock.post("/auth/realms/" + realm + "/protocol/openid-connect/token/") + .withRequestBody(WireMock.containing("grant_type=client_credentials")) + .withHeader("Authorization", WireMock.containing(buildBasicAuthHeader(client, clientSecret))) + .willReturn(WireMock.aResponse() + .withHeader("Content-Type", "application/json") + .withStatus(401))); + } + + private String buildBasicAuthHeader(String username, String password) { + String basic = username+ ":" + password; + return "Basic " + base64Encode(basic.getBytes(StandardCharsets.UTF_8)); + } + public synchronized void stop() { if (server != null) { server.stop();