From 62d4fd2e8a306f4f79416709b7862b2b15e4741d Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Wed, 12 Apr 2023 17:13:44 +0100 Subject: [PATCH] Add JWT authentication tests to management-interface-auth --- .../management-interface-auth/pom.xml | 17 +++++ .../it/management/GreetingResource.java | 12 ++++ .../src/main/resources/application.properties | 28 ++++++++ .../src/main/resources/privateKey.pem | 28 ++++++++ .../src/main/resources/publicKey.pem | 9 +++ .../ManagementInterfaceTestCase.java | 67 ++++++++++++++++++- 6 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 integration-tests/management-interface-auth/src/main/resources/privateKey.pem create mode 100644 integration-tests/management-interface-auth/src/main/resources/publicKey.pem diff --git a/integration-tests/management-interface-auth/pom.xml b/integration-tests/management-interface-auth/pom.xml index 7bdf390f8b792..2c2a74773dc53 100644 --- a/integration-tests/management-interface-auth/pom.xml +++ b/integration-tests/management-interface-auth/pom.xml @@ -30,6 +30,10 @@ io.quarkus quarkus-elytron-security-properties-file + + io.quarkus + quarkus-smallrye-jwt + io.quarkus quarkus-junit5 @@ -99,6 +103,19 @@ + + io.quarkus + quarkus-smallrye-jwt-deployment + ${project.version} + pom + test + + + * + * + + + diff --git a/integration-tests/management-interface-auth/src/main/java/io/quarkus/it/management/GreetingResource.java b/integration-tests/management-interface-auth/src/main/java/io/quarkus/it/management/GreetingResource.java index 1557a8d3bd791..6526c8505b21a 100644 --- a/integration-tests/management-interface-auth/src/main/java/io/quarkus/it/management/GreetingResource.java +++ b/integration-tests/management-interface-auth/src/main/java/io/quarkus/it/management/GreetingResource.java @@ -17,4 +17,16 @@ public String hello() { public String goodbye() { return "goodbye"; } + + @GET + @Path("/goodmorning") + public String goodmorning() { + return "goodmorning"; + } + + @GET + @Path("/goodevening") + public String goodevening() { + return "goodevening"; + } } diff --git a/integration-tests/management-interface-auth/src/main/resources/application.properties b/integration-tests/management-interface-auth/src/main/resources/application.properties index 51b3e507c06c3..6844b7e6ce612 100644 --- a/integration-tests/management-interface-auth/src/main/resources/application.properties +++ b/integration-tests/management-interface-auth/src/main/resources/application.properties @@ -1,15 +1,28 @@ quarkus.management.enabled=true +# Management router authentication: +# /q/health/* - basic authentication only, `management` role is required +# /q/metrics/* - basic and jwt authentications are allowed, any role is allowed quarkus.management.auth.basic=true quarkus.management.auth.policy.role-policy.roles-allowed=management quarkus.management.auth.permission.health.paths=/q/health/* quarkus.management.auth.permission.health.policy=role-policy +quarkus.management.auth.permission.health.auth-mechanism=basic + quarkus.management.auth.permission.metrics.paths=/q/metrics/* quarkus.management.auth.permission.metrics.policy=authenticated +# Main router authentication: +# /service/hello/* - public resource +# /service/goodbye/* - basic authentication only, `greeting` role is allowed +# /service/goodmorning/* - JWT bearer authentication only, `admin` role is allowed +# /service/goodevening/* - JWT bearer authentication only, `user` role is allowed + quarkus.http.auth.basic=true quarkus.http.auth.policy.role-policy.roles-allowed=greeting + quarkus.http.auth.permission.main.paths=/service/goodbye quarkus.http.auth.permission.main.policy=role-policy +quarkus.http.auth.permission.main.auth-mechanism=basic quarkus.security.users.embedded.enabled=true quarkus.security.users.embedded.plain-text=true @@ -18,3 +31,18 @@ quarkus.security.users.embedded.roles.alice=management quarkus.security.users.embedded.users.bob=bob quarkus.security.users.embedded.roles.bob=greeting + +quarkus.http.auth.policy.role-policy-jwt-admin.roles-allowed=admin +quarkus.http.auth.permission.main-jwt-admin.paths=/service/goodmorning +quarkus.http.auth.permission.main-jwt-admin.policy=role-policy-jwt-admin +quarkus.http.auth.permission.main-jwt-admin.auth-mechanism=bearer + +quarkus.http.auth.policy.role-policy-jwt-user.roles-allowed=user +quarkus.http.auth.permission.main-jwt-user.paths=/service/goodevening +quarkus.http.auth.permission.main-jwt-user.policy=role-policy-jwt-user +quarkus.http.auth.permission.main-jwt-user.auth-mechanism=bearer + +mp.jwt.verify.publickey.location=/publicKey.pem +mp.jwt.verify.issuer=https://server.example.com +smallrye.jwt.sign.key.location=/privateKey.pem +smallrye.jwt.new-token.issuer=https://server.example.com \ No newline at end of file diff --git a/integration-tests/management-interface-auth/src/main/resources/privateKey.pem b/integration-tests/management-interface-auth/src/main/resources/privateKey.pem new file mode 100644 index 0000000000000..27543a434a1eb --- /dev/null +++ b/integration-tests/management-interface-auth/src/main/resources/privateKey.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCWK8UjyoHgPTLa +PLQJ8SoXLLjpHSjtLxMqmzHnFscqhTVVaDpCRCb6e3Ii/WniQTWw8RA7vf4djz4H +OzvlfBFNgvUGZHXDwnmGaNVaNzpHYFMEYBhE8VGGiveSkzqeLZI+Y02G6sQAfDtN +qqzM/l5QX8X34oQFaTBW1r49nftvCpITiwJvWyhkWtXP9RP8sXi1im5Vi3dhupOh +nelk5n0BfajUYIbfHA6ORzjHRbt7NtBl0L2J+0/FUdHyKs6KMlFGNw8O0Dq88qnM +uXoLJiewhg9332W3DFMeOveel+//cvDnRsCRtPgd4sXFPHh+UShkso7+DRsChXa6 +oGGQD3GdAgMBAAECggEAAjfTSZwMHwvIXIDZB+yP+pemg4ryt84iMlbofclQV8hv +6TsI4UGwcbKxFOM5VSYxbNOisb80qasb929gixsyBjsQ8284bhPJR7r0q8h1C+jY +URA6S4pk8d/LmFakXwG9Tz6YPo3pJziuh48lzkFTk0xW2Dp4SLwtAptZY/+ZXyJ6 +96QXDrZKSSM99Jh9s7a0ST66WoxSS0UC51ak+Keb0KJ1jz4bIJ2C3r4rYlSu4hHB +Y73GfkWORtQuyUDa9yDOem0/z0nr6pp+pBSXPLHADsqvZiIhxD/O0Xk5I6/zVHB3 +zuoQqLERk0WvA8FXz2o8AYwcQRY2g30eX9kU4uDQAQKBgQDmf7KGImUGitsEPepF +KH5yLWYWqghHx6wfV+fdbBxoqn9WlwcQ7JbynIiVx8MX8/1lLCCe8v41ypu/eLtP +iY1ev2IKdrUStvYRSsFigRkuPHUo1ajsGHQd+ucTDf58mn7kRLW1JGMeGxo/t32B +m96Af6AiPWPEJuVfgGV0iwg+HQKBgQCmyPzL9M2rhYZn1AozRUguvlpmJHU2DpqS +34Q+7x2Ghf7MgBUhqE0t3FAOxEC7IYBwHmeYOvFR8ZkVRKNF4gbnF9RtLdz0DMEG +5qsMnvJUSQbNB1yVjUCnDAtElqiFRlQ/k0LgYkjKDY7LfciZl9uJRl0OSYeX/qG2 +tRW09tOpgQKBgBSGkpM3RN/MRayfBtmZvYjVWh3yjkI2GbHA1jj1g6IebLB9SnfL +WbXJErCj1U+wvoPf5hfBc7m+jRgD3Eo86YXibQyZfY5pFIh9q7Ll5CQl5hj4zc4Y +b16sFR+xQ1Q9Pcd+BuBWmSz5JOE/qcF869dthgkGhnfVLt/OQzqZluZRAoGAXQ09 +nT0TkmKIvlza5Af/YbTqEpq8mlBDhTYXPlWCD4+qvMWpBII1rSSBtftgcgca9XLB +MXmRMbqtQeRtg4u7dishZVh1MeP7vbHsNLppUQT9Ol6lFPsd2xUpJDc6BkFat62d +Xjr3iWNPC9E9nhPPdCNBv7reX7q81obpeXFMXgECgYEAmk2Qlus3OV0tfoNRqNpe +Mb0teduf2+h3xaI1XDIzPVtZF35ELY/RkAHlmWRT4PCdR0zXDidE67L6XdJyecSt +FdOUH8z5qUraVVebRFvJqf/oGsXc4+ex1ZKUTbY0wqY1y9E39yvB3MaTmZFuuqk8 +f3cg+fr8aou7pr9SHhJlZCU= +-----END PRIVATE KEY----- diff --git a/integration-tests/management-interface-auth/src/main/resources/publicKey.pem b/integration-tests/management-interface-auth/src/main/resources/publicKey.pem new file mode 100644 index 0000000000000..6dc936fca3485 --- /dev/null +++ b/integration-tests/management-interface-auth/src/main/resources/publicKey.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEq +Fyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwR +TYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5e +UF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9 +AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYn +sIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9x +nQIDAQAB +-----END PUBLIC KEY----- diff --git a/integration-tests/management-interface-auth/src/test/java/io/quarkus/it/management/ManagementInterfaceTestCase.java b/integration-tests/management-interface-auth/src/test/java/io/quarkus/it/management/ManagementInterfaceTestCase.java index 48f9a68972add..ba49cf5b1f813 100644 --- a/integration-tests/management-interface-auth/src/test/java/io/quarkus/it/management/ManagementInterfaceTestCase.java +++ b/integration-tests/management-interface-auth/src/test/java/io/quarkus/it/management/ManagementInterfaceTestCase.java @@ -1,10 +1,13 @@ package io.quarkus.it.management; +import java.util.Set; + import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; +import io.smallrye.jwt.build.Jwt; @QuarkusTest public class ManagementInterfaceTestCase { @@ -29,6 +32,11 @@ void verifyThatHealthChecksAreExposedOnManagementInterface() { .then().statusCode(200) .body(Matchers.containsString("UP")); + RestAssured.given().auth().oauth2(getAdminToken()).get(getPrefix() + "/q/health") + .then().statusCode(401); + RestAssured.given().auth().oauth2(getUserToken()).get(getPrefix() + "/q/health") + .then().statusCode(401); + RestAssured.get("/q/health") .then().statusCode(404); } @@ -44,12 +52,19 @@ void verifyThatMetricsAreExposedOnManagementInterface() { RestAssured.given().auth().basic("john", "john").get(getPrefix() + "/q/metrics") .then().statusCode(401); + RestAssured.given().auth().oauth2(getAdminToken()).get(getPrefix() + "/q/metrics") + .then().statusCode(200); + RestAssured.given().auth().oauth2(getUserToken()).get(getPrefix() + "/q/metrics") + .then().statusCode(200); + RestAssured.given().auth().oauth2("wrongtoken").get(getPrefix() + "/q/metrics") + .then().statusCode(401); + RestAssured.get("/q/metrics") .then().statusCode(404); } @Test - void verifyMainEndpoint() { + void verifyMainEndpointBasicAuth() { RestAssured.get("/service/hello").then().statusCode(200) .body(Matchers.equalTo("hello")); @@ -62,5 +77,55 @@ void verifyMainEndpoint() { RestAssured.given().auth().basic("bob", "bob").get("/service/goodbye") .then().statusCode(200) .body(Matchers.equalTo("goodbye")); + + RestAssured.given().auth().oauth2(getAdminToken()).get("/service/goodbye") + .then().statusCode(401); + RestAssured.given().auth().oauth2(getUserToken()).get("/service/goodbye") + .then().statusCode(401); + + } + + @Test + void verifyMainEndpointJwtAuth() { + RestAssured.get("/service/hello").then().statusCode(200) + .body(Matchers.equalTo("hello")); + + RestAssured.given().auth().preemptive().basic("john", "john").get("/service/goodmorning") + .then().statusCode(401); + RestAssured.given().auth().preemptive().basic("john", "john").get("/service/goodevening") + .then().statusCode(401); + + RestAssured.given().auth().preemptive().basic("alice", "alice").get("/service/goodmorning") + .then().statusCode(401); + RestAssured.given().auth().preemptive().basic("alice", "alice").get("/service/goodevening") + .then().statusCode(401); + + RestAssured.given().auth().basic("bob", "bob").get("/service/goodmorning") + .then().statusCode(401); + RestAssured.given().auth().basic("bob", "bob").get("/service/goodevening") + .then().statusCode(401); + + RestAssured.given().auth().oauth2(getAdminToken()).get("/service/goodmorning") + .then().statusCode(200) + .body(Matchers.equalTo("goodmorning")); + RestAssured.given().auth().oauth2(getUserToken()).get("/service/goodmorning") + .then().statusCode(403); + + RestAssured.given().auth().oauth2(getAdminToken()).get("/service/goodevening") + .then().statusCode(200) + .body(Matchers.equalTo("goodevening")); + RestAssured.given().auth().oauth2(getUserToken()).get("/service/goodevening") + .then().statusCode(200) + .body(Matchers.equalTo("goodevening")); + } + + private String getAdminToken() { + return Jwt.upn("alice").groups(Set.of("admin", "user")).sign(); + } + + private String getUserToken() { + return Jwt.subject("bob").groups("user").sign(); + } + }