mTLS termination in Java based Vertx Framework - java

I have a project based on Java based Vertx Framework, where I have few internal API calls.
So the flow is I have an API exposed at port XXXX (which has TLS configured - HTTPS), and inside this API call, I am calling another load balancer which is in HTTP. So, I need to terminate the mTLS before calling the Http load balancer.
Below is the sample snippet for VertX POST call:
private void handleDownstreamRequest(RoutingContext routingContext, String downstreamUrl) {
VertxUtil.assertOnVertxEventLoop();
client.postAbs(downstreamUrl) // POST request
.sendJson(
routingContext.getBody(),
ar -> {
asyncHttpResponseHandler(ar, routingContext);
});
}
I wanted to know how to terminate the TLS in Vertx Framework. Is there any inbuilt library exposed by Vertx to terminate mTLS or any sample code snippet will also help.

Configure the HTTP server for
You can configure the HTTP server to use a certificate authority in order to verify the identity of the clients:
HttpServerOptions options = new HttpServerOptions()
.setSsl(true)
.setClientAuth(ClientAuth.REQUIRED)
.setTrustStoreOptions(
new JksOptions()
.setPath("/path/to/your/truststore.jks")
.setPassword("password-of-your-truststore")
);
HttpServer server = vertx.createHttpServer(options);
The example above assumes you have a Java trust store but Vert.x support PFX/PEM formats too.

Related

Can not connect from flutter app to java backend running on Google Cloud Run

I have deployed a java backend in a docker container running on Google Cloud Run, now am having connection issues. I can reach my java backend using chrome and postman, but not flutter.
I am connecting to it using a flutter app. My java backend uses Jetty embedded for http. Previous to this, I did development on my local machine, and in the flutter app I would hard code in my servers LAN IP. The client connected reliably in this scenario
I have since deployed to Google Cloud Run and am not able to connect to the backend with my client.
I have tested the docker container locally, and I was able to connect to my backend when running the container using this command...
docker run -p 8080:8080 --network="host" image1
In the google cloud run console, I set the port to 8443.
In my flutter app. I have changed the URL from...
https://192.168.100.103:8080
To the url the Google Cloud Run specifies as my IP (I then added the port)...
https://blahblah-82j3flsijf-uc.a.run.app:8080
My flutter code that establishes the connection is as follows...
HttpClient client = HttpClient();
client.connectionTimeout = Duration(seconds:2); // throws SocketException after timeout
client.badCertificateCallback = ((X509Certificate cert, String host, int port) => true); // find the way to specifically accept a self signed certificate
HttpClientRequest request = await client.getUrl("https://blahblah-82j3flsijf-uc.a.run.app:8443");
request.headers.contentLength = requestBody.length;
request.write(requestBody);
My java backend code that establishes the jetty http server is as follows....
Server server = new Server(8080);
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[]{ new MessageHandler(), new DefaultHandler()});
server.setHandler(handlers);
server.start();
server.join();
When I try to connect from my flutter client, I get http 400 bad request.
I solved my issue. I had a few problems here.
First was that I was using https encryption in my java app when Google Cloud Run takes care of that for me. So I disabled https in my java app. I assume Google Cloud Run requires your container to handle only http requests (not positive though).
Secondly, I changed all my ports to run the Google Cloud Run default of 8080, and then completely removed the port from my flutter url.
Thirdly, I was calling HttpClient.getUrl which performs an http GET, but I was also adding a request body to the get. You should not add a body to a GET request. This previously worked for me because both my jetty based java backend, and the flutter dart:io HttpClient are completely fine with this violation, and both worked with a GET with a body. As soon as I introduced Google Cloud Run layer, it introduced more stringent enforcement of the http protocol, and correctly returned bad request when I sent a GET with a body.
If you are adding a body, use dart:io HttpClient.postUrl.

Using ServiceTalk from Apple (Netty) as a RESTful API with Jersey and Let's Encrypt HTTPS

