Custom DNS Resolver in JaxRS? - java

I'm developing a Java application (launched by Tomee) which needs to call, using JaxRS, an HTTPS server with its hostname, but the hostname is not resolved by the DNS.
In practice, my application creates a VM using Openstack API, so the IP address has been dynamically allocated during the lifetime of the application (which is why it's not solved by the DNS).
But I have to call an HTTPS server running on that VM, for which the certificate was signed using a given hostname, so I MUST call it with https://hostname, and not with https://ip_address...
I am not allowed to "play" with TLS configuration, by (for example) disabling Common Name check, so the only solution I see is to be able to "intercept" a DNS resolution request, to provide the good IP address to use.
The How to override DNS in HTTP connections in Java page shows a solution using Apache HttpClient - however, our microservice was entirely built on JaxRS, and I failed to find a way to do the same thing with it.
The client used is the v3.2.2 version of org.apache.cxf:cxf-rt-rs-client, provided by the Tomee we are based on.
Thanks for your attention!

Related

Why do we use port number localhost: 8080? Why don't we use a port number when using www.example.com?

When I use a Spring Boot app in local it uses, localhost:8080. When it is pushed to Pivotal Cloud Foundry, it has some route https://my-app.xyz-domain.com and we can access the URL without a port, what is happening behind the scene?
Please help me understand.
There is a default port number for each protocol which is used by the browser if none is specified. For https it is 443, for http 80 and for telnet 23.
On Unix and similar systems like Linux, those are often not available to a developer so other ports are used but then they have to be specified. 8080 is often available and looks like 80.
On CloudFoundry, your application is actually still running on localhost:8080. The reason that you can access your application through https://my-app.xyz-domain.com is that the platform handles routing the traffic from that URL to your application.
The way this works is as follows:
You deploy your application. It's run by the foundation in a container. The container is assigned a port, which it provides to the application through the $PORT env variable (this can technically change, but it's been 8080 for a long time). Your application then listens on localhost:$PORT or effectively localhost:8080.
The platform also runs Envoy in your container. It's configured to listen for incoming HTTP and HTTPS requests, and it will proxy that traffic to your application on localhost:$PORT.
Using the cf cli, you map a route to your application. This is a logical rule that tells the platform what external traffic should go to your application. A route can consist of a hostname, domain, and/or path. For example, my-cool-app.example.com or my-cool-app.example.com/foo. For a route to work, the domain must have its DNS directed to the platform.
When an end-user accesses the route that you mapped, the DNS resolves to the platform and the traffic is directed to the external load balancers (sometimes TCP/layer4, sometimes HTTPS/layer7) that sit in front of the platform. These proxies do not have knowledge of CF, they just proxy incoming traffic.
Traffic from the external load balancers is spread across the set of the platform Gorouters. The Gorouter is a second layer of proxies, but these proxies have knowledge of the platform, specifically, all of the routes that have been mapped on the platform and where those applications actually live.
When a request comes to Gorouter, it will recognize the route like my-cool-app.example.com and look up the location of the container where that app is running. Traffic from Gorouter is then proxied to the Envoy which is running in the app container. This ties into step two as the Envoy will route that traffic to your application.
All in total, incoming requests are routed like this:
Client/Browser -> External LBs -> Gorouters -> Envoy -> Application
First, you should change the port to 80 or 443, because HTTP corresponds to 80, and HTTPS corresponds to 443. Then, you should set the domain name to resolve to the current host, so that you can access the current application through the domain name. In addition, if you want to set the local domain name, then The hosts file should be modified.

How to create a SSL certificate for a host without domain?

