Skip to content

Commit c07aad2

Browse files
committed
feat(grpc,quarkus-rest,security): fix app startup for grpc svc with class security
1 parent 6652e49 commit c07aad2

File tree

6 files changed

+117
-1
lines changed

6 files changed

+117
-1
lines changed

extensions/resteasy-reactive/rest/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/StandardSecurityCheckInterceptor.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import org.jboss.resteasy.reactive.server.core.CurrentRequestManager;
1818

19+
import io.quarkus.arc.Arc;
1920
import io.quarkus.security.Authenticated;
2021
import io.quarkus.security.PermissionsAllowed;
2122
import io.quarkus.security.spi.runtime.AuthorizationController;
@@ -36,7 +37,9 @@ public abstract class StandardSecurityCheckInterceptor {
3637

3738
@AroundInvoke
3839
public Object intercept(InvocationContext ic) throws Exception {
39-
if (controller.isAuthorizationEnabled() && CurrentRequestManager.get() != null
40+
if (controller.isAuthorizationEnabled() && Arc.container() != null
41+
&& Arc.container().requestContext().isActive()
42+
&& CurrentRequestManager.get() != null
4043
&& alreadyDoneByEagerSecurityHandler(
4144
CurrentRequestManager.get().getProperty(STANDARD_SECURITY_CHECK_INTERCEPTOR), ic.getMethod())) {
4245
ic.getContextData().put(SECURITY_HANDLER, EXECUTED);

integration-tests/oidc-wiremock/src/main/java/io/quarkus/it/keycloak/GreeterResource.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import examples.HelloReply;
1010
import examples.HelloRequest;
1111
import examples.MutinyGreeterGrpc;
12+
import examples.MutinySaluterGrpc;
13+
import examples.SaluteReply;
14+
import examples.SaluteRequest;
1215
import io.grpc.Metadata;
1316
import io.quarkus.grpc.GrpcClient;
1417
import io.quarkus.grpc.GrpcClientUtils;
@@ -26,6 +29,9 @@ public class GreeterResource {
2629
@GrpcClient("hello")
2730
MutinyGreeterGrpc.MutinyGreeterStub helloClient;
2831

32+
@GrpcClient("saluter")
33+
MutinySaluterGrpc.MutinySaluterStub saluterClient;
34+
2935
@Path("bearer")
3036
@GET
3137
public Uni<String> sayHello() {
@@ -35,4 +41,13 @@ public Uni<String> sayHello() {
3541
.bearer(HelloRequest.newBuilder().setName("Jonathan").build()).map(HelloReply::getMessage);
3642
}
3743

44+
@Path("/other/bearer")
45+
@GET
46+
public Uni<String> sayHi() {
47+
Metadata headers = new Metadata();
48+
headers.put(AUTHORIZATION, "Bearer " + accessToken.getRawToken());
49+
return GrpcClientUtils.attachHeaders(saluterClient, headers)
50+
.bearer(SaluteRequest.newBuilder().setName("Jonathan").build()).map(SaluteReply::getMessage);
51+
}
52+
3853
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package io.quarkus.it.keycloak;
2+
3+
import jakarta.annotation.security.RolesAllowed;
4+
import jakarta.inject.Inject;
5+
6+
import examples.MutinySaluterGrpc;
7+
import examples.SaluteReply;
8+
import examples.SaluteRequest;
9+
import io.quarkus.grpc.GrpcService;
10+
import io.quarkus.security.identity.SecurityIdentity;
11+
import io.smallrye.mutiny.Uni;
12+
13+
@RolesAllowed("admin")
14+
@GrpcService
15+
public class SaluterServiceImpl extends MutinySaluterGrpc.SaluterImplBase {
16+
17+
@Inject
18+
SecurityIdentity securityIdentity;
19+
20+
@Override
21+
public Uni<SaluteReply> bearer(SaluteRequest request) {
22+
var principalName = securityIdentity.getPrincipal().getName();
23+
return Uni.createFrom().item(SaluteReply.newBuilder()
24+
.setMessage("Hi " + request.getName() + " from " + principalName).build());
25+
}
26+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2015, Google Inc.
2+
// All rights reserved.
3+
//
4+
// Redistribution and use in source and binary forms, with or without
5+
// modification, are permitted provided that the following conditions are
6+
// met:
7+
//
8+
// * Redistributions of source code must retain the above copyright
9+
// notice, this list of conditions and the following disclaimer.
10+
// * Redistributions in binary form must reproduce the above
11+
// copyright notice, this list of conditions and the following disclaimer
12+
// in the documentation and/or other materials provided with the
13+
// distribution.
14+
// * Neither the name of Google Inc. nor the names of its
15+
// contributors may be used to endorse or promote products derived from
16+
// this software without specific prior written permission.
17+
//
18+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22+
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23+
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24+
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26+
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
30+
syntax = "proto3";
31+
32+
option java_multiple_files = true;
33+
option java_package = "examples";
34+
option java_outer_classname = "SaluterProto";
35+
option objc_class_prefix = "HLW";
36+
37+
package saluter;
38+
39+
// The greeting service definition.
40+
service Saluter {
41+
// Sends a greeting
42+
// Name is 'Bearer' in order to match tenant name
43+
rpc bearer (SaluteRequest) returns (SaluteReply) {}
44+
}
45+
46+
// The request message containing the user's name.
47+
message SaluteRequest {
48+
string name = 1;
49+
}
50+
51+
// The response message containing the greetings
52+
message SaluteReply {
53+
string message = 1;
54+
}

integration-tests/oidc-wiremock/src/main/resources/application.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@ quarkus.native.additional-build-args=-H:IncludeResources=private.*\\.*,-H:Includ
317317

318318
quarkus.grpc.clients.hello.host=localhost
319319
quarkus.grpc.clients.hello.port=8081
320+
quarkus.grpc.clients.saluter.host=localhost
321+
quarkus.grpc.clients.saluter.port=8081
320322
quarkus.grpc.server.use-separate-server=false
321323

322324
%issuer-based-resolver.quarkus.oidc.bearer-issuer-resolver-a.auth-server-url=http://localhost:8185/auth/realms/quarkus2

integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,22 @@ public void testGrpcAuthorizationWithBearerToken() {
742742
.body(Matchers.containsString("Hello Jonathan from alice"));
743743
}
744744

745+
@Test
746+
public void testAuthorizationOnGrpcServiceClassLevel() {
747+
String token = getAccessToken("alice", Set.of("user"));
748+
RestAssured.given().auth().oauth2(token).when()
749+
.get("/api/greeter/other/bearer")
750+
.then()
751+
.statusCode(500);
752+
753+
token = getAccessToken("alice", Set.of("admin"));
754+
RestAssured.given().auth().oauth2(token).when()
755+
.get("/api/greeter/other/bearer")
756+
.then()
757+
.statusCode(200)
758+
.body(Matchers.containsString("Hi Jonathan from alice"));
759+
}
760+
745761
private static void assertSecurityIdentityAcquired(String tenant, String user, String role) {
746762
String jsonPath = tenant + "." + user + ".findAll{ it == \"" + role + "\"}.size()";
747763
RestAssured.given().when().get("/startup-service").then().statusCode(200)

0 commit comments

Comments
 (0)