So basically, I have made a RESTful API using ServiceTalk from Apple (Netty implementation) and Jersey and it works. Only through http though. I have seen that when I was making my React web page make a POST request through http, it would complain about CORS (which I'm still trying to fix) and that the browser (At least Brave) would not allow the request to be made because it was http and my web page was running on https using let's encrypt cert. How do I fix this issue? Do I need to add SSL with Netty? If so, how can I do that with a certificate that's going to be changing every once in a while?
I also have NGINX setup with Let's Encrypt and enabled auto-renew certificate setting from the setup wizard for NGINX + Let's Encrypt. If I can somehow make NGINX run the HTTPS request as a proxy to the netty server on http, then I think it would also be a better solution. I know this is a common practice with NodeJS Express + NGINX.
You are right, if you already have NGINX that serves your static content (html/css/js) it will be better to configure it as a proxy for a ServiceTalk backend service. That will let you keep SSL/TLS configuration in one place (NGINX config file only) and you will be able to use its auto-renew certificate feature. For an example of how you can configure NGINX as an SSL/TLS proxy for a backend service, see here: https://docs.nginx.com/nginx/admin-guide/security-controls/securing-http-traffic-upstream/
However, in this case, your connection between NGINX and ServiceTalk will not be encrypted. In some environments, it might be inappropriate according to security policies and requirements. If this is your case, you also need to configure SSL/TLS for ServiceTalk using HttpServerBuilder.secure() method that returns HttpServerSecurityConfigurator. Here is an example of a secure ServiceTalk server.
To avoid CORS, keep using NGINX as a proxy even when ServiceTalk also configured with SSL/TLS connections. If there is a requirement to avoid additional proxy on the way between a browser and backend service, target ServiceTalk directly. But NGINX gives additional features, like load balancing between multiple backend instances.
To get the best SSL performance in ServiceTalk/Netty we recommend to use OpenSSL provided instead of a built-in JDK provider. For more information, see Performance / netty-tcnative OpenSSL engine documentation section.
Note: ServiceTalk does not auto-renew SSL/TLS certificates. You will need to restart the server when certificate expires.

Using Azure EventHub behind a proxy with authentication

UPDATE
There are some News on that, see here: https://blogs.msdn.microsoft.com/eventhubs/2018/09/21/azure-event-hubs-websockets-and-proxy-support/
====
Azure's EventProcessorHost can be used to register and EventProcessor against an EventHub:
EventProcessorHost host = new EventProcessorHost(
EventProcessorHost.createHostName(null),
connectionStringBuilder.getEventHubName(),
"$Default",
ConnectionStringBuilder.toString(),
this.storageConnectionString,
this.storageContainerName
);
host.registerEventProcessor(MyEventProcessor.class, options).get();
One can add a proxy beforehand:
OperationContext.setDefaultProxy(
new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.url.com", 1234))
);
Question: How to provide an authentication (username/password) to this proxy?
TLDR: EventProcessorHost java library doesn't support proxy yet. This is a feature under construction.
Event Hubs Java Client sdk currently uses AMQPs protocol over TCP (on socket 5671, standard port assigned by IANA) to communicate to Event Hubs Service. We just built, support for Websockets transport; here' the PR. Building a snapshot version on dev branch and adding parameter TransportType=AmqpWebSockets in the ConnectionString should enable the client to talk to the EventHubs service over port 443.
We are building support for proxy using basic auth - by end of September. follow this for updates.

Jersey Client gives read timeout but Apache HTTP Client connects normally

I was using Jersey 2.25 client with Jackson, I configured everything correctly in Jersey, it worked normally on my development machine when I ran it in a test class, but Jersey client could never connect to a certain host that we have when deployed on our STG environment and always throws a read timeout exception.
I also know that the problem is not in our environment because I can connect using curl
But when switched to HTTPClient it worked normally.
This is how we created our Jersey Client:
Client client = ClientBuilder.newBuilder()
.register(JacksonFeature.class)
.property(ClientProperties.CONNECT_TIMEOUT,5000)
.property(ClientProperties.READ_TIMEOUT,15000)
.build();
The only difference here is the flow of the app, and also the major change that happens in the flow that could affect the connection is that somewhere before calling the Jersey client another class sets a proxy in the system config:
System.setProperty("http.proxyHost",strProxyHost);
System.setProperty("http.proxyPort",strProxyPort);
System.setProperty("https.proxyHost",strProxyHost);
System.setProperty("https.proxyPort",strProxyPort);
However we can establish a connection normally using HTTPClient:
HttpConnectionManagerParams params = new HttpConnectionManagerParams();
params.setConnectionTimeout(5000);
params.setSoTimeout(10000);
HttpConnectionManager manager = new SimpleHttpConnectionManager();
manager.setParams(params);
HttpClient httpClient = new HttpClient(manager);
We are using HTTPClient 3 because part of this app is legacy and we cannot update the version, but it works normally.
What could be causing this connection problem with Jersey? is there something global that Jersey reads when it's trying to connect?
Jersey by default uses HttpURLConnection and HttpURLConnection uses following global settings for proxy configuration -
System.setProperty("http.proxyHost",strProxyHost);
System.setProperty("http.proxyPort",strProxyPort);
System.setProperty("https.proxyHost",strProxyHost);
System.setProperty("https.proxyPort",strProxyPort);
It means if these system variables are set, Jersey will send all the requests through this configured proxy. Check Details here
However, Apache HttpClient does not follow these settings. For using proxy in Apache HttpClient, you have to use HostConfiguration class. Check details here
So, now to your problem, It looks that your STG environment is not able to connect to specified proxy but able to connect with the service directly.
So, while using Jersey, client is not able to connect to proxy and hence ReadTimeoutException is occurring. Since, you haven't configured HttpClient for using any proxy, it is able to connect with the service directly.

JAX-WS client authentication on proxy server

I'm trying to use JAX-WS api to send some soap messages on a client application. However, I'm behind a firewall and the only option is to use a proxy server to go outside.
I'm trying to find on google any answer about this and so far all fail: To Use System.setProperty for http.proxyHost, http.proxyPort, http.proxyUser, http.proxyPassword. To use Authenticator like is described here.
I'm running out of options, if someone could help me on this would be great.
Also, I have a option to use org.apache.commons.httpclient but then I need to generate manually the XML. So could you suggest any other approach or API for WS?
You can use ws import command when creating web client to configure proxy.
-httpproxy::
use above command to configure proxy.
How to do this depend on your IDE.
http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=/com.ibm.websphere.wsfep.multiplatform.doc/info/ae/ae/rwbs_wsimport.html
For Jax-ws webservice client, use the following
//set proxy info to the ClientProxyFeature
ClientProxyFeature cpf = new ClientProxyFeature();
cpf.setProxyHost("proxyhost");
cpf.setProxyPort(8888);
cpf.setProxyUserName("proxyuser");
cpf.setProxyPassword("proxypwd");
//get the port with the Feature
MyPort port = myService.getPort(cpf);

Categories