* Bump testcontainers
* Update _configprops.adoc * Add grpc integration test
This commit is contained in:
committed by
Abel Salgado Romero
parent
0568b306da
commit
22a9aec8bf
@@ -14,6 +14,7 @@
|
||||
|spring.cloud.gateway.filter.add-request-header.enabled | `+++true+++` | Enables the add-request-header filter.
|
||||
|spring.cloud.gateway.filter.add-request-parameter.enabled | `+++true+++` | Enables the add-request-parameter filter.
|
||||
|spring.cloud.gateway.filter.add-response-header.enabled | `+++true+++` | Enables the add-response-header filter.
|
||||
|spring.cloud.gateway.filter.json-to-grpc.enabled | `+++true+++` | Enables the JSON to gRPC filter.
|
||||
|spring.cloud.gateway.filter.circuit-breaker.enabled | `+++true+++` | Enables the circuit-breaker filter.
|
||||
|spring.cloud.gateway.filter.dedupe-response-header.enabled | `+++true+++` | Enables the dedupe-response-header filter.
|
||||
|spring.cloud.gateway.filter.fallback-headers.enabled | `+++true+++` | Enables the fallback-headers filter.
|
||||
@@ -26,7 +27,7 @@
|
||||
|spring.cloud.gateway.filter.preserve-host-header.enabled | `+++true+++` | Enables the preserve-host-header filter.
|
||||
|spring.cloud.gateway.filter.redirect-to.enabled | `+++true+++` | Enables the redirect-to filter.
|
||||
|spring.cloud.gateway.filter.remove-hop-by-hop.headers | |
|
||||
|spring.cloud.gateway.filter.remove-hop-by-hop.order | `+++0+++` |
|
||||
|spring.cloud.gateway.filter.remove-hop-by-hop.order | `+++0+++` |
|
||||
|spring.cloud.gateway.filter.remove-request-header.enabled | `+++true+++` | Enables the remove-request-header filter.
|
||||
|spring.cloud.gateway.filter.remove-request-parameter.enabled | `+++true+++` | Enables the remove-request-parameter filter.
|
||||
|spring.cloud.gateway.filter.remove-response-header.enabled | `+++true+++` | Enables the remove-response-header filter.
|
||||
@@ -42,16 +43,16 @@
|
||||
|spring.cloud.gateway.filter.rewrite-path.enabled | `+++true+++` | Enables the rewrite-path filter.
|
||||
|spring.cloud.gateway.filter.rewrite-response-header.enabled | `+++true+++` | Enables the rewrite-response-header filter.
|
||||
|spring.cloud.gateway.filter.save-session.enabled | `+++true+++` | Enables the save-session filter.
|
||||
|spring.cloud.gateway.filter.secure-headers.content-security-policy | `+++default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.content-type-options | `+++nosniff+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.content-security-policy | `+++default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.content-type-options | `+++nosniff+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.disable | |
|
||||
|spring.cloud.gateway.filter.secure-headers.download-options | `+++noopen+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.download-options | `+++noopen+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.enabled | `+++true+++` | Enables the secure-headers filter.
|
||||
|spring.cloud.gateway.filter.secure-headers.frame-options | `+++DENY+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.permitted-cross-domain-policies | `+++none+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.referrer-policy | `+++no-referrer+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.strict-transport-security | `+++max-age=631138519+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.xss-protection-header | `+++1 ; mode=block+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.frame-options | `+++DENY+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.permitted-cross-domain-policies | `+++none+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.referrer-policy | `+++no-referrer+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.strict-transport-security | `+++max-age=631138519+++` |
|
||||
|spring.cloud.gateway.filter.secure-headers.xss-protection-header | `+++1 ; mode=block+++` |
|
||||
|spring.cloud.gateway.filter.set-path.enabled | `+++true+++` | Enables the set-path filter.
|
||||
|spring.cloud.gateway.filter.set-request-header.enabled | `+++true+++` | Enables the set-request-header filter.
|
||||
|spring.cloud.gateway.filter.set-request-host-header.enabled | `+++true+++` | Enables the set-request-host-header filter.
|
||||
@@ -106,7 +107,7 @@
|
||||
|spring.cloud.gateway.httpclient.websocket.proxy-ping | `+++true+++` | Proxy ping frames to downstream services, defaults to true.
|
||||
|spring.cloud.gateway.httpclient.wiretap | `+++false+++` | Enables wiretap debugging for Netty HttpClient.
|
||||
|spring.cloud.gateway.httpserver.wiretap | `+++false+++` | Enables wiretap debugging for Netty HttpServer.
|
||||
|spring.cloud.gateway.loadbalancer.use404 | `+++false+++` |
|
||||
|spring.cloud.gateway.loadbalancer.use404 | `+++false+++` |
|
||||
|spring.cloud.gateway.metrics.enabled | `+++false+++` | Enables the collection of metrics data.
|
||||
|spring.cloud.gateway.metrics.prefix | `+++spring.cloud.gateway+++` | The prefix of all metrics emitted by gateway.
|
||||
|spring.cloud.gateway.metrics.tags | | Tags map that added to metrics.
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -56,7 +56,7 @@
|
||||
<junit-pioneer.version>1.0.0</junit-pioneer.version>
|
||||
<spring-cloud-circuitbreaker.version>2.1.4-SNAPSHOT</spring-cloud-circuitbreaker.version>
|
||||
<spring-cloud-commons.version>3.1.4-SNAPSHOT</spring-cloud-commons.version>
|
||||
<testcontainers.version>1.16.3</testcontainers.version>
|
||||
<testcontainers.version>1.17.2</testcontainers.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
@@ -18,17 +18,18 @@ package org.springframework.cloud.gateway.tests.grpc;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import io.grpc.Grpc;
|
||||
import io.grpc.Server;
|
||||
import io.grpc.ServerCredentials;
|
||||
import io.grpc.TlsServerCredentials;
|
||||
import io.grpc.netty.shaded.io.grpc.netty.NettySslContextServerCredentials;
|
||||
import io.grpc.netty.shaded.io.netty.handler.ssl.ApplicationProtocolConfig;
|
||||
import io.grpc.netty.shaded.io.netty.handler.ssl.ApplicationProtocolNames;
|
||||
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder;
|
||||
import io.grpc.stub.StreamObserver;
|
||||
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
@@ -36,13 +37,8 @@ import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cloud.gateway.config.GRPCSSLContext;
|
||||
import org.springframework.cloud.gateway.route.RouteLocator;
|
||||
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.SocketUtils;
|
||||
|
||||
/**
|
||||
* @author Alberto C. Ríos
|
||||
@@ -51,40 +47,42 @@ import org.springframework.util.SocketUtils;
|
||||
@EnableAutoConfiguration
|
||||
public class GRPCApplication {
|
||||
|
||||
private static final int GRPC_SERVER_PORT = SocketUtils.findAvailableTcpPort();
|
||||
private static final int GRPC_SERVER_PORT = 8095;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(GRPCApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
|
||||
return builder.routes().route("json-grpc", r -> r.path("/json/hello").filters(f -> {
|
||||
String protoDescriptor = "file:src/main/proto/hello.pb";
|
||||
String protoFile = "file:src/main/proto/hello.proto";
|
||||
String service = "HelloService";
|
||||
String method = "hello";
|
||||
return f.jsonToGRPC(protoDescriptor, protoFile, service, method);
|
||||
}).uri("https://localhost:" + GRPC_SERVER_PORT))
|
||||
.route("grpc", r -> r.predicate(p -> true).uri("https://localhost:" + GRPC_SERVER_PORT)).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public GRPCSSLContext sslContext() throws SSLException {
|
||||
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
} };
|
||||
|
||||
return new GRPCSSLContext(trustAllCerts[0]);
|
||||
}
|
||||
// @Bean
|
||||
// public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
|
||||
// return builder.routes().route("json-grpc", r -> r.path("/json/hello").filters(f ->
|
||||
// {
|
||||
// String protoDescriptor = "file:src/main/proto/hello.pb";
|
||||
// String protoFile = "file:src/main/proto/hello.proto";
|
||||
// String service = "HelloService";
|
||||
// String method = "hello";
|
||||
// return f.jsonToGRPC(protoDescriptor, protoFile, service, method);
|
||||
// }).uri("https://localhost:" + GRPC_SERVER_PORT))
|
||||
// .route("grpc", r -> r.predicate(p -> true).uri("https://localhost:" +
|
||||
// GRPC_SERVER_PORT)).build();
|
||||
// }
|
||||
//
|
||||
// @Bean
|
||||
// public GRPCSSLContext sslContext() throws SSLException {
|
||||
// TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
|
||||
// public X509Certificate[] getAcceptedIssuers() {
|
||||
// return new X509Certificate[0];
|
||||
// }
|
||||
//
|
||||
// public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
||||
// }
|
||||
//
|
||||
// public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
||||
// }
|
||||
// } };
|
||||
//
|
||||
// return new GRPCSSLContext(trustAllCerts[0]);
|
||||
// }
|
||||
|
||||
@Component
|
||||
static class GRPCServer implements ApplicationRunner {
|
||||
@@ -100,8 +98,8 @@ public class GRPCApplication {
|
||||
private void start() throws Exception {
|
||||
/* The port on which the server should run */
|
||||
ServerCredentials creds = createServerCredentials();
|
||||
server = Grpc.newServerBuilderForPort(GRPC_SERVER_PORT, creds).addService(new HelloService()).build()
|
||||
.start();
|
||||
server = Grpc.newServerBuilderForPort(GRPC_SERVER_PORT, creds)
|
||||
.addService(new HelloService()).build().start();
|
||||
|
||||
System.out.println("Starting gRPC server in port " + GRPC_SERVER_PORT);
|
||||
|
||||
@@ -116,11 +114,31 @@ public class GRPCApplication {
|
||||
}
|
||||
|
||||
private ServerCredentials createServerCredentials() throws IOException {
|
||||
File certChain = new ClassPathResource("public.cert").getFile();
|
||||
File privateKey = new ClassPathResource("private.key").getFile();
|
||||
File certChain = new ClassPathResource("certificate.pem").getFile();
|
||||
File keystore = new ClassPathResource("keystore.p12").getFile();
|
||||
// return nettyCredentials(certChain, privateKey);
|
||||
return TlsServerCredentials.create(certChain, privateKey);
|
||||
}
|
||||
|
||||
private ServerCredentials nettyCredentials(File certChain, File privateKey)
|
||||
throws SSLException {
|
||||
ApplicationProtocolConfig apn = new ApplicationProtocolConfig(
|
||||
ApplicationProtocolConfig.Protocol.ALPN,
|
||||
// NO_ADVERTISE is currently the only mode supported by both OpenSsl
|
||||
// and JDK providers.
|
||||
ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
|
||||
// ACCEPT is currently the only mode supported by both OpenSsl and JDK
|
||||
// providers.
|
||||
ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
|
||||
ApplicationProtocolNames.HTTP_2, ApplicationProtocolNames.HTTP_1_1);
|
||||
|
||||
ServerCredentials serverCredentials = NettySslContextServerCredentials
|
||||
.create(SslContextBuilder.forServer(certChain, privateKey)
|
||||
.applicationProtocolConfig(apn).build());
|
||||
return serverCredentials;
|
||||
}
|
||||
|
||||
private void stop() throws InterruptedException {
|
||||
if (server != null) {
|
||||
server.shutdown().awaitTermination(30, TimeUnit.SECONDS);
|
||||
@@ -130,12 +148,15 @@ public class GRPCApplication {
|
||||
static class HelloService extends HelloServiceGrpc.HelloServiceImplBase {
|
||||
|
||||
@Override
|
||||
public void hello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {
|
||||
public void hello(HelloRequest request,
|
||||
StreamObserver<HelloResponse> responseObserver) {
|
||||
|
||||
String greeting = "Hello, " + request.getFirstName() + " " + request.getLastName();
|
||||
String greeting = "Hello, " + request.getFirstName() + " "
|
||||
+ request.getLastName();
|
||||
System.out.println("Sending response: " + greeting);
|
||||
|
||||
HelloResponse response = HelloResponse.newBuilder().setGreeting(greeting).build();
|
||||
HelloResponse response = HelloResponse.newBuilder().setGreeting(greeting)
|
||||
.build();
|
||||
|
||||
responseObserver.onNext(response);
|
||||
responseObserver.onCompleted();
|
||||
|
||||
0
spring-cloud-gateway-integration-tests/grpc/src/main/resources/application.yml
Normal file → Executable file
0
spring-cloud-gateway-integration-tests/grpc/src/main/resources/application.yml
Normal file → Executable file
@@ -1,21 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdzCCAl+gAwIBAgIEIon96DANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdV
|
||||
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
|
||||
VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du
|
||||
MB4XDTIxMDkyNzE2NDQwNVoXDTMxMDkyNTE2NDQwNVowbDEQMA4GA1UEBhMHVW5r
|
||||
bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE
|
||||
ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC
|
||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIwevGHY30YdoUdCSB/5q7/F
|
||||
c0KHetdjb71G2u6vFdeNvSwMpCV8Z1JznOJ/1zuY+0Z105QCPM7fi1ACi+tqxDR+
|
||||
L7yjUHhUEMTiGgCHcYJIZZCYfWS3BQXVxgORXhDv7RduCUaCLnkaFY++iPMTUy0C
|
||||
VxIkplIEhAmqcikIgWaa5ZjBkegKgahlPQLKlfD4Rz/kq2P+LLYFsHNNdKfWv6XQ
|
||||
u4LMw7ZEAJtfdpaMTzmtQipbTt6Dh87vIa0CIVnCPdlQ3o/5WeaxEA1pnfOLas07
|
||||
1VdHih2nC5vHhQcTPQDfa+uwzQvzHrchjuvMUUZaCYJzuT0G6nbGBba54EBT7yUC
|
||||
AwEAAaMhMB8wHQYDVR0OBBYEFKOHmfytP5ab2C4iFHlSklu6tCcuMA0GCSqGSIb3
|
||||
DQEBCwUAA4IBAQAdgWwdOtRbI796Z22weTBc0/tM8kLc6G0raNb08WyZMPZVki04
|
||||
jPh73pPQCgYeI/pq5JqH46KgvehmygTzpWDAFIllW0kgABVw3Nu6duV+blt1JG8T
|
||||
lWP7t5A+qDXgPDm3I5diii7O1YlLB3I37XiBdEV/+2WmF1VGQ7uBWAv+uotQeuW2
|
||||
JvHOr4ICOiW45TzRYtAbzWukSYKg/A7lwBs7HE9KVomUxNrkD+7+ugRuy/31pyen
|
||||
pHsEJQpx5juFRE222B6GXmX0w9xLIOapytl4EoPUx3K8Ecc+yI2q00UUC43x0v28
|
||||
c05YqwRZ5vp+jUnRxkxaz85YdArfR7QFYWtO
|
||||
-----END CERTIFICATE-----
|
||||
Binary file not shown.
56
spring-cloud-gateway-integration-tests/grpc/src/main/resources/private.key
Normal file → Executable file
56
spring-cloud-gateway-integration-tests/grpc/src/main/resources/private.key
Normal file → Executable file
@@ -1,32 +1,32 @@
|
||||
Bag Attributes
|
||||
friendlyName: mykey
|
||||
localKeyID: 54 69 6D 65 20 31 36 33 32 38 32 34 38 37 31 33 33 35
|
||||
friendlyName: bootapp
|
||||
localKeyID: 54 69 6D 65 20 31 36 35 39 37 31 32 34 31 30 37 34 35
|
||||
Key Attributes: <No Attributes>
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCMHrxh2N9GHaFH
|
||||
Qkgf+au/xXNCh3rXY2+9RtrurxXXjb0sDKQlfGdSc5zif9c7mPtGddOUAjzO34tQ
|
||||
AovrasQ0fi+8o1B4VBDE4hoAh3GCSGWQmH1ktwUF1cYDkV4Q7+0XbglGgi55GhWP
|
||||
vojzE1MtAlcSJKZSBIQJqnIpCIFmmuWYwZHoCoGoZT0CypXw+Ec/5Ktj/iy2BbBz
|
||||
TXSn1r+l0LuCzMO2RACbX3aWjE85rUIqW07eg4fO7yGtAiFZwj3ZUN6P+VnmsRAN
|
||||
aZ3zi2rNO9VXR4odpwubx4UHEz0A32vrsM0L8x63IY7rzFFGWgmCc7k9Bup2xgW2
|
||||
ueBAU+8lAgMBAAECggEAGu2xQJDAYCZDn4FCgTqnYkSdIRUOa6SFjfe3DZYCeZmY
|
||||
2IVZaobdCICFjxYIlECTUfhFADXp38wgZvEGWOj86iWyIOu2BFoLmvrlCmL9Uo99
|
||||
TWuw9ZEi2vs5gegHDvQ9OXqBN9a+/bEgoa55fVWib4z6lNcMS8joYz8pj28+ByzE
|
||||
LW0/3T3p6beM2fUcCJWn3d2M3wUgSuXmcdjVXJSkhEwKTVcc4vTTcOeF6xb2VZ/g
|
||||
Pozv/39G1qZ+QtM58yBiqnJ1Z2gtAk71l/1ztQa3uY22gzw8Kj5dmqcHgdiN5DWI
|
||||
bNE+k5Q93FzUmZNYPzmY6YVkdEzaNMtmi96sdtEu5QKBgQD36YdGXUyoRXeNDRuc
|
||||
yMXr6j/9/ewii+byHhFoUvjLuXWIQ06V+nOtYqohg/zgGIiC5LQ8EB0uFZDMhbDf
|
||||
kSwtoXbpUDLYD2OPgIyLaPqHiYQ9BampbUz5vHlfYLr0vB+Xp5r22Eb6nDQRRtb5
|
||||
EXHoYgAokgpYdeTIcdKRcB/2DwKBgQCQsPePeu7PagM9vYEo4zfbFxfY3Qkr4lOQ
|
||||
BCZ/tgsS0b0jAAxpfUH0/3O5oXizmB/5K7vgKqGnTuBWJJ/hdCWq27FkKxJ+8ejU
|
||||
8V9TFd5VQ89VeB5OekZwPks8vftwzW4L82ZRW5hvyQB0jPR+lwqjrNqds+xxH7i+
|
||||
c+RFx15biwKBgQCgkGGK0zao7YUGl+zAWNDHgQo9KM5deZr0SUEg/kwhNlbHEEC/
|
||||
plxxeauS1XdcdMdFb3bER/N+O31y2Uu7IL0qOJ9ZcRXdFep3sNxWFoHcctZw51AB
|
||||
accnIEjD21R62bTkditJoL4n5i9a2TS2T/QkfAR6QkvtCz5IDGBCzgoFRQKBgC51
|
||||
VBfy3gklPgMt/PHW+1FSuep9FnvLwQ8F9iKdnjKdu8AoPNQGTw5Ok6bwDOSFnQaR
|
||||
n1Kb/anN7sRaICfw9kNFJVFHbznpjNwK4JO5+tif3EvSNND3+/QAXIIVck3G+GXH
|
||||
8nt/EJQcExRZSgv3jYf+cXeflPTBvb0RUyOAn3B/AoGAM9aUi2dg3XjlDkZahQlY
|
||||
P5QNIr9BY25Ordga3GLwfR6rE+jiWTeTmreXBSJ7nvcaEQUNyFMX9n3v/QI84etk
|
||||
lMJkZ4o2TgzRnCsFJoBV36Ihsa6B5uXVWAvMRLKvwKpptKXfO0TnhUg7oKtN4t3a
|
||||
/FzAOS2Eu1PFP27z74gAMKY=
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCr+JyQOvGQcuSm
|
||||
t1BN615YtrI0IoRFxfWHcbvU26A3TiGQtlnvXUIUTZApm1uSLR0o2VeS6ph+i3Ku
|
||||
WFZTjF9wTem4IY8U22f4SymD7tFU/X4//YL0GgcyJCT/gGaYY58EVEH8+K3Pz1Hy
|
||||
z/UnNuRrttxo+u94tB3OgTAYBB1KqY7Bqe7iZGleNz5baatOzYfEXmW4owHmqnfE
|
||||
LZAmXdFj55Rbndkr0LBiKkBHM8aDC1l0OSJBzKt6RF07+we8Nte1Oynd2F3lZRHa
|
||||
D8Pk7leDuV+KjC4W0X6kkwvZftmT/Y9C18+t2+J1BAz0kMsDjH1P87BconqVEhcM
|
||||
PehXGgXFAgMBAAECggEAIzrxSBLrPf5rnUPcrbnUQDRdWZTgqDKf1DmWk0rTDcFx
|
||||
2uWgkwr16JbjO8LaBZ48ZQvxhuWMjBAhVFpAhSkyvB0aDmDBoTI5oII1ZRPdyp2L
|
||||
6awT0dIrOzhwY+94FSwDfa2NPzfq07HTRf0YagoyzWZOzSrrOD0eBhotMh5Vqd+w
|
||||
UJ3VJCAWC0/Nz/4N5Ia2Hkyn2fz4fXdzux+/s5UKqaEHCXQWYmHj0XFLYSUb9rrO
|
||||
qMYKM8sJjma4R3XthNalZEd6TD+07jNl6BwFmMBMj6D0VBWxV02woKkoWltmydUD
|
||||
XhkdikCAB33CvHoj56PqCAFHrI6tnSRs9UqF/HPGQQKBgQDlfTJ3l2Orq1hy/D3d
|
||||
8Z3ndOthwjm7QLOX8dJi4CHtymX8Lg4qfHcrs5ltoazXMYgdFHLX1rNs+gJg9I5p
|
||||
vQS2jpRJ3BMzddrHaXjqhHv8WY1VYkPGML2tPol51LU7fx+2g+YnMzWNB7AIUz9K
|
||||
OZkvlPWRO6jOcjvGgLjKARQUzQKBgQC/1mgGpKKBnAfEoDGZ1SWpI21BFKL3DWMx
|
||||
YaOeFx+DETfAoUeIu1Ge2u8AIhrNE4dT8xOcG0vwGzHhKV63pabbMZ4+2pE92SEw
|
||||
U6VsGvd/lcKPJvxgLS3xFQEzEmgL4v1mSBsxqaGZf4XHpdb32bQeybAQwUm25MCw
|
||||
sEq/ZkX02QKBgAJOvvoq4IqyX2JQnQKlUlQofdFu1YvHe8bUXKw32r98YIgnombU
|
||||
95HN7YYHsSg8zESWlw0KkKVQ4kM9Uk1H5Es9pcoUV3EWB0woCFo7WM/RyrUIFuxg
|
||||
QxgB3/oEpInjnlsEeoT8Y9Z2NFPxGlrRt3OeCNYcBneE+IrncnQ9jIklAoGACUF0
|
||||
/20OEibPESORgRSRnpmA+fTe8ACLWqSVWllPQemgwQCHDQfMpld11JHQrThV/Szr
|
||||
M0r13P3S6EQwt7ecV1MLiYjOHSfOvCAtCQw8CMHXA0UkRBep8cnLpwUqU/h9tWOh
|
||||
PEIs89T9RWaw+oBcemfMwOIyhkp/KYc39AghM/ECgYAdTIT7J613mg8Ck/eUOBwx
|
||||
udT1wbpcrCqHJX8TKWmBOLh9teZvmq7OIuXGudf1tDRjw85p/7bYBcG+gvaiH0Yf
|
||||
qz5Npr4/+knxI2CBF2m81ln4Otq3X5siDL1wPCswawpnfdH+0qyfH6nxeGy0XSj2
|
||||
IQMa/LX1XqbUCry4sFl0yQ==
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
21
spring-cloud-gateway-integration-tests/grpc/src/main/resources/public.cert
Executable file
21
spring-cloud-gateway-integration-tests/grpc/src/main/resources/public.cert
Executable file
@@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDezCCAmOgAwIBAgIIAZ+HRnyzONYwDQYJKoZIhvcNAQELBQAwbDEQMA4GA1UE
|
||||
BhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQ
|
||||
MA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5r
|
||||
bm93bjAeFw0yMjA4MDUxNTEzMzBaFw0zMjA4MDIxNTEzMzBaMGwxEDAOBgNVBAYT
|
||||
B1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vua25vd24xEDAO
|
||||
BgNVBAoTB1Vua25vd24xEDAOBgNVBAsTB1Vua25vd24xEDAOBgNVBAMTB1Vua25v
|
||||
d24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCr+JyQOvGQcuSmt1BN
|
||||
615YtrI0IoRFxfWHcbvU26A3TiGQtlnvXUIUTZApm1uSLR0o2VeS6ph+i3KuWFZT
|
||||
jF9wTem4IY8U22f4SymD7tFU/X4//YL0GgcyJCT/gGaYY58EVEH8+K3Pz1Hyz/Un
|
||||
NuRrttxo+u94tB3OgTAYBB1KqY7Bqe7iZGleNz5baatOzYfEXmW4owHmqnfELZAm
|
||||
XdFj55Rbndkr0LBiKkBHM8aDC1l0OSJBzKt6RF07+we8Nte1Oynd2F3lZRHaD8Pk
|
||||
7leDuV+KjC4W0X6kkwvZftmT/Y9C18+t2+J1BAz0kMsDjH1P87BconqVEhcMPehX
|
||||
GgXFAgMBAAGjITAfMB0GA1UdDgQWBBTC2DG76TuGW8VAEJawy96C2VPBpDANBgkq
|
||||
hkiG9w0BAQsFAAOCAQEAduMMKQvGMMbmN6OdnrV9oBzpphKs1BWvbDBPsSrFm1zX
|
||||
d1yRLSn2GyICQIA7SNX6Z59rWHe2HSXtzW6gbXm0yvAcPBI1DcRbamO12VF75Xjl
|
||||
yg9oGuwckIcK2YtqYw7iTjFHyDFShTdWpYePxmyZ4HyZKWX3gKn1hGHA0SWYUJY+
|
||||
HkfPat0iwuwXDfAoyMchZrd7mOsXAhlD6+39gw9Vr+WhRFhv29hU8uuzcY+ahZfQ
|
||||
9H8OF2nW0ePcc41909uorWfa3hWAVA2xfvzoBunFVMJt6mzT5M2Es5I/0wSXflbU
|
||||
e4NjO4usVx7aU3jPkHEPGlDrwFJ8olDpKPutr2dGVA==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -58,6 +58,7 @@ public class JsonToGrpcApplicationTests {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
restTemplate = createUnsecureClient();
|
||||
// restTemplate = new RestTemplate();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -7,6 +7,15 @@ server:
|
||||
key-store-password: password
|
||||
key-password: password
|
||||
enabled: true
|
||||
key-alias: bootapp
|
||||
# key-store-provider: SUN
|
||||
# trust-certificate: classpath:certificate.pem
|
||||
# trust-certificate-private-key: classpath:private.key
|
||||
# trust-store: classpath:keystore.jks
|
||||
# trust-store-password: password
|
||||
# trust-certificate-private-key: classpath:private.key
|
||||
# trust-store-provider: classpath:keystore.jks
|
||||
|
||||
spring:
|
||||
cloud:
|
||||
gateway:
|
||||
@@ -20,6 +29,22 @@ spring:
|
||||
key-store-password: password
|
||||
key-password: password
|
||||
use-insecure-trust-manager: true
|
||||
# key-store-type: JKS
|
||||
# key-store: classpath:keystore.jks
|
||||
# key-store-password: password
|
||||
# trusted-x509-certificates: classpath:certificate.pem
|
||||
# trust-store: classpath:keystore.jks
|
||||
# trust-store-password: password
|
||||
# trust-certificate-private-key: classpath:private.key
|
||||
# key-store-provider: classpath:keystore.jks
|
||||
# key-password: password
|
||||
|
||||
routes:
|
||||
- uri: https://localhost:8095
|
||||
predicates:
|
||||
- Path=/json/hello
|
||||
filters:
|
||||
- JsonToGrpc=file:src/main/proto/hello.pb,file:src/main/proto/hello.proto,HelloService,hello
|
||||
|
||||
logging:
|
||||
level:
|
||||
|
||||
@@ -163,6 +163,50 @@ public class GatewayControllerEndpointTests {
|
||||
.expectStatus().isCreated();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostValidShortcutRouteDefinition() {
|
||||
// 04-08-2022 08:41:31.866 [reactor-http-epoll-1] TRACE org.springframework.web.HttpLogging.trace - [0a3d20a5-43] Decoded [RouteDefinition{id='gatewaywithgrpcfiltertest-0-104014-8916263311295787431172436062-test-gateway-tls-client-mapping-0', predicates=[PredicateDefinition{name='Path', args={_genkey_0=/json/hello}}], filters=[FilterDefinition{name='StripPrefix', args={_genkey_0=1}}, FilterDefinition{name='JsonToGrpcGatewayFilterFactory', args={_genkey_0=file:src/main/proto/hello.pb, _genkey_1=file:src/main/proto/hello.proto, _genkey_2=HelloService, _genkey_3=hello}}], uri=https://localhost:8095, order=0, metadata={}}]
|
||||
// 04-08-2022 08:41:31.870 [reactor-http-epoll-1] WARN o.s.c.g.a.GatewayControllerEndpoint.handleUnavailableDefinition - Invalid FilterDefinition: [JsonToGrpcGatewayFilterFactory]
|
||||
// 04-08-2022 08:41:31.882 [reactor-http-epoll-1] DEBUG o.s.w.s.h.ResponseStatusExceptionHandler.handle - [0a3d20a5-43] Resolved [ResponseStatusException: "400 BAD_REQUEST "Invalid FilterDefinition: [JsonToGrpcGatewayFilterFactory]""] for HTTP POST /actuator/gateway/routes/gatewaywithgrpcfiltertest-0-104014-8916263311295787431172436062-test-gateway-tls-client-mapping-0
|
||||
// 04-08-2022 08:41:31.883 [reactor-http-epoll-1] TRACE o.s.w.s.a.HttpWebHandlerAdapter.traceDebug - [0a3d20a5-43] Completed 400 BAD_REQUEST, headers={masked}
|
||||
//
|
||||
//[RouteDefinition{id='gatewaywithgrpcfiltertest-0-104014-8916263311295787431172436062-test-gateway-tls-client-mapping-0',
|
||||
// predicates=[PredicateDefinition{name='Path', args={_genkey_0=/json/hello}}],
|
||||
// filters=[FilterDefinition{name='StripPrefix', args={_genkey_0=1}},
|
||||
// FilterDefinition{name='JsonToGrpcGatewayFilterFactory',
|
||||
// args={_genkey_0=file:src/main/proto/hello.pb, _genkey_1=file:src/main/proto/hello.proto, _genkey_2=HelloService, _genkey_3=hello}}],
|
||||
|
||||
// uri=https://localhost:8095, order=0, metadata={}}]
|
||||
|
||||
RouteDefinition testRouteDefinition = new RouteDefinition();
|
||||
testRouteDefinition.setId("gatewaywithgrpcfiltertest-0-104014-8916263311295787431172436062-test-gateway-tls-client-mapping-0");
|
||||
testRouteDefinition.setUri(URI.create("https://localhost:8095"));
|
||||
testRouteDefinition.setOrder(0);
|
||||
testRouteDefinition.setMetadata(Collections.emptyMap());
|
||||
|
||||
FilterDefinition longFilterDefinition = new FilterDefinition();
|
||||
FilterDefinition stripPrefix = new FilterDefinition();
|
||||
stripPrefix.setName("StripPrefix");
|
||||
stripPrefix.addArg("_genkey_0","1");
|
||||
|
||||
longFilterDefinition.setName("JsonToGrpc");
|
||||
longFilterDefinition.addArg("_genkey_0","file:src/main/proto/hello.pb");
|
||||
longFilterDefinition.addArg("_genkey_1","file:src/main/proto/hello.proto");
|
||||
longFilterDefinition.addArg("_genkey_2","HelloService");
|
||||
longFilterDefinition.addArg("_genkey_3","hello");
|
||||
testRouteDefinition.setFilters(Collections.singletonList(longFilterDefinition));
|
||||
|
||||
PredicateDefinition hostRoutePredicateDefinition = new PredicateDefinition();
|
||||
hostRoutePredicateDefinition.setName("Path");
|
||||
hostRoutePredicateDefinition.addArg("_genkey_0","/json/hello");
|
||||
testRouteDefinition.setPredicates(
|
||||
Arrays.asList(hostRoutePredicateDefinition));
|
||||
|
||||
testClient.post().uri("http://localhost:" + port + "/actuator/gateway/routes/test-route")
|
||||
.accept(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(testRouteDefinition)).exchange()
|
||||
.expectStatus().isCreated();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostRouteWithNotExistingFilter() {
|
||||
|
||||
|
||||
@@ -1,127 +1,127 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.gateway.route.builder
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest
|
||||
import org.springframework.mock.web.server.MockServerWebExchange
|
||||
import org.springframework.test.context.junit4.SpringRunner
|
||||
import org.springframework.web.server.ServerWebExchange
|
||||
import reactor.core.publisher.toMono
|
||||
import reactor.test.StepVerifier
|
||||
import java.net.URI
|
||||
|
||||
@RunWith(SpringRunner::class)
|
||||
@SpringBootTest(classes = arrayOf(Config::class))
|
||||
class RouteDslTests {
|
||||
|
||||
@Autowired
|
||||
lateinit var builder: RouteLocatorBuilder
|
||||
|
||||
@Test
|
||||
fun sampleRouteDsl() {
|
||||
val routeLocator = builder.routes {
|
||||
route(id = "test") {
|
||||
host("**.abc.org") and path("/image/png")
|
||||
filters {
|
||||
addResponseHeader("X-TestHeader", "foobar")
|
||||
}
|
||||
uri("http://httpbin.org:80")
|
||||
}
|
||||
|
||||
route(id = "test2") {
|
||||
path("/image/webp") or path("/image/anotherone")
|
||||
filters {
|
||||
addResponseHeader("X-AnotherHeader", "baz")
|
||||
addResponseHeader("X-AnotherHeader-2", "baz-2")
|
||||
}
|
||||
uri("https://httpbin.org:443")
|
||||
}
|
||||
}
|
||||
|
||||
StepVerifier
|
||||
.create(routeLocator.routes)
|
||||
.expectNextMatches({
|
||||
it.id == "test" && it.filters.size == 1 && it.uri == URI.create("http://httpbin.org:80")
|
||||
})
|
||||
.expectNextMatches({
|
||||
it.id == "test2" && it.filters.size == 2 && it.uri == URI.create("https://httpbin.org:443")
|
||||
})
|
||||
.expectComplete()
|
||||
.verify()
|
||||
|
||||
val sampleExchange: ServerWebExchange = MockServerWebExchange.from(MockServerHttpRequest.get("/image/webp")
|
||||
.header("Host", "test.abc.org").build())
|
||||
|
||||
val filteredRoutes = routeLocator.routes.filter({
|
||||
sampleExchange.attributes.put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR, it.id)
|
||||
it.predicate.apply(sampleExchange).toMono().block()
|
||||
})
|
||||
|
||||
StepVerifier.create(filteredRoutes)
|
||||
.expectNextMatches({
|
||||
it.id == "test2" && it.filters.size == 2 && it.uri == URI.create("https://httpbin.org:443")
|
||||
})
|
||||
.expectComplete()
|
||||
.verify()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dslWithFunctionParameters() {
|
||||
val routerLocator = builder.routes {
|
||||
route(id = "test1", order = 10, uri = "http://httpbin.org") {
|
||||
host("**.abc.org")
|
||||
}
|
||||
route(id = "test2", order = 10, uri = "http://someurl") {
|
||||
host("**.abc.org")
|
||||
uri("http://override-url")
|
||||
}
|
||||
}
|
||||
|
||||
StepVerifier.create(routerLocator.routes)
|
||||
.expectNextMatches({
|
||||
it.id == "test1" &&
|
||||
it.uri == URI.create("http://httpbin.org:80") &&
|
||||
it.order == 10 &&
|
||||
it.predicate.apply(MockServerWebExchange
|
||||
.from(MockServerHttpRequest
|
||||
.get("/someuri").header("Host", "test.abc.org")))
|
||||
.toMono().block()
|
||||
})
|
||||
.expectNextMatches({
|
||||
it.id == "test2" &&
|
||||
it.uri == URI.create("http://override-url:80") &&
|
||||
it.order == 10 &&
|
||||
it.predicate.apply(MockServerWebExchange
|
||||
.from(MockServerHttpRequest
|
||||
.get("/someuri").header("Host", "test.abc.org")))
|
||||
.toMono().block()
|
||||
})
|
||||
.expectComplete()
|
||||
.verify()
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration
|
||||
open class Config {}
|
||||
///*
|
||||
// * Copyright 2013-2020 the original author or authors.
|
||||
// *
|
||||
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// * you may not use this file except in compliance with the License.
|
||||
// * You may obtain a copy of the License at
|
||||
// *
|
||||
// * https://www.apache.org/licenses/LICENSE-2.0
|
||||
// *
|
||||
// * Unless required by applicable law or agreed to in writing, software
|
||||
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// * See the License for the specific language governing permissions and
|
||||
// * limitations under the License.
|
||||
// */
|
||||
//
|
||||
//package org.springframework.cloud.gateway.route.builder
|
||||
//
|
||||
//import org.junit.Test
|
||||
//import org.junit.runner.RunWith
|
||||
//import org.springframework.beans.factory.annotation.Autowired
|
||||
//import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
//import org.springframework.boot.test.context.SpringBootTest
|
||||
//import org.springframework.cloud.gateway.support.ServerWebExchangeUtils
|
||||
//import org.springframework.context.annotation.Configuration
|
||||
//import org.springframework.mock.http.server.reactive.MockServerHttpRequest
|
||||
//import org.springframework.mock.web.server.MockServerWebExchange
|
||||
//import org.springframework.test.context.junit4.SpringRunner
|
||||
//import org.springframework.web.server.ServerWebExchange
|
||||
//import reactor.core.publisher.toMono
|
||||
//import reactor.test.StepVerifier
|
||||
//import java.net.URI
|
||||
//
|
||||
//@RunWith(SpringRunner::class)
|
||||
//@SpringBootTest(classes = arrayOf(Config::class))
|
||||
//class RouteDslTests {
|
||||
//
|
||||
// @Autowired
|
||||
// lateinit var builder: RouteLocatorBuilder
|
||||
//
|
||||
// @Test
|
||||
// fun sampleRouteDsl() {
|
||||
// val routeLocator = builder.routes {
|
||||
// route(id = "test") {
|
||||
// host("**.abc.org") and path("/image/png")
|
||||
// filters {
|
||||
// addResponseHeader("X-TestHeader", "foobar")
|
||||
// }
|
||||
// uri("http://httpbin.org:80")
|
||||
// }
|
||||
//
|
||||
// route(id = "test2") {
|
||||
// path("/image/webp") or path("/image/anotherone")
|
||||
// filters {
|
||||
// addResponseHeader("X-AnotherHeader", "baz")
|
||||
// addResponseHeader("X-AnotherHeader-2", "baz-2")
|
||||
// }
|
||||
// uri("https://httpbin.org:443")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// StepVerifier
|
||||
// .create(routeLocator.routes)
|
||||
// .expectNextMatches({
|
||||
// it.id == "test" && it.filters.size == 1 && it.uri == URI.create("http://httpbin.org:80")
|
||||
// })
|
||||
// .expectNextMatches({
|
||||
// it.id == "test2" && it.filters.size == 2 && it.uri == URI.create("https://httpbin.org:443")
|
||||
// })
|
||||
// .expectComplete()
|
||||
// .verify()
|
||||
//
|
||||
// val sampleExchange: ServerWebExchange = MockServerWebExchange.from(MockServerHttpRequest.get("/image/webp")
|
||||
// .header("Host", "test.abc.org").build())
|
||||
//
|
||||
// val filteredRoutes = routeLocator.routes.filter({
|
||||
// sampleExchange.attributes.put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR, it.id)
|
||||
// it.predicate.apply(sampleExchange).toMono().block()
|
||||
// })
|
||||
//
|
||||
// StepVerifier.create(filteredRoutes)
|
||||
// .expectNextMatches({
|
||||
// it.id == "test2" && it.filters.size == 2 && it.uri == URI.create("https://httpbin.org:443")
|
||||
// })
|
||||
// .expectComplete()
|
||||
// .verify()
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// fun dslWithFunctionParameters() {
|
||||
// val routerLocator = builder.routes {
|
||||
// route(id = "test1", order = 10, uri = "http://httpbin.org") {
|
||||
// host("**.abc.org")
|
||||
// }
|
||||
// route(id = "test2", order = 10, uri = "http://someurl") {
|
||||
// host("**.abc.org")
|
||||
// uri("http://override-url")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// StepVerifier.create(routerLocator.routes)
|
||||
// .expectNextMatches({
|
||||
// it.id == "test1" &&
|
||||
// it.uri == URI.create("http://httpbin.org:80") &&
|
||||
// it.order == 10 &&
|
||||
// it.predicate.apply(MockServerWebExchange
|
||||
// .from(MockServerHttpRequest
|
||||
// .get("/someuri").header("Host", "test.abc.org")))
|
||||
// .toMono().block()
|
||||
// })
|
||||
// .expectNextMatches({
|
||||
// it.id == "test2" &&
|
||||
// it.uri == URI.create("http://override-url:80") &&
|
||||
// it.order == 10 &&
|
||||
// it.predicate.apply(MockServerWebExchange
|
||||
// .from(MockServerHttpRequest
|
||||
// .get("/someuri").header("Host", "test.abc.org")))
|
||||
// .toMono().block()
|
||||
// })
|
||||
// .expectComplete()
|
||||
// .verify()
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//@Configuration(proxyBeanMethods = false)
|
||||
//@EnableAutoConfiguration
|
||||
//open class Config {}
|
||||
Reference in New Issue
Block a user