Skip to content

Commit 2103610

Browse files
author
Alexander Furer
committed
closes #189
1 parent 0116f2c commit 2103610

File tree

10 files changed

+173
-37
lines changed

10 files changed

+173
-37
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import io.grpc.examples.GreeterOuterClass;
1414
import org.hamcrest.Matchers;
1515
import org.junit.Before;
16+
import org.junit.Test;
1617
import org.junit.runner.RunWith;
1718
import org.lognet.springboot.grpc.demo.DemoApp;
1819
import org.lognet.springboot.grpc.security.AuthClientInterceptor;
@@ -52,6 +53,7 @@
5253

5354
@SpringBootTest(classes = DemoApp.class,
5455
properties = {
56+
"grpc.security.auth.fail-fast=false", // give validator a chance to run before failing auth
5557
"grpc.security.auth.interceptor-order=3", //third
5658
"grpc.metrics.interceptor-order=2", //second
5759
"grpc.validation.interceptor-order=1" //first
@@ -90,7 +92,7 @@ public void setUp() throws Exception {
9092

9193
}
9294

93-
// @Test
95+
@Test
9496
public void validationShouldInvokedBeforeAuthTest() {
9597
final GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(super.getChannel());
9698
StatusRuntimeException e = assertThrows(StatusRuntimeException.class, () -> {
@@ -99,8 +101,10 @@ public void validationShouldInvokedBeforeAuthTest() {
99101
.clearName()//invalid
100102
.build());
101103
});
104+
102105
assertThat(e.getStatus().getCode(), Matchers.is(Status.Code.INVALID_ARGUMENT));
103106

107+
104108
}
105109

106110
@Override

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

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.lognet.springboot.grpc;
22

3+
import io.grpc.Metadata;
34
import io.grpc.Status;
45
import io.grpc.StatusRuntimeException;
56
import io.grpc.examples.GreeterGrpc;
@@ -10,6 +11,9 @@
1011
import org.junit.runner.RunWith;
1112
import org.lognet.springboot.grpc.demo.DemoApp;
1213
import org.springframework.boot.test.context.SpringBootTest;
14+
import org.springframework.boot.test.context.TestConfiguration;
15+
import org.springframework.context.annotation.Bean;
16+
import org.springframework.context.annotation.Import;
1317
import org.springframework.test.context.junit4.SpringRunner;
1418

1519
import static org.hamcrest.MatcherAssert.assertThat;
@@ -19,7 +23,22 @@
1923

2024
@RunWith(SpringRunner.class)
2125
@SpringBootTest(classes = {DemoApp.class}, webEnvironment = NONE, properties = {"grpc.port=0"})
26+
@Import(ValidationTest.TestCfg.class)
2227
public class ValidationTest extends GrpcServerTestBase {
28+
29+
@TestConfiguration
30+
static class TestCfg {
31+
@Bean
32+
public GRpcErrorHandler authErrorHandler() {
33+
return new GRpcErrorHandler() {
34+
@Override
35+
public Status handle(Object message, Status status, Exception exception, Metadata requestHeaders, Metadata responseHeaders) {
36+
responseHeaders.put(Metadata.Key.of("test", Metadata.ASCII_STRING_MARSHALLER), "val");
37+
return super.handle(message,status,exception,requestHeaders,responseHeaders);
38+
}
39+
};
40+
}
41+
}
2342
private GreeterGrpc.GreeterBlockingStub stub;
2443

2544

@@ -45,6 +64,7 @@ public void stringValidationTest() {
4564
Matchers.containsStringIgnoringCase(getFieldName(GreeterOuterClass.Person.NAME_FIELD_NUMBER))
4665

4766
));
67+
4868
}
4969

5070
@Test
@@ -84,6 +104,7 @@ public void fieldsValidationTest() {
84104
Matchers.containsStringIgnoringCase("must be true")
85105

86106
));
107+
assertResponseHeaders(e);
87108
}
88109

89110
@Test
@@ -105,6 +126,7 @@ public void crossFieldsValidationTest() {
105126
Matchers.containsStringIgnoringCase(person.getName()),
106127
Matchers.containsStringIgnoringCase(Integer.toString(person.getAge()))
107128
));
129+
assertResponseHeaders(e);
108130

109131

110132

@@ -135,15 +157,18 @@ public void invalidResponseMessageValidationTest() {
135157

136158
Matchers.containsStringIgnoringCase(getFieldName(GreeterOuterClass.Person.NICKNAME_FIELD_NUMBER)),
137159
Matchers.containsStringIgnoringCase("must not be empty")
138-
139-
140160
));
141-
161+
assertResponseHeaders(e);
142162

143163
}
144164

145165

146166
String getFieldName(int fieldNumber) {
147167
return GreeterOuterClass.Person.getDescriptor().findFieldByNumber(fieldNumber).getName();
148168
}
169+
170+
private void assertResponseHeaders(StatusRuntimeException e) {
171+
final String header = e.getTrailers().get(Metadata.Key.of("test", Metadata.ASCII_STRING_MARSHALLER));
172+
assertThat(header, Matchers.is("val"));
173+
}
149174
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.lognet.springboot.grpc.auth;
22

33

