SSL Connection problem to web service from Java bean - java

I have written an application that connects to a SSL web service (including client certificate) through jaxws. For this to work I have a wstrust.jks that contains trusted root certificate for ws, and client.p12 that is the client certificate to use when connecting to ws. I have then created a custom SSLSocketFactory to be able to use my wstrust.jks and client.12 during the connection to ws. I tell jaxws to use my implementation by:
[javax.xml.ws.BindingProvider].getRequestContext().put(JAXWSProperties.SSL_SOCKET_FACTORY, customSSLSocketFactory);
Everything works like a charm if i run it as a standalone java-application. However when i use the same technique inside a Java bean (JSF) deployed as a war-file running under Tomcat,
i get a "PKIX path building failed"-error.
BUT If i configure SSL through JAVA_OPTS when i start my Tomcat (through the -Djavax.net.ssl.* parameters) I get it to work.
So my question:
How do i (or is it possible) to get my custom-SSLSocketFactory-technique to work inside the Java bean?
I guess as tomcat wraps itself around my application, when running as a bean, it is working differently and my wish to use a custom SSLSocketFactory isnt respected...
Thanks for any input on this!
/Tobbe

Solved it. If anyone have the same issue here is how. Instead of setting my custom factory through:
[javax.xml.ws.BindingProvider].getRequestContext().put(JAXWSProperties.SSL_SOCKET_FACTORY, customSSLSocketFactory);
I had to set it through:
HttpsURLConnection.setDefaultSSLSocketFactory(customSSLSocketFactory);
otherwise it seems to get ignored.
/Tobbe

Related

JBoss to Spring Boot and Spring Security upgrade: X509 Authentication problems

UPGRADING FROM: JBoss EAP 6.4 / Spring Security 4.2.1 (XML Configuration)
UPGRADING TO: Spring Boot 2.2.4 / Spring Security 5.2.1 (JavaConfig)
We have a REST endpoint protected by Spring Security that uses X509 authentication and a Test Client.
I breakpoint in Spring Security's Filter Chain at X509AuthenticationFilter.extractClientCertificate:
X509Certificate[] certs = (X509Certificate[]) request
.getAttribute("javax.servlet.request.X509Certificate");
I am no longer seeing the X509 Certificate coming across in the Request after going to Spring Boot and Spring Security 5.2 JavaConfig.
Didn't post source code because I don't expect anyone to fix my issue ... I'm just looking for some suggestions on where to dig or possible paths to explore. Some thoughts ...
Does Spring Security in Spring Boot use the embedded Tomcat Connectors? If I have a Tomcat Connector for HTTPS and the client hits us on HTTPS, do I need to somehow tell the Tomcat Connector for HTTPS to extract the X509 Cert from the Request?
How or what puts the X509 Certificate into the Request with an attribute of javax.servlet.request.X509Certificate? I was debugging against the old (working) JBoss EAP app and never could figure out how it got into the Request, only that it was there when I breakpoint in Spring Security's X509AuthenticationFilter.
If anyone ever comes across this ... I resolved it and will be happy to answer questions if it helps others.
It turns out not to be an issue with Spring Security, but rather with how we had the Tomcat Connectors configured.
We needed to:
Set up the truststore for the Spring Boot Tomcat Secure Connector correctly, using the method calls below that are compatible with org.apache.coyote.http11.Http11NioProtocol.
Also (and this is essential) - setClientAuth to "true".
It's ugly, I dug into the source code for Tomcat-embed-core, but there are a series of strings that are the equivalent of "force the client to send the certificate as part of the Request". Those strings are: "true", "yes", "require", "required". They all do the same thing, so we just used "true".
protocol.setTruststoreFile(truststorePath); // local directory path
protocol.setTruststoreType(truststoreType); // a string of either PKCS12 or JKS
protocol.setTruststorePass(truststorePass); // whatever password you set on your Keystore
protocol.setClientAuth("true"); // Makes the client provide cert in Request over HTTPS
Tomcat Connectors are not well-documented. There is a method call:
protocol.setSSLCACertificateFile(trustStorePath);
that does nothing under org.apache.coyote.http11.Http11NioProtocol.
Apparently it is meant to work with org.apache.coyote.http11.Http11AprProtocol (Apache Portable Runtime). That was a red herring for us, we made that method call, but it was not in fact setting up our truststore.

