Skip to content

Commit 0718ff1

Browse files
authored
Add authentication only check for @secured (#164)
* Add authentication only check for @secured * Move @secured authenticated logic into processSecuredAnnotation() * Create testcase for authentication only @secured annotation * Add documentation about new Secured annotation behavior
2 parents 5a05830 + fe0ba38 commit 0718ff1

File tree

9 files changed

+143
-7
lines changed

9 files changed

+143
-7
lines changed

README.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ Defining bean with type `GrpcSecurityConfigurerAdapter` annotated with `@EnableG
354354
----
355355

356356
This default configuration secures GRPC methods/services annotated with `org.springframework.security.access.annotation.@Secured` annotation. +
357+
The value passed to the Annotation can be left empty in which case only authentication will be performed. +
357358
If `JwtDecoder` bean exists in your context, it will also register `JwtAuthenticationProvider` to handle the validation of authentication claim.
358359

359360
==== Custom

grpc-spring-boot-starter-demo/src/main/java/org/lognet/springboot/grpc/demo/GreeterService.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,24 @@ public void sayHello(GreeterOuterClass.HelloRequest request, StreamObserver<Gree
2828
public void sayAuthHello(Empty request, StreamObserver<GreeterOuterClass.HelloReply> responseObserver) {
2929

3030

31+
final Authentication auth = GrpcSecurity.AUTHENTICATION_CONTEXT_KEY.get();
32+
if(null!=auth) {
33+
String user = auth.getName();
34+
if (auth instanceof JwtAuthenticationToken) {
35+
user = JwtAuthenticationToken.class.cast(auth).getTokenAttributes().get("preferred_username").toString();
36+
}
37+
responseObserver.onNext(GreeterOuterClass.HelloReply.newBuilder().setMessage(user).build());
38+
}else{
39+
responseObserver.onNext(GreeterOuterClass.HelloReply.newBuilder().setMessage("Hello").build());
40+
}
41+
responseObserver.onCompleted();
42+
}
43+
44+
@Override
45+
@Secured({})
46+
public void sayAuthOnlyHello(Empty request, StreamObserver<GreeterOuterClass.HelloReply> responseObserver) {
47+
48+
3149
final Authentication auth = GrpcSecurity.AUTHENTICATION_CONTEXT_KEY.get();
3250
if(null!=auth) {
3351
String user = auth.getName();

grpc-spring-boot-starter-demo/src/main/proto/greeter.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ service Greeter {
99
// Sends a greeting
1010
rpc SayHello ( HelloRequest) returns ( HelloReply) {}
1111
rpc SayAuthHello ( google.protobuf.Empty) returns ( HelloReply) {}
12+
rpc SayAuthOnlyHello ( google.protobuf.Empty) returns ( HelloReply) {}
1213

1314
}
1415
service SecuredGreeter {

grpc-spring-boot-starter-demo/src/main/protoGen/io/grpc/examples/CalculatorGrpc.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
package io.grpc.examples;
22

33
import static io.grpc.MethodDescriptor.generateFullMethodName;
4+
import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall;
5+
import static io.grpc.stub.ClientCalls.asyncClientStreamingCall;
6+
import static io.grpc.stub.ClientCalls.asyncServerStreamingCall;
47
import static io.grpc.stub.ClientCalls.asyncUnaryCall;
8+
import static io.grpc.stub.ClientCalls.blockingServerStreamingCall;
59
import static io.grpc.stub.ClientCalls.blockingUnaryCall;
610
import static io.grpc.stub.ClientCalls.futureUnaryCall;
11+
import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall;
12+
import static io.grpc.stub.ServerCalls.asyncClientStreamingCall;
13+
import static io.grpc.stub.ServerCalls.asyncServerStreamingCall;
714
import static io.grpc.stub.ServerCalls.asyncUnaryCall;
15+
import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;
816
import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;
917

1018
/**

grpc-spring-boot-starter-demo/src/main/protoGen/io/grpc/examples/GreeterGrpc.java

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
package io.grpc.examples;
22

33
import static io.grpc.MethodDescriptor.generateFullMethodName;
4+
import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall;
5+
import static io.grpc.stub.ClientCalls.asyncClientStreamingCall;
6+
import static io.grpc.stub.ClientCalls.asyncServerStreamingCall;
47
import static io.grpc.stub.ClientCalls.asyncUnaryCall;
8+
import static io.grpc.stub.ClientCalls.blockingServerStreamingCall;
59
import static io.grpc.stub.ClientCalls.blockingUnaryCall;
610
import static io.grpc.stub.ClientCalls.futureUnaryCall;
11+
import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall;
12+
import static io.grpc.stub.ServerCalls.asyncClientStreamingCall;
13+
import static io.grpc.stub.ServerCalls.asyncServerStreamingCall;
714
import static io.grpc.stub.ServerCalls.asyncUnaryCall;
15+
import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;
816
import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;
917

1018
/**
@@ -84,6 +92,37 @@ io.grpc.examples.GreeterOuterClass.HelloReply> getSayAuthHelloMethod() {
8492
return getSayAuthHelloMethod;
8593
}
8694

95+
private static volatile io.grpc.MethodDescriptor<com.google.protobuf.Empty,
96+
io.grpc.examples.GreeterOuterClass.HelloReply> getSayAuthOnlyHelloMethod;
97+
98+
@io.grpc.stub.annotations.RpcMethod(
99+
fullMethodName = SERVICE_NAME + '/' + "SayAuthOnlyHello",
100+
requestType = com.google.protobuf.Empty.class,
101+
responseType = io.grpc.examples.GreeterOuterClass.HelloReply.class,
102+
methodType = io.grpc.MethodDescriptor.MethodType.UNARY)
103+
public static io.grpc.MethodDescriptor<com.google.protobuf.Empty,
104+
io.grpc.examples.GreeterOuterClass.HelloReply> getSayAuthOnlyHelloMethod() {
105+
io.grpc.MethodDescriptor<com.google.protobuf.Empty, io.grpc.examples.GreeterOuterClass.HelloReply> getSayAuthOnlyHelloMethod;
106+
if ((getSayAuthOnlyHelloMethod = GreeterGrpc.getSayAuthOnlyHelloMethod) == null) {
107+
synchronized (GreeterGrpc.class) {
108+
if ((getSayAuthOnlyHelloMethod = GreeterGrpc.getSayAuthOnlyHelloMethod) == null) {
109+
GreeterGrpc.getSayAuthOnlyHelloMethod = getSayAuthOnlyHelloMethod =
110+
io.grpc.MethodDescriptor.<com.google.protobuf.Empty, io.grpc.examples.GreeterOuterClass.HelloReply>newBuilder()
111+
.setType(io.grpc.MethodDescriptor.MethodType.UNARY)
112+
.setFullMethodName(generateFullMethodName(SERVICE_NAME, "SayAuthOnlyHello"))
113+
.setSampledToLocalTracing(true)
114+
.setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(
115+
com.google.protobuf.Empty.getDefaultInstance()))
116+
.setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(
117+
io.grpc.examples.GreeterOuterClass.HelloReply.getDefaultInstance()))
118+
.setSchemaDescriptor(new GreeterMethodDescriptorSupplier("SayAuthOnlyHello"))
119+
.build();
120+
}
121+
}
122+
}
123+
return getSayAuthOnlyHelloMethod;
124+
}
125+
87126
/**
88127
* Creates a new async stub that supports all call types for the service
89128
*/
@@ -152,6 +191,13 @@ public void sayAuthHello(com.google.protobuf.Empty request,
152191
asyncUnimplementedUnaryCall(getSayAuthHelloMethod(), responseObserver);
153192
}
154193

194+
/**
195+
*/
196+
public void sayAuthOnlyHello(com.google.protobuf.Empty request,
197+
io.grpc.stub.StreamObserver<io.grpc.examples.GreeterOuterClass.HelloReply> responseObserver) {
198+
asyncUnimplementedUnaryCall(getSayAuthOnlyHelloMethod(), responseObserver);
199+
}
200+
155201
@java.lang.Override public final io.grpc.ServerServiceDefinition bindService() {
156202
return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())
157203
.addMethod(
@@ -168,6 +214,13 @@ public void sayAuthHello(com.google.protobuf.Empty request,
168214
com.google.protobuf.Empty,
169215
io.grpc.examples.GreeterOuterClass.HelloReply>(
170216
this, METHODID_SAY_AUTH_HELLO)))
217+
.addMethod(
218+
getSayAuthOnlyHelloMethod(),
219+
asyncUnaryCall(
220+
new MethodHandlers<
221+
com.google.protobuf.Empty,
222+
io.grpc.examples.GreeterOuterClass.HelloReply>(
223+
this, METHODID_SAY_AUTH_ONLY_HELLO)))
171224
.build();
172225
}
173226
}
@@ -207,6 +260,14 @@ public void sayAuthHello(com.google.protobuf.Empty request,
207260
asyncUnaryCall(
208261
getChannel().newCall(getSayAuthHelloMethod(), getCallOptions()), request, responseObserver);
209262
}
263+
264+
/**
265+
*/
266+
public void sayAuthOnlyHello(com.google.protobuf.Empty request,
267+
io.grpc.stub.StreamObserver<io.grpc.examples.GreeterOuterClass.HelloReply> responseObserver) {
268+
asyncUnaryCall(
269+
getChannel().newCall(getSayAuthOnlyHelloMethod(), getCallOptions()), request, responseObserver);
270+
}
210271
}
211272

212273
/**
@@ -242,6 +303,13 @@ public io.grpc.examples.GreeterOuterClass.HelloReply sayAuthHello(com.google.pro
242303
return blockingUnaryCall(
243304
getChannel(), getSayAuthHelloMethod(), getCallOptions(), request);
244305
}
306+
307+
/**
308+
*/
309+
public io.grpc.examples.GreeterOuterClass.HelloReply sayAuthOnlyHello(com.google.protobuf.Empty request) {
310+
return blockingUnaryCall(
311+
getChannel(), getSayAuthOnlyHelloMethod(), getCallOptions(), request);
312+
}
245313
}
246314

247315
/**
@@ -279,10 +347,19 @@ public com.google.common.util.concurrent.ListenableFuture<io.grpc.examples.Greet
279347
return futureUnaryCall(
280348
getChannel().newCall(getSayAuthHelloMethod(), getCallOptions()), request);
281349
}
350+
351+
/**
352+
*/
353+
public com.google.common.util.concurrent.ListenableFuture<io.grpc.examples.GreeterOuterClass.HelloReply> sayAuthOnlyHello(
354+
com.google.protobuf.Empty request) {
355+
return futureUnaryCall(
356+
getChannel().newCall(getSayAuthOnlyHelloMethod(), getCallOptions()), request);
357+
}
282358
}
283359

284360
private static final int METHODID_SAY_HELLO = 0;
285361
private static final int METHODID_SAY_AUTH_HELLO = 1;
362+
private static final int METHODID_SAY_AUTH_ONLY_HELLO = 2;
286363

287364
private static final class MethodHandlers<Req, Resp> implements
288365
io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
@@ -309,6 +386,10 @@ public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserv
309386
serviceImpl.sayAuthHello((com.google.protobuf.Empty) request,
310387
(io.grpc.stub.StreamObserver<io.grpc.examples.GreeterOuterClass.HelloReply>) responseObserver);
311388
break;
389+
case METHODID_SAY_AUTH_ONLY_HELLO:
390+
serviceImpl.sayAuthOnlyHello((com.google.protobuf.Empty) request,
391+
(io.grpc.stub.StreamObserver<io.grpc.examples.GreeterOuterClass.HelloReply>) responseObserver);
392+
break;
312393
default:
313394
throw new AssertionError();
314395
}
@@ -372,6 +453,7 @@ public static io.grpc.ServiceDescriptor getServiceDescriptor() {
372453
.setSchemaDescriptor(new GreeterFileDescriptorSupplier())
373454
.addMethod(getSayHelloMethod())
374455
.addMethod(getSayAuthHelloMethod())
456+
.addMethod(getSayAuthOnlyHelloMethod())
375457
.build();
376458
}
377459
}

grpc-spring-boot-starter-demo/src/main/protoGen/io/grpc/examples/GreeterOuterClass.java

Lines changed: 8 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

grpc-spring-boot-starter-demo/src/main/protoGen/io/grpc/examples/SecuredGreeterGrpc.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
package io.grpc.examples;
22

33
import static io.grpc.MethodDescriptor.generateFullMethodName;
4+
import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall;
5+
import static io.grpc.stub.ClientCalls.asyncClientStreamingCall;
6+
import static io.grpc.stub.ClientCalls.asyncServerStreamingCall;
47
import static io.grpc.stub.ClientCalls.asyncUnaryCall;
8+
import static io.grpc.stub.ClientCalls.blockingServerStreamingCall;
59
import static io.grpc.stub.ClientCalls.blockingUnaryCall;
610
import static io.grpc.stub.ClientCalls.futureUnaryCall;
11+
import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall;
12+
import static io.grpc.stub.ServerCalls.asyncClientStreamingCall;
13+
import static io.grpc.stub.ServerCalls.asyncServerStreamingCall;
714
import static io.grpc.stub.ServerCalls.asyncUnaryCall;
15+
import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;
816
import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;
917

1018
/**

grpc-spring-boot-starter-demo/src/test/java/org/lognet/springboot/grpc/auth/DefaultAuthConfigTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,14 @@ public void securedServiceMethodTest() {
5555
assertTrue(String.format("Reply should contain name '%s'",USER_NAME),reply.contains(USER_NAME));
5656

5757
}
58+
@Test
59+
public void securedAuthOnlyServiceMethodTest() {
60+
61+
final GreeterGrpc.GreeterBlockingStub securedFutureStub = GreeterGrpc.newBlockingStub(getChannel(true));
62+
63+
final String reply = securedFutureStub.sayAuthOnlyHello(Empty.getDefaultInstance()).getMessage();
64+
assertNotNull("Reply should not be null",reply);
65+
assertTrue(String.format("Reply should contain name '%s'",USER_NAME),reply.contains(USER_NAME));
66+
67+
}
5868
}

grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/security/GrpcServiceAuthorizationConfigurer.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,13 @@ private void processSecuredAnnotation() {
140140
.filter(m -> m.getName().equalsIgnoreCase(methodDefinition.getMethodDescriptor().getBareMethodName()))
141141
.findFirst()
142142
.flatMap(m -> Optional.ofNullable(AnnotationUtils.findAnnotation(m, Secured.class)))
143-
.ifPresent(secured -> new AuthorizedMethod(methodDefinition.getMethodDescriptor()).hasAnyAuthority(secured.value()));
143+
.ifPresent(secured -> {
144+
if (secured.value().length == 0) {
145+
new AuthorizedMethod(methodDefinition.getMethodDescriptor()).authenticated();
146+
} else {
147+
new AuthorizedMethod(methodDefinition.getMethodDescriptor()).hasAnyAuthority(secured.value());
148+
}
149+
});
144150

145151
}
146152
}

0 commit comments

Comments
 (0)