getting SSLHandshakeException exception while calling api through the route locator - sslhandshakeexception

I am using below code to route to the particular service and all services are running on https but while calling these api through the locator but getting SSLHandshakeException.
#Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder,
TokenRelayGatewayFilterFactory filterFactory) {
return builder.routes()
.route(p -> p.path("/abc/api/**")
.filters(f -> f.filter(filterFactory.apply()))`enter code here`
.uri("https://localhost:8081"))
.route(p -> p.path("/bcd/api/**")
.filters(f -> f.filter(filterFactory.apply()))
.uri("https://localhost:8082/"))
.build();
}
2021-08-12 10:54:45.611 ERROR 1060 --- [ctor-http-nio-4] a.w.r.e.AbstractErrorWebExceptionHandler : [100eea72-1] 500 Server Error for HTTP GET "/abc/api/preference/country-list"
javax.net.ssl.SSLHandshakeException: No name matching localhost found
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131) ~[na:na]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.authentication.logout.LogoutWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.savedrequest.ServerRequestCacheWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.ui.LogoutPageGeneratingWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.ui.LoginPageGeneratingWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.config.web.server.ServerHttpSecurity$OAuth2ResourceServerSpec$BearerTokenAuthenticationWebFilter [DefaultWebFilterChain]
|_ 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.web.cors.reactive.CorsWebFilter [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 "/abc/api/preference/country-list" [ExceptionHandlingWebHandler]

This error message means that during TLS handshake the server responded with a certificate which Subject / Subject Alternative Names didn't include localhost. First thing is to check what does the server certificate contain:
openssl s_client -connect localhost:<port_number>
Save everything starting with -----BEGIN CERTIFICATE----- and ending with -----END CERTIFICATE----- as cert.pem and inspect with:
openssl x509 -in cert.pem -text -noout
This should show you both Subject and Subject Alternative Names, if any.
You have at least a few options here:
Configure server with a certificate which has localhost in SAN.
Disable hostname verification, either by VM param (if your underlying library supports this) or through code.
Override default DNS resolution and redirect the traffic to whatever is in the server certificate Subject or SAN to localhost. This can be done through hosts file or custom DNS resolver. Custom resolver requires more work and will depend on the underlying library that you use.

Related

How to enable HTTPS using Goddady SSL in a Spring Boot application, deployed as WAR file in Tomcat

I have a Spring Boot application, deployed as WAR file in a Tomcat in Godaddy.Now, I do need to enable HTTPS on it.I had installed SSL on our domain and https is working on it.DNS and SSL certificates are managed by GoDaddy. I have already downloaded the certificate for tomcat which contains files as 'randomhex.crt','randomhex.pem','gd_bundle-g2-g1.crt','gdig2.crt.pem' and then I generated 'keystore.jks'&'keystore.p12' using these file following the below commands.
Step 1:
"keytool -import -trustcacerts -alias intermediate -file gd_bundle-g2-g1.crt -keystore keystore.jks" using password as 'password1'
Step 2:
"keytool -import -trustcacerts -alias 'alias1' -file e1......7.crt -keystore keystore.jks" using password as 'password1'
Step 3:
"keytool -importkeystore -srckeystore keystore.jks -destkeystore keystore.p12 -srcstoretype JKS -deststoretype PKCS12 -deststorepass 'password2' -srcalias 'alias1' -destalias 'alias2'" using password as 'password1'
I know now I need to add this 'keystore.p12' file to my springboot project 'resource' folder and set below ssl properties,but I am not sure about what value to set based on the above mentioned commands.Please help me to set the values for below,
server:
ssl:
key-store: classpath:keystore.p12
key-store-password: ?
key-store-type: ?
key-alias: ?
key-password: ?
enabled: true
port: ?
Also do I need to make anything on my TOMCAT server to make https work for this spring boot project???
Try this for Spring Boot:
server:
ssl:
key-store: classpath:keystore.p12
key-store-password: password2
key-store-type: PKCS12
key-alias: alias2
enabled: true
port: 443
It does not look like a key-password is set. Try leaving it out & try 'changeit' (the default for jks).
For TOMCAT it needs to be set in $TOMCAT_HOME/conf/server.xml - one of the connectors:
<Connector
protocol="org.apache.coyote.http11.Http11NioProtocol"
port="443" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true"
keystoreFile="path/to/keystore.p12" keystorePass="password2" keyAlias="alias2"
clientAuth="false" sslProtocol="TLS"/>
Finally I found the solution.No need to configure SSL on spring boot.Just configure https on tomcat then https will work on your project.To configure https on tomcat you need to generate a keystore file(normally in .jks or .p12 format) by using sslcert.crt(randomhex.crt),sslkey.key,sslCA.crt(gd_bundle-g2-g1.crt) files as shown below:
goto '/opt/apache-tomcat/conf/' on your server and put above/below mentioned files there
openssl pkcs12 -export -in mycert.crt -inkey mykey.key -out mycert.p12 -name tomcat -CAfile myCA.crt -caname root -chain
Here
'mycert.crt' -> your randomhex.crt file,
'mykey.key' -> SSL key file from godaddy,
'myCA.crt' -> gd_bundle-g2-g1.crt ,
'mycert.p12' -> Name of the keystore file you want to generate.
You should asked a password when running above command and remember that password to configure tomcat server.xml file.
Now open server.xml o tomcat conf folder in edit mode and add below connector there,after that exit and save changes and restart tomcat then https will start working on your project.
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" compression="on" scheme="https" secure="true" keystoreFile="conf/mycert.p12"
keystorePass="password" SSLVerifyClient="none" SSLProtocol="TLSv1.2" />
Don't forget to add port 8443 on your spring boot 'application.yml'
server:
port: 8443

Spring application and external tomcat server HTTP2

When I deploy a spring boot application on an external tomcat server, do I need to configure HTTP2 on the tomcat server as well my spring boot application? I am a bit confused here about how the communication occurs when I call my spring application deployed inside of Tomcat via the browser or any other client say, Postman.
I have enabled HTTP2 on Tomcat and verified the same:
0:0:0:0:0:0:0:1 - - [08/Jan/2023:18:28:44 +0530] "GET / HTTP/2.0" 200 11408
0:0:0:0:0:0:0:1 - - [08/Jan/2023:18:28:44 +0530] "GET /tomcat.svg HTTP/2.0" 200 68761
0:0:0:0:0:0:0:1 - - [08/Jan/2023:18:28:44 +0530] "GET /tomcat.css HTTP/2.0" 200 5895
and I have configured my spring boot application to use HTTP2 as well using the steps mentioned in this link.
When I am calling my RestController deployed in the external tomcat, I am still getting HTTP 1.1
127.0.0.1 - - [08/Jan/2023:23:41:26 +0530] "HEAD /demo-0.0.1-SNAPSHOT/ HTTP/1.1" 200 -
127.0.0.1 - - [08/Jan/2023:23:41:51 +0530] "HEAD /demo-0.0.1-SNAPSHOT/getMessage HTTP/1.1" 200 -
where demo-0.0.1-SNAPSHOT is the deployed artifact.
I verified the same using curl
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 41
Date: Sun, 08 Jan 2023 18:11:51 GMT
What am I missing here?
My application.properties file looks like:
# configuring SSL
server.port=8443
server.ssl.key-store-type=pkcs12
server.ssl.key-store=classpath:springboot.p12
server.ssl.key-store-password=password
server.ssl.key-alias=springboot
# enabling http2
server.http2.enabled=true
and I have created the Keystore correctly using the following command:
keytool -genkeypair -alias springboot -keyalg RSA -keysize 4096 -storetype PKCS12 -keystore springboot.p12 -validity 3650 -storepass password
EDIT 1:
Spring Boot version - 2.7.2
Tomcat server - 9.0.70
In my server.xml, I have commented and edited the following Connector:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="200" SSLEnabled="true">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig>
<Certificate certificateKeystoreFile="ssl/tomcat.jks"
certificateKeyAlias="tomcat"
certificateKeystorePassword="password"
type="RSA" />
</SSLHostConfig>
</Connector>
which has helped me enable TLS as well as HTTP2 both on Tomcat. The problem is when I am deploying a spring boot application and making rest calls to that application's RestController, I am getting HTTP1.1 response. Making calls to Tomcat webservices is giving correct HTTP2 response.
Tomcat as standalone sever has by default in it's sever.xml disabled the connector for http 2.
Spring Boot 2, up to Tomcat 9
If this is a spring boot 2 deployed as war application then this could be using up to Tomcat 9.
You must find your Tomcat 9 (Server.xml) connector for http2 under the deployed server conf directory and uncomment this connector, while also providing the necessary certificate files.
You need to uncomment the
<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="150" SSLEnabled="true" >
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig>
<Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
certificateFile="conf/localhost-rsa-cert.pem"
certificateChainFile="conf/localhost-rsa-chain.pem"
type="RSA" />
</SSLHostConfig>
</Connector>
Spring Boot 3, Tomcat 10 or later
In case you have a spring boot 3 deployed as war application then this should be using Tomcat 10 or later.
You must find your Tomcat 10 (Server.xml) connector for http2 under the deployed server conf directory and uncomment while also providing the necessary certificate file.
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig>
<Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
type="RSA" />
</SSLHostConfig>
</Connector>
I found the solution. While deploying a spring boot application on external tomcat there is no need to specify Server SSL and HTTP2 parameters in the spring properties file as Tomcat will handle all the HTTPS requests. I was trying to mix 2 things.
Configuring the Spring Boot application to support HTTP2 will work if we are deploying using an embedded Tomcat server and I was able to verify that with Chrome browser.
As of writing this post, Postman still doesn't support HTTP2 requests, hence, I was seeing HTTP 1.1 protocol in the Tomcat access log. The same thing I believe is the issue with curl request. As my certificate is self-signed, I am using options -k and -sI. Maybe that's the reason, I am getting the response :
HTTP/1.1 200
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 10 Jan 2023 18:09:29 GMT
when running curl -k -sI https://localhost:8443. I will figure out why I am getting HTTP 1.1 and update it here.
Sharing this answer to help anyone coming across this question next time.

Spring API Gateway java.net.ConnectException: Connection timed out: no further information

I have a spring boot app with simple GET method "sayHello" i have configured API gateway to route calls to my microservice module when uri pattern matches /ms1/**
Both gateway and microservice registered to the Registry service and dashboard displays both registered
API-GATEAY YAML configuration
server:
port: '8010'
spring:
application:
name: MY-GATEWAY
cloud:
compatibility-verifier:
enabled: false
gateway:
routes:
- id: MICRO-SERVICE1
uri: lb://MICRO-SERVICE1
predicates:
- Path=/ms1/**
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-uri: http://localhost:8761/eureka/
intance:
hostname: localhost
MICRO-SERVICE1 YAML configuration
server:
port: '8030'
spring:
application:
name: MICRO-SERVICE1
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-uri: http://localhost:8761/eureka/
intance:
hostname: localhost
Controller's GET method
#RestController
#RequestMapping("/ms1")
public class UATController {
#GetMapping(value = "/sayHello")
public #ResponseBody ResponseEntity<String> sayHello() {
String message = "Hello World";
return new ResponseEntity<String>(message, HttpStatus.OK);
}
}
I am getting following error when i access via gateway, however when i access my microservice directly it works any idea where i am wrong here?
http://localhost:8010/ms1/sayHello <- Not working via gateway
http://localhost:8030/ms1/sayHello <- Working direct access
Wed Dec 07 23:32:31 EST 2021
[83b324d4-2] There was an unexpected error (type=Internal Server Error, status=500).
Connection timed out: no further information: DESKTOP-1.verizon.net/192.168.1.160:8030
io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection timed out: no further information: DESKTOP-1.verizon.net/192.168.1.160:8030
Suppressed: The stacktrace has been enhanced by Reactor, refer to additional information below:
Error has been observed at the following site(s):
*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ HTTP GET "/ms1/sayHello" [ExceptionHandlingWebHandler]
Original Stack Trace:
Caused by: java.net.ConnectException: Connection timed out: no further information
at java.base/sun.nio.ch.Net.pollConnect(Native Method)
at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672)
at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:946)
at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:330)
at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:334)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:707)
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:986)
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)
I have faced the same issue today as well when running the micro services, the gateway and the Eureka discovery all on localhost.
I was able to solve it by adding eureka.instance.preferIpAddress=true to my application.properties of the micro services. That property causes that the services will advertise their IP addresses instead of the host names. More info here under point 2.6: https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-eureka-server.html. My guess is that there was an issue with forwarding the requests to the microservices due to using localhost.
Edit: Here are my settings
There is nothing special in my setup. These are the values I am using in my application.properties
The microservice is using:
spring.cloud.discovery.enabled=true
spring.application.name=[The name of my app]
eureka.client.register.with-eureka=true
eureka.client.service-url.defaultZone=http://localhost:8999/eureka
eureka.instance.prefer-ip-address=true
The properties for the gateway are similar to the service one.
The load balancing part looks like this:
spring.cloud.gateway.routes[0].id=[Same name as my app]
spring.cloud.gateway.routes[0].uri=lb://[name of my app]
spring.cloud.gateway.routes[0].predicates=Path=/test/**
Where test/** is the part of the Rest URL of my application
Adding DESKTOP-1.verizon.net to hosts file worked, following is entry I have added to C:\Windows\System32\drivers\etc\hosts file. Unfortunately eureka.instance.prefer-ip-address=true didn't work for me
127.0.0.1 DESKTOP-1.verizon.net
have added this settings in yml file in all services and its work for me.
eureka:
instance:
prefer-ip-address: true
I just faced the same issue, and in my case, I had a problem with port number. I was using the code below to set up the port for me:
server:
port: ${random.int(8010,8013)}
I noticed when the service starts, even though the log shows "Tomcat started on port(s): 8010", on Eureka's page shows "host.docker.internal:my-service:8011"
This error happens randomly, because sometimes when you re-start the microservice, it is able to register on Eureka correctly.
You can do a simple test using a non-random port number.
I haven't figured out how to solve it for random port number.
UPDATING:
I did this and worked fine for me:
server:
port: 0
spring:
application:
name: user-service
eureka:
instance:
hostname: localhost
prefer-ip-address: true
client:
serviceUrl:
defaultZone: http://localhost:9000/eureka/

How to resolve 502 and 503 errors with tomcat and springboot

We are constantly getting 502 and 503 errors during load test. 10% errors during the test and all of them are 502 and 503. We are using apache webserver and tomcat 9 as application server with springboot as framework. Any specific configuration to be added to avoid these errors? Please let me know. PFB the tomcat connector configurations:
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
maxHttpHeaderSize="65536"
maxPostSize="6291456"
maxConnections="1500"
maxThreads="1500"
redirectPort="8443"

NPE when activating netty access log and http2

I want to activate the access log of netty, but it fails with a NPE.
application.yml
logging.level.reactor.netty.http.server.AccessLog: INFO
build.gradle.kts
tasks.withType<BootRun> {
jvmArgs = listOf("-Dreactor.netty.http.server.accessLogEnabled=true")
}
Problem
Running the application...
./gradlew bootRun
...starts up the application but on the first request:
2021-04-23 11:54:55.632 ERROR 24889 --- [or-http-epoll-3] o.s.w.s.adapter.HttpWebHandlerAdapter : [cdc3650c-1] Error [java.lang.NullPointerException] for HTTP GET "/foo/bar?x=1", but ServerHttpResponse already committed (200 OK)
2021-04-23 11:54:55.638 ERROR 24889 --- [or-http-epoll-3] r.n.http.server.HttpServerOperations : [id:cdc3650c-1, L:/127.0.0.1:8080 - R:/127.0.0.1:60818] Error finishing response. Closing connection
java.lang.NullPointerException: null
at reactor.netty.http.server.logging.AccessLogHandlerH1.write(AccessLogHandlerH1.java:102) ~[reactor-netty-http-1.0.6.jar:1.0.6]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ Handler com.example.FooController#bar(long, CurrentUser, Continuation) [DispatcherHandler]
So it seems that accessLogArgProvider in AccessLogHandlerH1 is null, but I could not find what to do about it?
Notes
When removing the jvmArgs the application works fine. The same problem occurs when using intellij run configurations.
I am on Spring Boot 2.5.0-RC1 and jdk 11.
UPDATE
Found out that this issue only occurs with activated http2
server.http2.enabled: true
In reactor.netty.http.server.logging there is a AccessLogHandlerH1 for http/1.1 and a AccessLogHandlerH2 for http2.
It seems like the H1 handler is used independently of activating http2 which might be a bug?
Turns out it is a bug in reactor-netty: https://github.com/reactor/reactor-netty/issues/1610

Resources