How to configure SSL with Archiva?

I'd like my Archiva instance to be safely secured by my SSL certificate. Available documentation seems not to mention this topic at all, which struck me very odd.
I know that Archiva is backed up by Jetty (which of course supports SSL), but when you start reading about setting up SSL with Jetty you immediately run into questions like: where do I find jetty-ssl.xml (which seems to be absent in Archiva's default installation)? Where/how do I start?
I also know that I could add an Apache proxy in front of Archiva, but I don't necessarily want to do this. I don't want one server be dependent on another.
Getting jetty-ssl.xml. Apache archiva (v2.2.4) uses jetty 8.1.14. You can download the 8.1.x from jetty's previous versions and extract the jetty-ssl.xml file from the /etc folder into the archiva config folder (<archiva home>/conf).
Configuring jetty-ssl.xml. See the answers of this question to get more details on updating the file (i.e. port, keystore path, keystore passwork and if private key is encryted, keymanager password).
To obfuscate your password, you can use archiva internal libraries (example using archiva v2.2.3):
java -cp <archiva home>/lib/jetty-util-8.1.14.v20131031.jar org.eclipse.jetty.util.security.Password "{PASSWORD}"
Updating wrapper.conf. Modify Archiva's wrapper configuration (located at <archiva home>/conf/wrapper.conf) and add the followin entry in the Application parameters section
wrapper.app.parameter.3=%ARCHIVA_BASE%/conf/jetty-ssl.xml
restart archiva service to take new configuration
Troubleshooting. Look at the wrapper log (localted at <archiva home>/log) for errors. You can increase the log level to INFO for more details. If everything is correct you should see an entry like this (I'm using port 8444):
INFO:oejs.AbstractConnector:Started SslSelectChannelConnector#0.0.0.0:8444
You can add jetty-ssl.xml in the same place as jetty.xml.
IMHO the easiest solution is probably to have an httpd instance handling ssl and proxying to Archiva in http. As it it will be easy to upgrade etc...

Spring security: using relative path

I have an application with name test.war.
Because of Apache installed on my server I have to use another port number for Tomcat applications so after deployment this application available at domain.com:8080/test/.
I decided to create a subdomain in order to remove that ugly 8080 from url, so I setted up the server like described here. So now test.domain.com reffers to domain.com:8080/test/.
Everything seems fine except of one problem - because my application is not ROOT.war and I am using spring:url function every url in the application is translated to /test/bla-bla. So I removed that function. But still have a problem with spring security because it still translates an urls relative to app name i.e. /test/bla-bla.
How can I solve that problem?
Thank you
UPD: I don't want to deploy it as a ROOT application because I have two or three such applications and I wanted to create a subdomain for each one of them
Spring Security doesn't "translate" URLs. In fact this isn't specific to Spring Security. You'll run into similar issues with any application which does redirects. If you want to hide the context paths of applications which are behind a proxy, then you need to rewrite the URLs at the proxy.
I'd recommend you read the Tomcat Generic Proxy Howto and the section on URL rewriting in particular, as it specifically addresses this issue.

Call glassfish ejb from stand-alone application

So I have a simple ejb (#stateless) deployed on a glassfish 3.1 server.
I want to call it from a standalone application.
It's working great if I add the gf-client.jar into my run configuration.
But how can I do if I do not have that file (the server is in another machine) ?
I tried using
<dependency>
<groupId>org.glassfish.common</groupId>
<artifactId>glassfish-naming</artifactId>
<version>LATEST</version>
</dependency>
But I have
Exception in thread "main" javax.naming.NameNotFoundException: java:global
at com.sun.enterprise.naming.impl.TransientContext.resolveContext(TransientContext.java:252)
at com.sun.enterprise.naming.impl.TransientContext.lookup(TransientContext.java:171)
at com.sun.enterprise.naming.impl.SerialContextProviderImpl.lookup(SerialContextProviderImpl.java:58)
at com.sun.enterprise.naming.impl.LocalSerialContextProviderImpl.lookup(LocalSerialContextProviderImpl.java:95)
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:233)
at javax.naming.InitialContext.lookup(Unknown Source)
at be.java.tuto.Application.main(Application.java:17)
Thanks.
EDIT:
I just needed to invoke an EJB deployed on GF from my Tomcat server and resurrected my dependencies. And because I dont want to keep them back for myself :)...
My IDE is Eclipse so I created an User Library containing all the files shown above.
Hope this solves your problem!
I was facing the same problem. For just wanting to invoke a GF session-Bean method I had to add the complete gf-client.jar to my clients classpath.
My problem was that this library is referencing almost the whole GF-libray-folder and even after a clean-up there were >15 referenced jars left which I had to add to my clients classpath.
For me I did't want this overhead so I decided to call the remote method via JAX-WS webservice.
The advantage of using webservises is that it is very easy to add webservice capability to an already existing session-bean by annotating the bean-class with #WebService.
After publishing the bean to the appserver you're able to view your deployed endpoint and getting the WSDL. With this you can generate your webservice-stubs automatically by using the wsimport-tool shipped with your JDK and use this generated files in yor client to invoke the remote method.
See example here.
Once created those files are portable and can be used in any client.
So if your willing to change the way your client calls the remote method this would be a portable, lightweight (except of a bit more http overhead) and easy to implement alternative.
P.S.
You don't lose the ability of invoking your method via EJB-call.
Hope this helped, have Fun!

How to call a web security with message security and client certificate authentication?

I need to call a web service with a java client.
This service authenticates clients through certificates at the message level (Ws-Security, not SSL).
It should be possible since, I can generate web services with JAX-WS with mutual certificate security in this dialog.
But I don't manage to create a client. Does anyone has an idea ?
I did not tried it myself, but from http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc/ :
Configuring Message Security Using XWSS
The Application Server contains all of the JAR files necessary to use XWS-Security for securing JAX-WS applications, however, in order to view the sample applications, you must download and install the standalone Java WSDP bundle. You can download the Java WSDP from http://java.sun.com/webservices/downloads/webservicespack.html.
To add message security to an existing JAX-WS application using XWSS, follow these steps on the client side:
Create a client security configuration. The client security configuration file specifies the order and type of message security operations that will be used for the client application. For example, a simple security configuration to perform a digital signature operation looks like this:
<xwss:Sign id="s" includeTimestamp="true">
<xwss:X509Token encodingType="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
valueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-
x509-token-profile-1.0#X509SubjectKeyIdentifier"
certificateAlias="xws-security-client"
keyReferenceType="Identifier"/>
</xwss:Sign>
</xwss:SecurityConfiguration>
</xwss:Service>
<xwss:SecurityEnvironmentHandler>
simple.client.SecurityEnvironmentHandler
</xwss:SecurityEnvironmentHandler>
For more information on writing and understanding security configurations and setting up SecurityEnvironmentHandlers, please see the Java Web Services Developer Pack 1.6 Tutorial at http://java.sun.com/webservices/docs/1.6/tutorial/doc/index.html.
In your client code, create an XWSSecurityConfiguration object initialized with the security configuration generated. Here is an example of the code that you would use in your client file. For an example of a complete file that uses this code, look at the example client in the \jaxws2.0\simple-doclit\src\simple\client\ directory.
FileInputStream f = new FileInputStream("./etc/client_security_config.xml");
XWSSecurityConfiguration config = SecurityConfigurationFactory.newXWSSecurityConfiguration(f);
Set security configuration information on the RequestContext by using the XWSSecurityConfiguration.MESSAGE_SECURITY_CONFIGURATION property. For an example of a complete file that uses this code, look at the example client in the \jaxws2.0\simple-doclit\src\simple\client\ directory.
// put the security config info
((BindingProvider)stub).getRequestContext().put(
XWSSecurityConfiguration.MESSAGE_SECURITY_CONFIGURATION,
config);
Invoke the method on the stub as you would if you were writing the client without regard to adding XWS-Security. The example for the application from the \jaxws2.0\simple-doclit\src\simple\client\ directory is as shown below:
Holder<String> hold = new Holder("Hello !");
stub.ping(ticket, hold);

Categories