Not able to bypass javax.net.ssl.SSLHandshakeException: General SSLEngine problem - spring-boot

I do understand it is not a best practice to bypass SSL certification
but for my local testing I need that. So I have two secured(https)
localhost and I want to access the second localhost from the first
one using spring gateway
For generating SSL certificate I have used this link
https://howtodoinjava.com/spring-boot/spring-boot-ssl-https-example/
To bypass SSL check I have added this piece of the code in the main class for both gateway and consumer
public static void main(String[] args) {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
System.out.println("Error" + e);
}
SpringApplication.run(Gateway.class, args);
}
Yet I am still getting this handshake exception. What I am missing?
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:477) ~[netty-codec-4.1.66.Final.jar:4.1.66.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276) ~[netty-codec-4.1.66.Final.jar:4.1.66.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-transport-4.1.66.Final.jar:4.1.66.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-transport-4.1.66.Final.jar:4.1.66.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-transport-4.1.66.Final.jar:4.1.66.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) [netty-transport-4.1.66.Final.jar:4.1.66.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-transport-4.1.66.Final.jar:4.1.66.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-transport-4.1.66.Final.jar:4.1.66.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) [netty-transport-4.1.66.Final.jar:4.1.66.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) [netty-transport-4.1.66.Final.jar:4.1.66.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719) [netty-transport-4.1.66.Final.jar:4.1.66.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655) [netty-transport-4.1.66.Final.jar:4.1.66.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581) [netty-transport-4.1.66.Final.jar:4.1.66.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) [netty-transport-4.1.66.Final.jar:4.1.66.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) [netty-common-4.1.66.Final.jar:4.1.66.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-common-4.1.66.Final.jar:4.1.66.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-common-4.1.66.Final.jar:4.1.66.Final]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_301]
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alert.createSSLException(Alert.java:131) ~[na:1.8.0_301]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ HTTP GET "/consumer" [ExceptionHandlingWebHandler]

Apparently there is a hack in spring boot gateway to achieve this
spring.cloud.gateway.httpclient.ssl.use-insecure-trust-manager=true

You could check who is calling hostname verifier (via catching Exception with a breakpoint).. your stack might be not exactly the same as in tutorial someone wrote 1 year ago.
In my case I had to add
#Bean
public TLSProtocolConfigurer tlsProtocolConfigurer() {
TLSProtocolConfigurer tlsProtocolConfigurer = new TLSProtocolConfigurer();
tlsProtocolConfigurer.setSslHostnameVerification("allowAll");
return tlsProtocolConfigurer;
}
Have you checked that thread?
Unable to find valid certification path to requested target - error even after cert imported

Related

Azure SDK JAVA - How to use ProxyOptions to connect to the proxy URL and how to pass the required path to the httpClient along with the hostname

