Configure SSL on Camel rest-component using Spring-Boot with embedded Jetty - java

Been bashing my head in for a few days trying to get SSL working with an existing rest endpoint. Currently using self-signed certificates in a jks.
We have a rest route (not this route, but very similar):
#Override
public void configure() {
restConfiguration()
.component("jetty")
.scheme("https")
.bindingMode(RestBindingMode.off)
.dataFormatProperty("prettyPrint", "true")
.port(8443);
rest("/post")
.post()
.consumes("application/json")
.produces("application/json")
.to( // next endpoint // );
This works perfectly over HTTP. When we set the scheme as HTTPS, Jetty throws a SSL cypher mismatch error when a request is sent to it; I'd imagine this is because no SSL configuration is being picked up.
I've tried some of the examples on the internet (such as configuring Jetty from the application.properties), but that doesn't actually seem to do anything at all.
Any help appreciated, all of the routes in the project are written using the Camel Java DSL, not the XML equivalent.

This has since been fixed. We discovered that the correct method of doing this was by configuring the embedded Jetty itself, rather than modifying the camel route.
This was achievable by instantiating a JettyHttpComponent, and setting the SSLContextParameters on it.

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.

camel cxf uri option property.XXX to set http client timeout

It is possible to set client timeout via camel cxf uri options?
There is possibility to set cxf://someAddress?[options], where options can be properties.XXX.
It is possible to set somehow http client receive timeout?
I tried many of them (found in source code or via google), but no one works:
properties.com.sun.xml.ws.request.timeout
properties.com.sun.xml.internal.ws.request.timeout
properties.javax.xml.ws.client.receiveTimeout
properties.org.apache.cxf.jms.client.timeout
properties.org.apache.cxf.transport.http.async.SO_TIMEOUT
properties.conduit.client.ReceiveTimeout
properties.org.apache.cxf.transports.http.configuration.client.ReceiveTimeout
properties.http-conf:client.ReceiveTimeout
properties.HTTPClientPolicy.ReceiveTimeout
properties.org.apache.cxf.http.conduits.client.ReceiveTimeout
properties.org.apache.cxf.http.conduit.client.ReceiveTimeout
properties.org.apache.cxf.transports.http.configuration.HTTPClientPolicy.ReceiveTimeout
I know it is possible with sprinx xml, but I want it configurable via Talend context.
I also know that I can configure cxf client via CxfEndpointConfigurer bean, but camel 2.13 (upgrade is not possible) does not have configureClient method.
Thank you for answer.
As mentioned in this document you can configure HTTP Client to set timeout
<http-conf:conduit name="{http://apache.org/hello_world_soap_http}SoapPort.http-conduit">
<http-conf:client Connection="Keep-Alive"
MaxRetransmits="1"
AllowChunking="false"
ConnectionTimeout="60000"
ReceiveTimeout="60000"/>
</http-conf:conduit>
Maybe you need to use a RouteBuilder, use the java variable in your route.
Tyr do something like this:
from("cxf://someAddress?[options]?timeout=${yourTimeOutVariable}")

Cross Domain Issue : Camel Swagger with Jetty in a Karaf Environment

I'm working in a OSGi environment project. I have discovered that camel offer an integration for swagger. So i have used it. It's working well until launching a request with swagger UI.
I mean when i put in swagger ui the uri i have defined with camel-swagger-java, it works. Swagger discovers my api !
But when i want to launch a request with swagger ui, i have some issue with cross domain request.
I have found several solutions :
- first one with camel rest
restConfiguration().component("jetty").bindingMode(RestBindingMode.json)
.dataFormatProperty("prettyPrint", "true")
.contextPath("/").port(8080).apiContextPath("/api-doc/login").apiProperty("api.title", "Login API").apiProperty("api.version", "1.0.0-SNAPSHOT")
.apiProperty("cors", "true").apiProperty("apiContextIdListing", "true");
I have set to true cors property. But it didn't solved my issue. Then after some search, i found it might be jetty which forbidden cross domain request. But a this point, i have not found how to configure Jetty in a OSGi environment (Karaf / Fellix) to accept this kind of request.
Thanks for your help
I found a solution. With Camel i had to create OPTIONS Rest Interface per Service. It's very dirty(http://camel.465427.n5.nabble.com/Workaround-with-REST-DSL-to-avoid-HTTP-method-not-allowed-405-td5771508.html). So I used this solution : github.com/swagger-api/swagger-ui/issues/1888

How can I get the Discovery Client working when using spring-cloud together with netflix Eureka?

I'm trying to make a basic project using spring cloud with the netflix addons such as Hystrix, Eureka and Ribbon to learn how this works. The project I'm trying to make is a simple message server that will keep messages. And a message-client that will just ask the server for a message, and I want to use the auto discovery client for this, or the RestTemplate discovery. But I can't get either to work.
I have the following structure:
message-client (eureka client)
message-server (eureka client)
configuration-service (config server)
discovery-service (eureka server)
What I currently do is I start up the configuration-service, and expose the application.yml details to all of these "apps/clients" when they are connecting by the following structure:
config-service\src\main\resources\config\appname.yml
app\src\main\resources\bootstrap.yml (contains the appname and url to cloud config)
This is working just fine, and my apps start up on the port they receive from the config server, as well as they all connect to my eureka server, and all of them are visible there. As well as the Hystrix failover is also working, not that it is related to this but it tells me that it can't be completely wrong then.
But here comes my confusion...
When using the #Autowired annotation in my service class (#Service annotated) inside my client module, I get a discoveryClient object, but I am unable to find any other services using that one.
Message Client - boot class:
#EnableAutoConfiguration
#EnableHystrix
#EnableEurekaClient
#ComponentScan("cloud.rest.resources, spring.cloud.client")
public class ClientBoot {
public static void main(String[] args) {
SpringApplication.run(ClientBoot.class, args);
}
}
Message Client - REST Resource:
#RestController
public class MessageResource {
#Autowired
private MessageClient messageClient;
#RequestMapping(value = "/message/{client}", method = RequestMethod.GET)
public Message getMessage(#PathVariable String client) {
return messageClient.getMessage(client);
}
}
Message Client - MessageClient:
#Service
public class RestMessageClient implements MessageClient {
#Autowired
private DiscoveryClient discoveryClient;
#Autowired
private RestTemplate restTemplate;
#Override
public Message getMessage(String client) {
return restTemplate.getForObject(String.format("http://message-server/message/%s", client), Message.class);
}
}
My message server boot class that is holding the messages has the same annotations as my client one.
And as I said, my service class are unable to find anything..
Which leads me to all of my questions:
What is required to actually use ribbon load balancer?
Do I have to use ribbon to be able to use the "auto discovery", I thought not but now I'm just confused.
From what I've understood, when using EnableEurekaClient I should not need to use the EnableDiscoveryClient as well?
Can I change the yml files on my config-server for the clients in runtime and just have to reboot the client?
How much configuration is really meant to be shared by the config-server, because currently all of my clients just contain a super basic bootstrap.yml file.
Does anyone have a good link to where I can read more about all the properties that is being set in my yml files? Both a documentation of what the properties that exists actually do as well as some documentation on how I can use them in combination with spring cloud?
Do I need specific properties to enable my apps/clients to find other apps/clients?
Edited information
Thank you for your quick and excellent reply, I've gone through this over and over today and I finally got my application working..
The problem (I can't understand why and was hoping you could help me understand that) is that my discovery service contains yml files for each of my other clients where I specify things like port and eureka information.. What I specified here as well was:
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka
So, when I set this value it seems to override something that makes my service discovery not working.. Even tho I can see all my applications in the eureka server, they were unable to find each other when I had this value set.
I set this value by having a message-server.yml file in my configuration service that is sent out to my message-server application after bootstrap..
So then I have two new questions.
How do I override this eureka server property?
Why does my discovery client stop working when I set this value, what is it that it actually does?
What is required to actually use ribbon load balancer?
The ribbon-loadbalancer must be on the classpath (e.g. via "spring-cloud-starter-ribbon"). Then you can inject one as a LoadBalancerClient or you can inject a RestTemplate (it will be load-balancer aware if you have a LoadBalancerClient).
Do I have to use ribbon to be able to use the "auto discovery", I thought not but now I'm just confused.
What is "auto discovery"? You don't need to use Ribbon to use the DiscoveryClient (Ribbon is a load balancer, not a service registry).
From what I've understood, when using EnableEurekaClient I should not need to use the EnableDiscoveryClient as well?
Correct. #EnableEurekaClient is annotated with #EnableDiscoveryClient so it is only there to express a preference.
Can I change the yml files on my config-server for the clients in runtime and just have to reboot the client?
Yes. Or you can use the /refresh or /restart endpoints (a full reboot is probably best in production, at least periodically).
How much configuration is really meant to be shared by the config-server, because currently all of my clients just contain a super basic bootstrap.yml file.
As much as you want. How long is a piece of string? If I were you I would try and keep the central config to a minimum (only the things that change between environments, or at runtime).
Does anyone have a good link to where I can read more about all the properties that is being set in my yml files? Both a documentation of what the properties that exists actually do as well as some documentation on how I can use them in combination with spring cloud?
Spring Boot and Spring Cloud have autogenerated metadata for externalized properties. The new generation of IDEs understands them (so get STS 3.6.4 or IDEA 14.1), and they are listed in the user guide (for Spring Boot at least) under http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#common-application-properties
Do I need specific properties to enable my apps/clients to find other apps/clients?
You need to be able to locate your service registry (Eureka in this case). If you are using Eureka and your clients have registered then that is enough.

SSL Connection problem to web service from Java bean

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

Categories