In Play 2.4.3 web app I need to call other service via HTTPS using WSClient. I followed the article but the error appears:
play.api.libs.ws.ssl.CompositeCertificateException: No trust manager
was able to validate this certificate chain: # of exceptions = 1
The exception inside CompositeCertificateException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
Part of application.conf responsible for SSL:
play.ws.ssl {
trustManager = {
stores = [
{ type : "PEM", path : "C:/A/B/globalsign.crt" }
]
}
}
What's wrong here?
I solved the problem through the following steps:
Run InstallCert.java to generate jssecacerts file.
Add path to the file in application.conf.
Config example:
play.ws.ssl {
trustManager = {
stores = [
{path: "C:/A/B/jssecacerts"}
{path: ${java.home}/lib/security/cacerts}
]
}
}
Related
** ERROR SparkSubmit$$anon$2: Could not convert socket to TLS
javax.mail.MessagingException: Could not convert socket to TLS;
nested exception is:
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 com.sun.mail.smtp.SMTPTransport.startTLS(SMTPTransport.java:2046)
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:711)
at javax.mail.Service.connect(Service.java:366)
at javax.mail.Service.connect(Service.java:246)
at javax.mail.Service.connect(Service.java:195)
at javax.mail.Transport.send0(Transport.java:254)
passing this in config location :/javax.mail-1.5.5.jar ;: Is present in the lib location.
Code:
def sendEmail(fromAddr:String,toAddr:String,subjectLine: String,messageCont: String) ={
val emailProps = new Properties()
emailProps.put("mail.smtp.auth" , "false")
emailProps.put("mail.smtp.starttls.enable" , "true")
emailProps.put("mail.smtp.host" , "")
emailProps.put("mail.smtp.port" , "")
**
We have a rest API written in SpringBoot using a 2-way ssl Auth.
We would like to send 401 HTTP status code when the user selects the wrong/expired client certificate.
When it happens I can see the exception:
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
The API starts normally and works fine. The exception occurs whenever the user tries to call my api selecting a wrong client certificate or invalid. In this case I would like to return 401 to the caller
Spring boot is configured with Tomcat and #EnableWebSecurity
http.x509().subjectPrincipalRegex("XXXXXX").userDetailsService(this.userDetailsService);
((RequiresChannelUrl)http.requiresChannel().anyRequest()).requiresSecure();
urls().forEach((url, guard) -> {
try {
((AuthorizedUrl)http.authorizeRequests().antMatchers(new String[]{url})).access(guard);
} catch (Exception var4) {
throw new UnsupportedOperationException("error");
}
});
Here the stack trace:
DirectJDKLog.java:175 [] Handshake failed during wrap
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
...
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439)
....
....
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
The browser shows: ERR_BAD_SSL_CLIENT_AUTH_CERT
Is it possible to catch this exception in SpringBoot and send a specific HTTP status code?
Maybe you can try a controller advice:
#ControllerAdvice
class MyControllerExceptionHandler {
#ResponseStatus(HttpStatus.UNAUTHORIZED) // or whatever you want
#ExceptionHandler(SSLHandshakeException.class)
public void handleHandshakeException() {
// Nothing to do
}
}
Maybe the solution posted here or here can help you
In your security configuration you add this lines:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
//....
and().
.anonymous().disable()
.exceptionHandling()
.authenticationEntryPoint(new org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint("YourValue"));
}
and it will return HTTP 401:
Status Code: 401 Unauthorized
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Expires: 0
//... other header values
WWW-Authenticate: YourValue
This question already has answers here:
Resolving javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed Error?
(33 answers)
Closed 5 years ago.
I would like to allow a connection from a java client.
This Java client needs to support multiple public keys for different DB's.
I must do it with a PUBLIC KEY and MUST NOT trust server certificate.
I have searched online but could not find a full solution for this problem, these are some of the links I have read:
first
second
third
I have also read this link myt question is not duplicate since its a completly different connection type - this is a JDBC connection with conneciton manager and not a general URL connection with SSL.
and many more, all the stack overflow solution I found offered to trust server certificate which means skip the public key verification
This is my code:
String connectionString = "jdbc:mysql://abcd-efg.rds.amazonaws.com:3306/test?trustServerCertificate=false&useSSL=true&requireSSL=true&verifyServerCertificate=true"
File f = new File("C:\\temp\\amazonPublic.pem");
CertificateFactory fact = null;
fact = CertificateFactory.getInstance("X.509");
X509Certificate cer = (X509Certificate) fact.generateCertificate(new FileInputStream(f));
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
char[] password = new char[] {'1','2','3','4'};
ks.load(null, password);
ks.setCertificateEntry("alias", cer);
FileOutputStream fos = new FileOutputStream(new File("C:\\temp\\ca.cer"));
ks.store(fos, password);
fos.close();
Properties p = new Properties();
p.setProperty("javax.net.ssl.trustStore","C:\\temp\\ca.cer");
p.setProperty("javax.net.ssl.trustStorePassword","1234");
try (java.sql.Connection connection =
DriverManager.getConnection(connectionString,p)) {
connection.isValid(1000);
}
And this is the error:
Caused by: java.sql.SQLException: Could not connect to yyyyy-zz-prd-xxxxxxxxxxxx-1.rds.amazonaws.com:3306: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.handleConnectionPhases(AbstractConnectProtocol.java:706)
at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.connect(AbstractConnectProtocol.java:406)
at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.connectWithoutProxy(AbstractConnectProtocol.java:1022)
at org.mariadb.jdbc.internal.util.Utils.retrieveProxy(Utils.java:483)
at org.mariadb.jdbc.Driver.connect(Driver.java:106)
Caused by: 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.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496)
... 17 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
... 23 more
What am I missing in the solution?
For the sake of Humankind while working with MariaDB driver - debugging it
I find out that:
The property should be "serverSslCert" or "trustStore"
The prefix of javax.net.ssl only required when working with System.setProperty
So this simple change did the trick.
Properties p = new Properties();
p.setProperty("serverSslCert","C:/temp/amazonPublic.pem");
p.setProperty("trustStorePassword",jdbcDetails.getSensitiveData());
p.setProperty("user",jdbcDetails.username);
p.setProperty("password",jdbcDetails.getSensitiveData());
I am trying to connect to specific host with TLS support. I have a valid private key - "my.key" , my certificate - "my.crt", and also rootCA certificate "root_ca.crt". I already know that requested host using OpenSsl. Vertx may use some different variants how to do this:
By JksOptions() and java keystore file ".jks"
By PfxOptions() and file ".pfx" (in PKCS12 format)
By PemKeyCertOptions() and two files ("key.pem" and "cert.pem")
But when i doing like this:
NetClient client = vertx.createNetClient(
(NetClientOptions) new NetClientOptions()
.setLogActivity(true)
.setSsl(true)
.setOpenSslEngineOptions(new OpenSSLEngineOptions())
.addEnabledSecureTransportProtocol("TLSv1.2")
.setJksOptions(
new JksOptions()
.setPath("/path/to/my.jks")
.setPassword("password")
)
);
client.connect(some_port, "some_host", ar -> {
if (ar.succeeded()) {
LOG.debug("Connection succeeded!!!!");
} else {
LOG.debug("Connection failed!!!! :: {} :: {}", ar.cause(), ar.cause().getMessage());
}
});
build is success, but when i run this code i have exception:
INFO: Succeeded in deploying verticle
[vert.x-eventloop-thread-0] DEBUG io.netty.handler.ssl.ReferenceCountedOpenSslContext - verification of certificate failed
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.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:281)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136)
at io.netty.handler.ssl.ReferenceCountedOpenSslClientContext$ExtendedTrustManagerVerifyCallback.verify(ReferenceCountedOpenSslClientContext.java:223)
at io.netty.handler.ssl.ReferenceCountedOpenSslContext$AbstractCertificateVerifier.verify(ReferenceCountedOpenSslContext.java:606)
at org.apache.tomcat.jni.SSL.readFromSSL(Native Method)
at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.readPlaintextData(ReferenceCountedOpenSslEngine.java:470)
at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:927)
at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1033)
at io.netty.handler.ssl.SslHandler$SslEngineType$1.unwrap(SslHandler.java:200)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1117)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1039)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:642)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:565)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:479)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:441)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
at java.lang.Thread.run(Thread.java:748)
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
... 30 more
Maybe i am doing something wrong when creating the keystore?
To create it i am using this tutorial - https://support.adeptia.com/hc/en-us/articles/207878953-How-to-create-a-KeyStore-with-certificate-chain
Please help me understand how can i get correct keystore to connect with my host by TLS?
I find a way to create correct java keystore in PKCS12 format by this command:
openssl pkcs12 -inkey my.key -in my.crt -export -out domain.pfx
and then put generated "domain.pfx" file in PfxOptions and "root_ca.crt" file put in PemTrustOptions like this:
return new NetClientOptions()
.setSsl(true)
.addEnabledSecureTransportProtocol("TLSv1.2")
.setPfxKeyCertOptions(
new PfxOptions()
.setPath(pathToKeystoreFile)
.setPassword(keystorePassword)
)
.setPemTrustOptions(
new PemTrustOptions()
.addCertPath(rootCACertificate)
);
P.S. keystorePassword you entered while creating a certificates.
I'm using secure social in my Play project. I'm trying to use my own E-Mail for the registaiton process.
The how to is described here:
http://securesocial.ws/guide/views-customization.html
My Problem is, that I get an error when I try to genreate the absoute URL in the template:
#securesocial.controllers.routes.Registration.signUp(mailToken).absoluteURL(IdentityProvider.sslEnabled)
Here ist the Error Log:
[error] play - Cannot invoke the action, eventually got an error:
java.lang.Runt imeException: There is no HTTP Context available from
here. [error] application -
! #6j0al12dk - Internal server error, for (POST) [/signup] ->
play.api.Application$$anon$1: Execution exception[[RuntimeException:
There is no HTTP Context available from here.]]
at play.api.Application$class.handleError(Application.scala:293) ~[play_
2.10.jar:2.2.3]
at play.api.DefaultApplication.handleError(Application.scala:399) [play_
2.10.jar:2.2.3]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun
$applyOrElse$3.apply(PlayDefaultUpstreamHandler.scala:264)
[play_2.10.jar:2.2.3]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun
$applyOrElse$3.apply(PlayDefaultUpstreamHandler.scala:264)
[play_2.10.jar:2.2.3]
at scala.Option.map(Option.scala:145) [scala-library.jar:na]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3.applyOrE
lse(PlayDefaultUpstreamHandler.scala:264) [play_2.10.jar:2.2.3] Caused
by: java.lang.RuntimeException: There is no HTTP Context available
from h ere.
at play.mvc.Http$Context.current(Http.java:30) ~[play_2.10.jar:2.2.3]
at play.mvc.Http$Context$Implicit.ctx(Http.java:196) ~[play_2.10.jar:2.2 .3]
at play.core.j.PlayMagicForJava$.requestHeader(TemplateMagicForJava.scal
a:56) ~[play-java_2.10.jar:2.2.3]
at views.html.custom.mails.signUpEmail$.apply(signUpEmail.template.scala
:42) ~[classes/:na]
at plugins.NekViews.getSignUpEmail(NekViews.scala:100) ~[classes/:na]
at securesocial.core.providers.utils.Mailer$.sendSignUpEmail(Mailer.scal
a:49) ~[securesocial_2.10-2.1.3.jar:2.1.3] [info] application -
[securesocial] unloaded identity provider: userpass [info] application
- [securesocial] unloaded password hasher bcrypt [info] play - Shutdown application
default Akka system.
Does anybody know what the mistake is?
Your template requires implicit request which is mandatory for obtaining an absolute URL.
#(/*template's parameters*/)(implicit request: RequestHeader)
This request must be available in a method which renders the template.
I had a pretty similar error if not the same, probably you're also mixing some java code in your project.
You must create a java context in your controller ( in this case the custom views controller ) for it to be used by the views.
For example:
Scala helper to create a java context
object JavaContext {
import play.mvc.Http
import play.core.j.JavaHelpers
def withContext[Status](block: => Status)(implicit header: RequestHeader): Status = {
try {
Http.Context.current.set(JavaHelpers.createJavaContext(header))
block
}
finally {
Http.Context.current.remove()
}
}
}
Usage:
class CustomSecureSocialTemplates(env:RuntimeEnvironment[_]) extends ViewTemplates.Default(env:RuntimeEnvironment[_])
{
override def getLoginPage(form: Form[(String, String)],
msg: Option[String] = None)(implicit request: RequestHeader, lang: Lang): Html = {
JavaContext.withContext {
views.html.security.login(form,msg)
}
}
//...
}
Source: dominikdorn.com