I am trying utilise the ProxyOptions to re-route the blob upload to a proxy URL. In this case localhost
Demo Project:
Gradle Dependency:
implementation 'com.azure:azure-storage-blob'
implementation 'com.azure:azure-core'
implementation 'com.azure:azure-core-http-netty'
implementation 'com.azure:azure-identity'
implementation 'com.azure:azure-security-keyvault-secrets'
implementation ('com.azure.resourcemanager:azure-resourcemanager:2.18.0') {
exclude group: 'com.azure', module: 'azure-core'
}
configurations.all{
resolutionStrategy{
force 'com.azure:azure-storage-common:12.18.0', 'com.azure:azure-storage-common:12.14.3'
}
}
#Bean
public BlobClient blobClient() throws URISyntaxException, UnknownHostException {
HttpClient client = new NettyAsyncHttpClientBuilder()
.proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("localhost", 8080)))
.build();
String accountName = "xxxx";
String accountkey = "yyyyy";
String endPoint = String.format(java.util.Locale.ROOT, "https://%s.blob.core.windows.net", accountName);
BlobClient blobClient = new BlobClientBuilder()
.endpoint(endPoint)
.credential(new StorageSharedKeyCredential(accountName, accountkey))
.containerName("test-bucket-1")
.blobName("test.txt")
.httpClient(client)
.buildClient();
return blobClient;
}
and the controller which consumes the above blobClient:
#PutMapping(value ={"/azure/test"})
public boolean uploadAzureBlob(
#RequestParam("containerName") String containerName,
#RequestParam("blobName") Optional\<String\> blobName,
HttpServletRequest request, HttpServletResponse response) throws IOException, URISyntaxException {
InputStream inputStream = request.getInputStream();
BinaryData binaryData = BinaryData.fromStream(inputStream);
BlobParallelUploadOptions blobParallelUploadOptions = new BlobParallelUploadOptions(binaryData);
Response\<BlockBlobItem\> blobItemResponse =
blobClient.uploadWithResponse(
blobParallelUploadOptions,
Duration.ofSeconds(120L),
Context.NONE);
return true;
}
When the blobClient is trying to upload the blob object it should re-route to the following controller which is running in my local machine. I want to basically intercept the API call and redirect it to the proxy application running in my local. At least to the #RequestMapping(value ={"\*"})
Proxy Project:
Gradle Dependency:
implementation platform('com.azure:azure-sdk-bom:1.1.1')
implementation 'com.azure:azure-storage-blob'
implementation 'com.azure:azure-core'
implementation 'com.azure:azure-core-http-netty'
implementation 'com.azure:azure-identity'
implementation 'com.azure:azure-security-keyvault-secrets'
implementation ('com.azure.resourcemanager:azure-resourcemanager:2.18.0') {
exclude group: 'com.azure', module: 'azure-core'
}
configurations.all{
resolutionStrategy{
force 'com.azure:azure-storage-common:12.18.0', 'com.azure:azure-storage-common:12.14.3'
}
}
The controller code of the proxy:
#RequestMapping("/v2/azure-proxy")
public class AzureBlobProxyController {
#PutMapping(value ={"/{containerName}/{blobName}"})
public boolean uploadSecureStream(#PathVariable("containerName") String containerName,
#PathVariable("blobName") String blobName,
HttpServletRequest request, HttpServletResponse response) throws Exception
{
return true;
}
#RequestMapping(value ={"/*"})
public boolean getBlobContainerAsyncClient(
HttpServletRequest request,
HttpServletResponse httpServletResponse) throws Exception
{
return true;
}
}
But i am getting the following exception:
2022-11-28 00:22:12.535 WARN 86304 --- \[r-http-kqueue-1\] r.netty.http.client.HttpClientConnect : \[c80a00e1, L:/127.0.0.1:54822 - R:localhost/127.0.0.1:8080\] The connection observed an error
javax.net.ssl.SSLException: failure when writing TLS control frames
at io.netty.handler.ssl.SslHandler.setHandshakeFailureTransportFailure(SslHandler.java:1896) \~\[netty-handler-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.handler.ssl.SslHandler.access$600(SslHandler.java:168) \~\[netty-handler-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.handler.ssl.SslHandler$2.operationComplete(SslHandler.java:933) \~\[netty-handler-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.handler.ssl.SslHandler$2.operationComplete(SslHandler.java:928) \~\[netty-handler-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:578) \~\[netty-common-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:552) \~\[netty-common-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:491) \~\[netty-common-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:616) \~\[netty-common-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.util.concurrent.DefaultPromise.setFailure0(DefaultPromise.java:609) \~\[netty-common-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.util.concurrent.DefaultPromise.tryFailure(DefaultPromise.java:117) \~\[netty-common-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.PendingWriteQueue.safeFail(PendingWriteQueue.java:288) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.PendingWriteQueue.removeAndFailAll(PendingWriteQueue.java:186) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.handler.proxy.ProxyHandler.failPendingWrites(ProxyHandler.java:434) \~\[netty-handler-proxy-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.handler.proxy.ProxyHandler.failPendingWritesAndClose(ProxyHandler.java:351) \~\[netty-handler-proxy-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.handler.proxy.ProxyHandler.setConnectFailure(ProxyHandler.java:346) \~\[netty-handler-proxy-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.handler.proxy.ProxyHandler.channelRead(ProxyHandler.java:266) \~\[netty-handler-proxy-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:327) \~\[netty-codec-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:299) \~\[netty-codec-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.handler.proxy.HttpProxyHandler$HttpClientCodecWrapper.channelRead(HttpProxyHandler.java:272) \~\[netty-handler-proxy-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) \~\[netty-transport-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.kqueue.AbstractKQueueStreamChannel$KQueueStreamUnsafe.readReady(AbstractKQueueStreamChannel.java:544) \~\[netty-transport-classes-kqueue-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.kqueue.AbstractKQueueChannel$AbstractKQueueUnsafe.readReady(AbstractKQueueChannel.java:383) \~\[netty-transport-classes-kqueue-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.kqueue.KQueueEventLoop.processReady(KQueueEventLoop.java:211) \~\[netty-transport-classes-kqueue-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.channel.kqueue.KQueueEventLoop.run(KQueueEventLoop.java:289) \~\[netty-transport-classes-kqueue-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:995) \~\[netty-common-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) \~\[netty-common-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) \~\[netty-common-4.1.77.Final.jar:4.1.77.Final\]
at java.base/java.lang.Thread.run(Thread.java:832) \~\[na:na\]
Caused by: io.netty.handler.proxy.HttpProxyHandler$HttpProxyConnectException: http, none, localhost/127.0.0.1:8080 =\> xxxx.blob.core.windows.net/\<unresolved\>:443, status: 400
at io.netty.handler.proxy.HttpProxyHandler.handleResponse(HttpProxyHandler.java:200) \~\[netty-handler-proxy-4.1.77.Final.jar:4.1.77.Final\]
at io.netty.handler.proxy.ProxyHandler.channelRead(ProxyHandler.java:257) \~\[netty-handler-proxy-4.1.77.Final.jar:4.1.77.Final\]
... 23 common frames omitted
Caused by: io.netty.handler.proxy.HttpProxyHandler$HttpProxyConnectException: http, none, localhost/127.0.0.1:8080 =\> xxxx.blob.core.windows.net/\<unresolved\>:443, status: 400
How to fix the above issue and how can i make the proxy reach the #RequestMapping("/v2/azure-proxy"). In the socketAddress i am able to give hostname how can i give the path variables?
I have tried using the com.azure.core.http.HttpClient to re-route:
HttpClient client = new NettyAsyncHttpClientBuilder()
.proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("localhost", 8080)))
.build();
but i need to be able to use the proxy path:
http://localhost:8080/v2/azure-proxy

SSL Exception Tag mismatch error, with spring webflux webclient requests

I just converted a service to the webflux/netty stack (formerly it was mvc/undertow)
This service makes https requests to downstream services using spring webclient(formerly okHttp client).
The service is built with JDK 17 (and runs on JVM 18)
On the production environment, we are experiencing SSL errors starting after some time (15 minutes or up to 120 minutes) which increases over time. If the service is restarted, the errors are gone, until they start again later.
The exception I get:
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLException: Tag mismatch
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:480)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:279)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:800)
at io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe$1.run(AbstractEpollChannel.java:425)
at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:391)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:995)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: javax.net.ssl.SSLException: Tag mismatch
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:133)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:371)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:314)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:309)
at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:123)
at java.base/sun.security.ssl.SSLEngineImpl.decode(SSLEngineImpl.java:736)
at java.base/sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:691)
at java.base/sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:506)
at java.base/sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:482)
at java.base/javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:679)
at io.netty.handler.ssl.SslHandler$SslEngineType$3.unwrap(SslHandler.java:295)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1342)
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1235)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1284)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:510)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:449)
... 18 common frames omitted
Caused by: javax.crypto.AEADBadTagException: Tag mismatch
at java.base/com.sun.crypto.provider.GaloisCounterMode$GCMDecrypt.doFinal(GaloisCounterMode.java:1591)
at java.base/com.sun.crypto.provider.GaloisCounterMode.engineDoFinal(GaloisCounterMode.java:454)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2501)
at java.base/sun.security.ssl.SSLCipher$T12GcmReadCipherGenerator$GcmReadCipher.decrypt(SSLCipher.java:1659)
at java.base/sun.security.ssl.SSLEngineInputRecord.decodeInputRecord(SSLEngineInputRecord.java:239)
at java.base/sun.security.ssl.SSLEngineInputRecord.decode(SSLEngineInputRecord.java:196)
at java.base/sun.security.ssl.SSLEngineInputRecord.decode(SSLEngineInputRecord.java:159)
at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:111)
... 29 common frames omitted
The webclient config code:
#Bean
public WebClient webClient(MetricsWebClientCustomizer metricsCustomizer,
WebClient.Builder builder,
#Value("${s2s.client.read-timeout-ms}") int readTimeoutMs) throws SSLException {
metricsCustomizer.customize(builder);
HttpClient httpClient = createNettyHttpClient(readTimeoutMs);
WebClient webClient = builder
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
// warming up web client to allow smooth first requests
httpClient.warmup().subscribe((ignored) -> log.info("web client initialized"));
return webClient;
}
private HttpClient createNettyHttpClient(int readTimeoutMs) throws SSLException {
final ConnectionProvider connectionProvider = ConnectionProvider
.builder("webclient-connection-provider")
.maxIdleTime(Duration.ofSeconds(poolConnectionMaxIdleTimeSeconds))
.maxConnections(maxConnections)
.pendingAcquireMaxCount(pendingAcquireMaxCount)
.build();
return HttpClient.create(connectionProvider)
.doOnConnected(
c -> c.addHandlerLast(new ReadTimeoutHandler(readTimeoutMs))
.addHandlerLast(new WriteTimeoutHandler(readTimeoutMs)))
.option(CONNECT_TIMEOUT_MILLIS, readTimeoutMs)
.compress(true)
.runOn(LoopResources.create("eventloop-webclient", nettyWorkerThreadsCount, true));
}