4+
import io.grpc.Metadata;
45
import io.grpc.Status;
56
import io.grpc.StatusRuntimeException;
67
import io.grpc.examples.CalculatorGrpc;
@@ -9,6 +10,7 @@
910
import org.hamcrest.Matchers;
1011
import org.junit.Test;
1112
import org.junit.runner.RunWith;
13+
import org.lognet.springboot.grpc.GRpcErrorHandler;
1214
import org.lognet.springboot.grpc.demo.DemoApp;
1315
import org.lognet.springboot.grpc.security.EnableGrpcSecurity;
1416
import org.lognet.springboot.grpc.security.GrpcSecurity;
@@ -17,6 +19,7 @@
1719
import org.springframework.beans.factory.annotation.Autowired;
1820
import org.springframework.boot.test.context.SpringBootTest;
1921
import org.springframework.boot.test.context.TestConfiguration;
22+
import org.springframework.context.annotation.Bean;
2023
import org.springframework.context.annotation.Import;
2124
import org.springframework.security.oauth2.jwt.JwtDecoder;
2225
import org.springframework.test.context.ActiveProfiles;
@@ -45,9 +48,22 @@
4548
public class JwtRoleTest extends JwtAuthBaseTest {
4649

4750

51+
static final Metadata.Key<String> key = Metadata.Key.of("test", Metadata.ASCII_STRING_MARSHALLER);
52+
4853
@TestConfiguration
4954
static class TestCfg {
5055

56+
@Bean
57+
public GRpcErrorHandler handler(){
58+
return new GRpcErrorHandler(){
59+
@Override
60+
public Status handle(Object message, Status status, Exception exception, Metadata requestHeaders, Metadata responseHeaders) {
61+
62+
responseHeaders.put(key,"value");
63+
return super.handle(message, status, exception, requestHeaders, responseHeaders);
64+
}
65+
};
66+
}
5167
@EnableGrpcSecurity
5268
public class DemoGrpcSecurityConfig extends GrpcSecurityConfigurerAdapter {
5369

@@ -142,6 +158,8 @@ public void shouldFail() {
142158
});
143159
assertThat(statusRuntimeException.getStatus().getCode(), Matchers.is(Status.Code.PERMISSION_DENIED));
144160

161+
assertThat(statusRuntimeException.getTrailers().get(key),Matchers.is("value"));
162+
145163

146164
}
147165

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.lognet.springboot.grpc;
2+
3+
import io.grpc.Metadata;
4+
import io.grpc.ServerCall;
5+
import io.grpc.ServerInterceptor;
6+
import io.grpc.Status;
7+
8+
public interface FailureHandlingServerInterceptor extends ServerInterceptor {
9+
default void closeCall(Object o, GRpcErrorHandler errorHandler, ServerCall<?, ?> call, Metadata headers, final Status status, Exception exception){
10+
11+
final Metadata responseHeaders = new Metadata();
12+
Status statusToSend;
13+
if(null==o){
14+
statusToSend = errorHandler.handle(status, exception, headers, responseHeaders);
15+
}else {
16+
statusToSend = errorHandler.handle(o,status, exception, headers, responseHeaders);
17+
}
18+
19+
call.close(statusToSend, responseHeaders);
20+
}
21+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.lognet.springboot.grpc;
2+
3+
import io.grpc.Metadata;
4+
import io.grpc.Status;
5+
6+
public class GRpcErrorHandler {
7+
8+
/**
9+
*
10+
* @param status
11+
* @param exception
12+
* @param requestHeaders
13+
* @param responseHeaders - to be filled by implementor with trails meant to be sent to client
14+
* @return
15+
*/
16+
public Status handle(Status status, Exception exception, Metadata requestHeaders, Metadata responseHeaders) {
17+
return handle(null,status,exception,requestHeaders,responseHeaders);
18+
}
19+
20+
/**
21+
*
22+
* @param message - request message
23+
* @param status
24+
* @param exception
25+
* @param requestHeaders
26+
* @param responseHeaders - to be filled by implementor with trails meant to be sent to client
27+
* @return
28+
*/
29+
public Status handle(Object message,Status status, Exception exception, Metadata requestHeaders, Metadata responseHeaders) {
30+
return status.withDescription(exception.getMessage());
31+
}
32+
}

grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/autoconfigure/GRpcServerProperties.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public static class SecurityProperties {
8686
@Setter
8787
public static class Auth {
8888
private Integer interceptorOrder;
89+
private boolean failFast = true;
8990
}
9091
}
9192

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,11 @@ protected ServerInterceptor performBuild() throws Exception {
7777
final RoleVoter scopeVoter = new RoleVoter();
7878
scopeVoter.setRolePrefix("SCOPE_");
7979
securityInterceptor.setAccessDecisionManager(new AffirmativeBased(Arrays.asList(new RoleVoter(),scopeVoter, new AuthenticatedAttributeVoter())));
80-
final Integer order = Optional.of(applicationContext.getBean(GRpcServerProperties.class))
80+
final GRpcServerProperties.SecurityProperties.Auth authCfg = Optional.of(applicationContext.getBean(GRpcServerProperties.class))
8181
.map(GRpcServerProperties::getSecurity)
8282
.map(GRpcServerProperties.SecurityProperties::getAuth)
83-
.map(GRpcServerProperties.SecurityProperties.Auth::getInterceptorOrder)
8483
.orElse(null);
85-
securityInterceptor.setOrder(order);
84+
securityInterceptor.setConfig(authCfg);
8685
return securityInterceptor;
8786
}
8887
@SuppressWarnings("unchecked")

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ protected GrpcSecurityConfigurerAdapter() {
2020
}
2121

2222

23+
2324
@Autowired
2425
public void setApplicationContext(ApplicationContext context) throws Exception {
2526

0 commit comments

Comments
 (0)