4

This is the first time ever I got the requirement to connect to https url. Within no time, I came to know that I need SSLContext to be passed.

I also came to know that I need to configure in standalone.xml to get it done.

Any pointers towards the solution/link, working code would be much appreciated.

Do we have to generate keystores ourselves? or wildfly provides any existing ones?

This is what I've tried:

    SSLContext context = null;
    KeyManagerFactory kmf = null;
    KeyStore ks = null;
    char[] storepass = "somestringhere".toCharArray();
    char[] keypass = "somestringhere".toCharArray();

    try {
        context = SSLContext.getInstance("SSL");
    } catch (NoSuchAlgorithmException e3) {
        // TODO Auto-generated catch block
        e3.printStackTrace();
    }
    try {
        kmf = KeyManagerFactory.getInstance("SunX509");
    } catch (NoSuchAlgorithmException e2) {
        // TODO Auto-generated catch block
        e2.printStackTrace();
    }
    FileInputStream fin = null;
    try {
        fin = new FileInputStream("file here");
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    try {
        ks = KeyStore.getInstance("JKS");
    } catch (KeyStoreException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    try {
        ks.load(fin, storepass);
    } catch (NoSuchAlgorithmException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (CertificateException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

    try {
        kmf.init(ks, keypass);
    } catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    try {
        context.init(kmf.getKeyManagers(), null, null);
    } catch (KeyManagementException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    Client client = ClientBuilder.newBuilder().sslContext(context).build();

    WebTarget target = client
            .target("https://....");

    Builder builder = target.request();

I tried https://stackoverflow.com, it gave 200OK, I tried google.com, it said document has moved 302 status. I tried the url which I want to connect I got peer not authenticated exception

Caused by: javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
    at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:421) [jsse.jar:1.7.0_71]
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128) [httpclient-4.2.5.jar:4.2.5]
    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572) [httpclient-4.2.5.jar:4.2.5]
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180) [httpclient-4.2.5.jar:4.2.5]
    at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294) [httpclient-4.2.5.jar:4.2.5]
    at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640) [httpclient-4.2.5.jar:4.2.5]
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479) [httpclient-4.2.5.jar:4.2.5]
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906) [httpclient-4.2.5.jar:4.2.5]
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805) [httpclient-4.2.5.jar:4.2.5]
    at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:283) [resteasy-client-3.0.6.Final.jar:]
    ... 30 more

And the server asks for basic authentication, is it the reason for the exception?

pinkpanther
  • 4,770
  • 2
  • 38
  • 62

2 Answers2

4

Here are my codes to use JAX-RS with HTTPS using Wildly 10.Note that Wildly implementation for JAX-RS is RestEasy 3.xxxx.

ClientBuilder builder = ClientBuilder.newBuilder();
builder.sslContext(ConnectionFactory.getSslContext());
builder.hostnameVerifier(ConnectionFactory.getHostnameVerifier());
client = builder.build();
String baseURI = acsUser.getSelectedService().getWebserviceBaseUrl();
WebTarget webTarget = client.target(baseURI);

Here is the class called ConnectionFactory.

public class ConnectionFactory {

Proxy proxy;

String proxyHost;

Integer proxyPort;

public boolean canConnect = true;

private static final Logger log = Logger.getLogger("ReportPortal");

public ConnectionFactory() {
}

/**
 *
 * @return
 */
public static SSLContext getSslContext() {
    SSLContext sslContext = null;
    try {
        sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, new TrustManager[]{new      SecureTrustManager()}, new SecureRandom());
    }
    catch (NoSuchAlgorithmException | KeyManagementException ex) {
        log.error("ERROR OCCURS", ex);
    }
    return sslContext;
}

/**
 *
 * @return
 */
public static HostnameVerifier getHostnameVerifier() {
    return (String hostname, javax.net.ssl.SSLSession sslSession) -> true;
}

public Boolean isHttps(String url) {

    if (url.startsWith("https://")) {
        return Boolean.TRUE;
    }
    else {
        return Boolean.FALSE;
    }
}

}

AIMABLE
  • 885
  • 8
  • 5
  • 1
    This solution worked for me, using this implementation of SecureTrustManager http://stackoverflow.com/questions/10385259/configure-proxy-to-jersey-client/10394903 – user954156 Apr 03 '17 at 14:50
3

"Do we have to generate keystores ourselves?"

Yes. You need to generate one for the Server and a Trust store (which is just a key store, but we just call it a trust store to differentiate it).

See SSL setup guide in the Wildfly documentation. It will show you how to create a keystore and configure it with Wildfly. Just follow the section "Pure Java SSL-Setup using keytool"