Loop redirect when login OAuth2.0 Login + Webflux Security

I am developing authentication and authorization in an environment where I use Spring Cloud Gateway Webflux + OAuth 2.0 the structure to achieve is the following:
As Authorization Server I have my own OAuth server that contains the /login page where I perform the authentication and it is also in charge of generating JWT and as Resource Server I have a WebFlux module that is also in charge of being the Gateway.
The Resource Server configuration is as follows:
application.yml
spring:
application:
name: spring-boot-gateway
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://adp-auth-provider/auth/oauth/token
client:
registration:
oauth:
client-name: oauth
client-id: first-client
client-secret: xxxxxx
provider: adp-auth-provider
authorization-grant-type: authorization_code
redirect-uri: /login
scope: read
provider:
adp-auth-provider:
authorization-uri: /auth/oauth/authorize
token-uri: http://adp-auth-provider/auth/oauth/token
user-info-uri: http://adp-auth-provider/userinfo
jwt-set-uri: http://adp-auth-provider/token_keys
WebFluxSecurityConfig.java
#Configuration(proxyBeanMethods = false)
#EnableWebFluxSecurity
#EnableReactiveMethodSecurity
public class WebFluxSecurityConfig {
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http
.httpBasic().disable()
.csrf().disable()
.authorizeExchange(exchanges -> exchanges
.pathMatchers(HttpMethod.GET, "/oauth2/authorization/**",
"/actuator",
"/actuator/**",
"/auth/login",
"/login")
.permitAll()
.anyExchange()
.authenticated()
.oauth2Login()
.and()
.build();
}
}
SpringGatewayApplication.java
#SpringBootApplication
public class SpringGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(SpringGatewayApplication.class, args);
}
}
When I type http://localhost in the browser, it redirects perfectly to the OAuth /login page, but when I enter my credentials it redirects me to the next page:
The requests appear to have been the right ones:
Does anyone know why I am not redirected to the index once I have logged in correctly? It stays on that page and if I click on oauth it redirects me to the same page again.
**EDIT:
Setting redirect-uri to the default "{baseUrl}/login/oauth2/code/{registrationId}" displays the following error:
2022-01-18 12:12:15.852 ERROR 2836 --- [ctor-http-nio-6] a.w.r.e.AbstractErrorWebExceptionHandler : [477242e5-1] 500 Server Error for HTTP GET "/login/oauth2/code/oauth?code=nTCRNi&state=Ub8jQjbp1baxhgsxcpNULMMHoV8z42bQsp62iL2jNV8%3D"
java.lang.IllegalStateException: No provider found for class org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken
at org.springframework.security.web.server.authentication.AuthenticationWebFilter.lambda$authenticate$6(AuthenticationWebFilter.java:123) ~[spring-security-web-5.6.0.jar:5.6.0]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
*__checkpoint ⇢ org.springframework.security.oauth2.client.web.server.authentication.OAuth2LoginAuthenticationWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ org.springframework.security.oauth2.client.web.server.OAuth2AuthorizationRequestRedirectWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ org.springframework.security.web.server.context.ReactorContextWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ org.springframework.security.web.server.header.HttpHeaderWriterWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
*__checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ HTTP GET "/login/oauth2/code/oauth?code=nTCRNi&state=Ub8jQjbp1baxhgsxcpNULMMHoV8z42bQsp62iL2jNV8%3D" [ExceptionHandlingWebHandler]
Original Stack Trace:
at org.springframework.security.web.server.authentication.AuthenticationWebFilter.lambda$authenticate$6(AuthenticationWebFilter.java:123) ~[spring-security-web-5.6.0.jar:5.6.0]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.Mono.subscribe(Mono.java:4400) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:82) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.FluxHide$SuppressFuseableSubscriber.onComplete(FluxHide.java:147) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:102) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:367) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerComplete(FluxConcatMap.java:296) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onComplete(FluxConcatMap.java:885) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondComplete(MonoFlatMap.java:196) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onComplete(MonoFlatMap.java:268) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:142) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2058) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2058) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:150) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondComplete(MonoFlatMap.java:196) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onComplete(MonoFlatMap.java:268) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2058) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:102) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:142) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:142) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:142) ~[reactor-core-3.4.12.jar:3.4.12]
at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:400) ~[reactor-netty-core-1.0.13.jar:1.0.13]
at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:419) ~[reactor-netty-core-1.0.13.jar:1.0.13]
at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:473) ~[reactor-netty-core-1.0.13.jar:1.0.13]
at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:702) ~[reactor-netty-http-1.0.13.jar:1.0.13]
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:93) ~[reactor-netty-core-1.0.13.jar:1.0.13]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103) ~[netty-codec-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324) ~[netty-codec-4.1.70.Final.jar:4.1.70.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296) ~[netty-codec-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) ~[netty-transport-4.1.70.Final.jar:4.1.70.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) ~[netty-common-4.1.70.Final.jar:4.1.70.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.70.Final.jar:4.1.70.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.70.Final.jar:4.1.70.Final]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
The application.yml now looks like this:
spring:
application:
name: spring-boot-gateway
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost/auth/oauth/token
client:
registration:
oauth:
client-name: oauth
client-id: first-client
client-secret: xxxx
provider: adp-auth-provider
authorization-grant-type: authorization_code
redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
scope: read
provider:
adp-auth-provider:
authorization-uri: http://localhost/auth/oauth/authorize
token-uri: http://localhost/auth/oauth/token
user-info-uri: http://localhost/auth/me
user-name-attribute: sub
You have specified a redirect-uri for your client of /login. The page that says "Login with OAuth 2.0" is an auto-generated login page that Spring Security makes available by default under the /login endpoint. I don't think you intended to redirect there, but you currently have configured your client to do so.
The docs for OAuth 2.0 Login with WebFlux (Reactive) have recently been rewritten to align with the Servlet version, and are worth reading in their entirety.
Read the section of the docs on the Redirection Endpoint. Until you have a basic flow working, I'd recommend setting your redirect-uri to the default value of "{baseUrl}/login/oauth2/code/{registrationId}". Once things work, you can begin exploring how to customize this value. As the docs state, keep in mind that changing your redirect-uri property for a client also requires customizing the Redirection Endpoint in Spring Security to match.
If you also wish to customize the default Login Page, see the previous section of the docs, OAuth 2.0 Login Page.
The problem was occurring because the default authentication manager wasn't working for me, I had to implement one specifically for my problem.
#Configuration(proxyBeanMethods = false)
#EnableWebFluxSecurity
#EnableReactiveMethodSecurity
public class WebFluxSecurityConfig {
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, AuthenticationManager authenticationManager) {
return http
.httpBasic().disable()
.csrf().disable()
.authorizeExchange(exchanges -> exchanges
.pathMatchers(HttpMethod.GET, "/oauth2/authorization/**",
"/actuator",
"/actuator/**",
"/auth/login",
"/login/**")
.permitAll()
.anyExchange()
.authenticated()
.oauth2Login()
.authenticationManager(authenticationManager)
.and()
.build();
}
}
I also had to modify the redirect-uri and leave it as '/login/oauth2/code/{registrationId}'.
spring:
application:
name: spring-boot-gateway
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://127.0.0.1/auth/oauth/token
client:
registration:
oauth:
client-name: oauth
client-id: first-client
client-secret: xxxxx
provider: adp-auth-provider
authorization-grant-type: authorization_code
redirect-uri: '/login/oauth2/code/{registrationId}'
scope: read
provider:
adp-auth-provider:
authorization-uri: /auth/oauth/authorize
token-uri: /auth/oauth/token
user-info-uri: /auth/me