I am testing and debugging a system where application A submits a POST request to a URL when some event occurs. One of my programs, application B, must react to this event.
Application A requires that the URL uses HTTPS. I don't want to use a self-signed certificate because it may cause problems (curl complains about the self-signed certificate when I test it locally).
Letsencrypt can create a SSL certificate for free, but requires a domain. This is a problem for me because application B runs on a virtual machine. Whenever the machine is restarted, it gets a different IP address. Currently, there is no domain associated with that machine (i. e. you can only access it via a URL like http://aaa.bbb.ccc.ddd/).
Is there a way to use a non-self-signed certificate for an application without domain (i. e. one that runs on a URL like http://aaa.bbb.ccc.ddd/)? If not, what is the easiest way to make a Spring boot application (application B) support a non-self-signed SSL certificate?
There is one answer suggesting to create one's own certificate authority and installing it on all machines that access the URL. This is not an option for me because I have no control over application A.
Update 1: Application B runs on an EC2 instance in AWS.
Letsencrypt can create a SSL certificate for free, but requires a domain. This is a problem for me because application B runs on a virtual machine. Whenever the machine is restarted, it gets a different IP address.
It does not matter if the IP changes since all what is checked is the domain name. Thus, if the machine gets a new IP address you need to update the DNS to point to this new domain name.
In general the client will check if the subject/SAN of the certificate matches the domain in the URL. It is not possible to get a certificate which is generic enough to cover all the IP addresses you could get. Thus, having your own fixed domain name with a dynamic IP address behind it is the way to go if you want to use normal clients to access the site.

How to call a IPv6 REST service over AWS Lambda

I've got an Alexa Skill hosted in AWS Lambda which uses AsyncHttpClient to call an IPv6 REST service under the following EXAMPLE URL:
http://[2a12:5375:4151:2300:1353:a632:5f4e:c232]:4711/rest/test
Now my problem is, that I always get the following exception:
ava.util.concurrent.ExecutionException: java.net.ConnectException: Protocol family unavailable
If I check the IP address which is assigned to the underlying server or the application?, I get the following address (also example):
ip-10-23-56-1.eu-west-1.compute.internal: 10.23.56.1
So I think, because I am using an IPv6 while the system uses IPv4, I can't get it working?
I can call my REST service from another server successfully.
I am also using the following system properties:
System.setProperty("java.net.preferIPv6Addresses", "true");
System.setProperty("java.net.preferIPv4Stack", "false");
Is there any solution to provide a 'tunnel' over the IPv4 underlying system to tunnel the IPv6 address to call the REST service? Or is there any simpler solution?
The error Protocol family unavailable means that the protocol (in this case IPv6) is not available or not configured on the system on which your code is running.
In the case of AWS, the only thing you can do about this is to complain and hope they eventually roll out IPv6 support to services which don't yet have it.
After quite an extensive research and tests the word is: IPv6 is not available for Lambda. This goes a bit further if you run your Lambda functions inside a VPC.
If your function is associated with a subnet that includes IPv6 CIDR then no amount of correct config will get your Lambda to access external resources.
You will be able to do API calls to some of the AWS resources available as VPC endpoints. This includes services like S3 and Dynamo, they will get an internal IP within your VPC. Services like SQS are not supported under VPC endpoint so will get external resolution.
Any service or external API call that goes outside your VPC will fail with IPv6 CIDR. The only way to go around this is to remove IPv6 CIDR from the subnet or create a dedicated subnets just for your Lambda functions.
We have opted for the latter option and all is working great with appropriate VPC security and routing policies applied.

Best way to tunnel RMI over HTTP

I'm looking for a secure way to tunnel RMI traffic.
In My application(java Webstart) i must assume that the only port that is open is port 80.
I have the looked att socketfactories for rmi but do i really need a proxy then.
I need to do all my tunneling on the client side.
The only firewall i am trying to get past is on the client side.
I'm not able to open 1099 with port ranges above.
Would be nice to see some implementations.
Thanks!
Port 1099 was reserved for RMI at IANA in about 1995. There is no reason for it not to be open for outbound access in the client-side firewall.
RMI can be made to use fixed port numbers by supplying a port number when constructing (super(port)) or exporting (exportObject(object, port)). Better still, if you create the Registry within the server JVM via LocateRegistry.createRegistry(), all subequently exported remote objects will use that port unless they specify a different port or they use a server socket factory.
BUT ... RMI already includes HTTP tunneling 'out of the box'. No external solution required. You have to deploy the RMI-Servlet provided with the JDK, at the server end.
(a)
although not the newest fashion, exposing remote services with Hessian and Burlap seems to be a simple solution to avoid problem working across firewalls: http://hessian.caucho.com/doc/
see sample code for the server and client side:
http://www.javatpoint.com/spring-remoting-by-hessian-example
(b) or consider using Spring HttpInvokder (see some sample code here: http://www.javatpoint.com/spring-remoting-by-http-invoker-example)
HttpInvokder provides more customization options through the RemoteInvocationFactory, RemoteInvocationExecutor and HttpInvokerRequestExecutor strategies (for example, to add custom context information (such as user credentials) to the remote invocation, or using java’s built-in object serialization etc.), see:
http://docs.spring.io/spring-framework/docs/2.0.x/api/org/springframework/remoting/support/RemoteInvocationFactory.html

Logging hostname resolved in CXF

I have a java web service client that uses CXF. The server has 10+ possible ips that are resolved via dynamic dns. I have the jvm configured properly to not cache dns.
My question is, I have the requirement that I need to log on the client the payload with the ip it was delivered to. Logging just the hostname will not work as the hostname to ip resolution is constantly changing.
I would suggest grabbing the source of the CXF LoggingInInterceptor from:
http://svn.apache.org/repos/asf/cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/LoggingInInterceptor.java
and update it to suite your needs. Particularly, you would need to grab the HttpServletREquest off the message and figure out how to get the IP off of it to add to the logs. The CXF version is protocol agnostic (would work for JMS or others) and thus doesn't do any of the HTTP specific things that would require the HttpServletRequest.

Categories