Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using HTTPS with REST in Java

Tags:

java

rest

ssl

x509

I have a REST server made in Grizzly that uses HTTPS and works wonderfully with Firefox. Here's the code:

//Build a new Servlet Adapter. ServletAdapter adapter=new ServletAdapter(); adapter.addInitParameter("com.sun.jersey.config.property.packages", "My.services"); adapter.addInitParameter(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS, SecurityFilter.class.getName()); adapter.setContextPath("/"); adapter.setServletInstance(new ServletContainer());  //Configure SSL (See instructions at the top of this file on how these files are generated.) SSLConfig ssl=new SSLConfig(); String keystoreFile=Main.class.getResource("resources/keystore_server.jks").toURI().getPath(); System.out.printf("Using keystore at: %s.",keystoreFile); ssl.setKeyStoreFile(keystoreFile); ssl.setKeyStorePass("asdfgh");  //Build the web server. GrizzlyWebServer webServer=new GrizzlyWebServer(getPort(9999),".",true);  //Add the servlet. webServer.addGrizzlyAdapter(adapter, new String[]{"/"});  //Set SSL webServer.setSSLConfig(ssl);  //Start it up. System.out.println(String.format("Jersey app started with WADL available at "   + "%sapplication.wadl\n",         "https://localhost:9999/")); webServer.start(); 

Now, I try to reach it in Java:

SSLContext ctx=null; try {     ctx = SSLContext.getInstance("SSL"); } catch (NoSuchAlgorithmException e1) {     e1.printStackTrace(); } ClientConfig config=new DefaultClientConfig(); config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(null,ctx)); WebResource service=Client.create(new DefaultClientConfig()).resource("https://localhost:9999/");  //Attempt to view the user's page. try{     service         .path("user/"+username)         .get(String.class); } 

And get:

com.sun.jersey.api.client.ClientHandlerException: 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.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:128)  at com.sun.jersey.api.client.Client.handle(Client.java:453)  at com.sun.jersey.api.client.WebResource.handle(WebResource.java:557)  at com.sun.jersey.api.client.WebResource.get(WebResource.java:179) 

From examples that I've found on the web, it seems like I would need to setup a Truststore then setup some sort of TrustManager. This seems like a lot of code and setup work for my simple little project. Is there an easier way to just say..I trust this cert and point to a .cert file?

like image 234
User1 Avatar asked Nov 18 '09 16:11

User1


People also ask

Can we use HTTPS in REST API?

You can enable HTTPS just for encryption, or you can also configure a REST API for client authentication (mutual authentication). Because REST APIs always use the integration server HTTP listener for the integration server, you must configure the integration server HTTP listener.


1 Answers

When you say "is there an easier way to... trust this cert", that's exactly what you're doing by adding the cert to your Java trust store. And this is very, very easy to do, and there's nothing you need to do within your client app to get that trust store recognized or utilized.

On your client machine, find where your cacerts file is (that's your default Java trust store, and is, by default, located at <java-home>/lib/security/certs/cacerts.

Then, type the following:

keytool -import -alias <Name for the cert> -file <the .cer file> -keystore <path to cacerts> 

That will import the cert into your trust store, and after this, your client app will be able to connect to your Grizzly HTTPS server without issue.

If you don't want to import the cert into your default trust store -- i.e., you just want it to be available to this one client app, but not to anything else you run on your JVM on that machine -- then you can create a new trust store just for your app. Instead of passing keytool the path to the existing, default cacerts file, pass keytool the path to your new trust store file:

keytool -import -alias <Name for the cert> -file <the .cer file> -keystore <path to new trust store> 

You'll be asked to set and verify a new password for the trust store file. Then, when you start your client app, start it with the following parameters:

java -Djavax.net.ssl.trustStore=<path to new trust store> -Djavax.net.ssl.trustStorePassword=<trust store password> 

Easy cheesy, really.

like image 72
delfuego Avatar answered Oct 10 '22 23:10

delfuego