spring #Transactional with coroutines in webflux is throwing an error

When adding #Transactional annotation to a service suspend function which is being called by the handler I get the following error. If I leave it without the annotation then the code works as expected but in case of error it cannot roll back.
either is coming from arrow-kt-core
asHandlerFunction is used as a brigde to be able to document the APIs.
Any idea what happens?
Entities and repositories are placed under io.x.a. The service is inside io.x. The repository scans only io.x.a
Error:
java.lang.IllegalArgumentException: object is not an instance of declaring class
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ HTTP POST "/api/assets/130473/one-second-resolution" [ExceptionHandlingWebHandler]
Stack trace:
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at kotlin.reflect.jvm.internal.calls.InlineClassAwareCaller.call(InlineClassAwareCaller.kt:134)
at kotlin.reflect.jvm.internal.KCallableImpl.call(KCallableImpl.kt:108)
at kotlin.reflect.full.KCallables.callSuspend(KCallables.kt:55)
at org.springframework.core.CoroutinesUtils$invokeSuspendingFunction$mono$1.invokeSuspend(CoroutinesUtils.kt:64)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:377)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
at kotlinx.coroutines.reactor.MonoKt.monoInternal$lambda-2(Mono.kt:90)
at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:57)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
at reactor.core.publisher.MonoUsingWhen.subscribe(MonoUsingWhen.java:87)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:157)
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:73)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:127)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1815)
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:249)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1815)
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:249)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1815)
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:249)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.complete(MonoIgnoreThen.java:284)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onNext(MonoIgnoreThen.java:187)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:232)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:203)
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onComplete(MonoPeekTerminal.java:299)
at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onComplete(MonoIgnoreElements.java:88)
at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onComplete(MonoIgnoreElements.java:88)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2057)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816)
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:249)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.complete(MonoIgnoreThen.java:284)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onNext(MonoIgnoreThen.java:187)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:232)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:203)
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onComplete(MonoPeekTerminal.java:299)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:209)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:259)
at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onComplete(MonoIgnoreElements.java:88)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816)
at reactor.core.publisher.MonoCompletionStage.lambda$subscribe$0(MonoCompletionStage.java:82)
at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:859)
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:837)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2073)
at com.github.jasync.sql.db.util.FutureUtilsKt.success(FutureUtils.kt:16)
at com.github.jasync.sql.db.mysql.MySQLConnection$succeedQueryPromise$1.accept(MySQLConnection.kt:344)
at com.github.jasync.sql.db.mysql.MySQLConnection$succeedQueryPromise$1.accept(MySQLConnection.kt:54)
at java.base/java.util.Optional.ifPresent(Optional.java:183)
at com.github.jasync.sql.db.mysql.MySQLConnection.succeedQueryPromise(MySQLConnection.kt:343)
at com.github.jasync.sql.db.mysql.MySQLConnection.onOk(MySQLConnection.kt:218)
at com.github.jasync.sql.db.mysql.codec.MySQLConnectionHandler.channelRead0(MySQLConnectionHandler.kt:119)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at java.base/java.lang.Thread.run(Thread.java:829)
Router:
#Bean
fun router(...): RouterFunction<ServerResponse> {
return route()
.POST(
"...",
asHandlerFunction { createNewOneSecondResolutionSession(it) })
.build()
}
private fun asHandlerFunction(init: suspend (ServerRequest) -> ServerResponse) = HandlerFunction {
mono(Dispatchers.Unconfined) {
init(it)
}
}
Handler:
private suspend fun theFun(req: ServerRequest): ServerResponse {
val a = ...
val b = ...
return service.theFun(a, b).fold(
{ error ->
internalServerErrorResponse("Client user already exists.")
},
{ ServerResponse.ok().bodyValueAndAwait(it) }
)
}
Service:
#Transactional("tm1")
suspend fun theFun(
a: A,
b: B
): Either<Error, Result> = either {
val user= userService.createNewUser(username = "test", password = "pw")
.mapLeft {
log
Error
}
.bind()
throw RuntimeException("xx")
}
Persistence Configuration:
#Configuration
#EnableR2dbcRepositories(
basePackages = ["io.x.a"],
entityOperationsRef = "operations1"
)
class PersistenceConfig1(
#Value("\${spring.datasource.d1.r2dbcUrl}") private val r2dbcUrl: String
) {
#Bean
#Qualifier("d1")
fun connectionFactory(): ConnectionFactory {
return ConnectionFactories.get(ConnectionFactoryOptions.parse(r2dbcUrl))
}
#Bean
fun r2dbcEntityOperations(#Qualifier("d1") connectionFactory: ConnectionFactory): R2dbcEntityOperations {
val databaseClient = DatabaseClient.create(connectionFactory)
return R2dbcEntityTemplate(databaseClient, DefaultReactiveDataAccessStrategy(MySqlDialect.INSTANCE));
}
#Bean("tm1")
fun transactionManager(#Qualifier("d1") connectionFactory: ConnectionFactory): ReactiveTransactionManager {
return R2dbcTransactionManager(connectionFactory)
}
}
I found a solution using TransactionalOperator.
#Bean("transactionalOperator1")
fun transactionalOperator1(#Qualifier("tm1") transactionManager: ReactiveTransactionManager): TransactionalOperator {
return TransactionalOperator.create(transactionManager)
}
#Bean("transactionalOperator2")
fun transactionalOperator2(#Qualifier("tm2") transactionManager: ReactiveTransactionManager): TransactionalOperator {
return TransactionalOperator.create(transactionManager)
}
#Qualifier("transactionalOperator1") private val transactionalOperator1: TransactionalOperator,
#Qualifier("transactionalOperator2") private val transactionalOperator2: TransactionalOperator,
suspend fun theFun(...): Either<Error, Result> =
transactionalOperator1.executeAndAwait { t1->
transactionalOperator2.executeAndAwait { t2->
...
.handleErrorWith {
t1.setRollbackOnly()
t2.setRollbackOnly()
}
}
}!!
At the end of executeAndAwait it commits the code. If the rollbackOnly flag is set then it will instruct the ReactiveTransactionManager to roll back the changes.