Then you need to create the client keystore. You will export the certificate from the server store and import it into the client store.

How it works is that the Client needs to trust the server. And the way to do that is through the Server certificate. Now if the certificate is signed by from a well known CA, generally Java will already support this cert, and we dont need to configure the client. But since you are creating your own self signed cert, we need to configure the client to trust the server certificate by importing it into the trust-store.

You can see all the step for handling the certs/stores for both client and server here in this post. Scroll down to step 5. The three code snippets that begin with keytool are the commands to complete this task. The first creates the server store named tomcat-keystore.jks (but you can name it anything). The next snippet exports the certificate from the keystore, into a file name tomcat.crt (but you an name it anything). The third command will import the previous cert into a client-truststore.jks (but you can name it anything). You'll notice that you don't need to explicitly create the trust-store, it be will create implicitly when we do an import.

Once you have the server keystore, follow the instructions in the wildfly documentation linked above and configure the store with the server.

To configure the Client, see step 6 in the above linked answer. It configures the client with the trust-store we created. Everything in the code is standard Java and JAX-RS except for the configuration of the Basic auth, which is specific to Jersey.

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • I'm connecting https url but that url is not mine..I mean not from my jax-rs application...I just want to connect to that url using ClientBuilder api..so in this case, I do not need to configure wildfly server with certificate right? since I don't want to host any https conenctions? – pinkpanther Jun 05 '15 at 08:55
  • Sorry, I thought you wanted to do some testing from your server and client. If the server you are accessing has a certificate signed by a well know CA, chances are Java has the cert in it's own trust-store and you will not need to configure it. Say you wanted to access a Google API. There will definitely be a cert in the trust-store, and you don't need to configure the client. Only need to do so when the cert is not trusted. You can try to make an https request to the server and see what happens. If cert is not trusted, you can either ignore the untrusted cert, or downloaded it and add it – Paul Samsotha Jun 05 '15 at 09:02
  • I could probably find you some good info on either case, but first you should probably check if it already works with the url you are trying to access. – Paul Samsotha Jun 05 '15 at 09:04
  • in this case which SSLConext should I pass? I tried with getDefault it did not work. I'm getting peer not authenticated. The part I have trouble with is to initialize the sslcontext with keystore and all. But is it not possible to assume that server's certificate is valid and authenticate? – pinkpanther Jun 05 '15 at 09:09
  • First of all. I basically tried in normal way like `ClientBuilder.newClient().target("https://.....").post()`, after which it has thrown Peer not authenticated after which I realized that it's https so I need something more. – pinkpanther Jun 05 '15 at 09:12
  • If you want to ignore the problem, you may be able to use the `TrustManager[]` seen [here](https://gist.github.com/outbounder/1069465). If you look at the client code I linked to above you will the the `SSLContext` is initialized with the array as the second argument. Just replace `tmf.getTrustManagers()` with the `TrustManager[]` in the Github link. I've never tried this, but I remember seeing from some posts that this works. – Paul Samsotha Jun 05 '15 at 09:21
  • If it doesn't work, you can try to download the cert and add it to the Java trust store. Compile the code from [this link](http://helpdesk.objects.com.au/java/how-do-i-programatically-extract-a-certificate-from-a-site-and-add-it-to-my-keystore), then run `java InstallCert changeit`. Note `changeit` is the default password for the Java keystore – Paul Samsotha Jun 05 '15 at 09:22
  • Oh and another thing for the "ignore" option. You may need to get the `HostnameVerifier` with the `ClientBuilder`. You can see an implementation where it always returns true, in the github link also – Paul Samsotha Jun 05 '15 at 09:33
  • I'm using rest easy...github link uses ClientConfig which can't be resolved in my workspace. – pinkpanther Jun 05 '15 at 09:38
  • Sorry I didn't make it clear. The code I linked to in the original answer uses standard JAX-RS code. I only linked to github to get the `TrustManager[]` and also the `HostnameVerifier`. You can replace the code for the trust manage in the first link. And use `ClientBuilder.hostnameVerifer` to set the `HostnameVerifier` – Paul Samsotha Jun 05 '15 at 09:41
  • 1
    Basically all you need is `SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null);`. Replace the `tmf.getTrustManagers()` with the `TrustManager[]` from the github. Then you can do `ClientBuilder.newBuilder().sslContext(sslContext).hostNameVerifier(hostNameVierifer)` – Paul Samsotha Jun 05 '15 at 09:50
  • Could you possibly post the working code put together? I'm having hard time due to me being new to this. – pinkpanther Jun 05 '15 at 10:00