Springboot 2.3.1.RELEASE and Cassandra connectivity issue

I am getting authentication exception while connecting to CASSANDRA using latest springboot version.
It was working with order version . In newer version of data-cassandra a lot of changes has been introduced . Please find the below configurations I am using .
Springboot version : 2.3.1.RELEASE
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
</dependency>
Cassandra Config:
#Configuration
#EnableCassandraRepositories
public class CassandraConfig extends AbstractCassandraConfiguration {
#Value("${spring.data.cassandra.contact-points}")
private String contactPoints;
#Value("${spring.data.cassandra.port}")
private int port;
#Value("${spring.data.cassandra.keyspace-name}")
private String keySpace;
#Value("${spring.data.cassandra.username}")
private String username;
#Value("${spring.data.cassandra.password}")
private String password;
#Override
protected String getContactPoints() {
return contactPoints;
}
#Override
protected int getPort() {
return port;
}
#Override
protected CqlSession getRequiredSession() {
// TODO Auto-generated method stub
List<InetSocketAddress> hostList = new ArrayList<>();
Stream.of(contactPoints.split(",")).collect(Collectors.toList()).forEach(host->
hostList.add(new InetSocketAddress(host, port))
);
return CqlSession.builder()
.addContactPoints(hostList)
.withAuthCredentials(username, password)
.withKeyspace(keySpace)
.withLocalDatacenter("local")
.build();
}
#Override
protected String getKeyspaceName() {
return keySpace;
}
}
Getting the below error at startup
requires authenti cation (org.apache.cassandra.auth.PasswordAuthenticator), but no authenticator configured at com.datastax.oss.driver.internal.core.channel.ProtocolInitHandler$InitRequest.lambda$buildAuthenticator$5(ProtocolInitHandler.java:354) at java.util.Optional.orElseThrow(Optional.java:290) at com.datastax.oss.driver.internal.core.channel.ProtocolInitHandler$InitRequest.buildAuthenticator(ProtocolInitHandler.java:350) at com.datastax.oss.driver.internal.core.channel.ProtocolInitHandler$InitRequest.onResponse(ProtocolInitHandler.java:204) at com.datastax.oss.driver.internal.core.channel.ChannelHandlerRequest.onResponse(ChannelHandlerRequest.java:94) at com.datastax.oss.driver.internal.core.channel.InFlightHandler.channelRead(InFlightHandler.java:255) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:748)
It was working perfectly with Springboot version 2.2.4.RELEASE version
You are probably hitting this issue, although the issue is marked solved in 2.3.1. Try maybe with 2.4.0, or try the following workaround:
#Bean
CqlSessionBuilderCustomizer authCustomizer(CassandraProperties properties) {
return (builder) -> builder.withAuthCredentials(
properties.getUsername(), properties.getPassword());
}
Finally I remove all the custom configuration class and kept only the below configuration in application.yml and it worked .
spring:
profiles: dev
data:
cassandra:
keyspace-name:
contact-points:
port:
username:
password:
localDatacenter:
My repo looks like below :
#Repository
public interface MyRepo extends CassandraRepository<MyEntity,String>

Resources