66

I'm using the Jersey Client library to run tests against a rest service running on jboss. I have https set up fine on the server (running on localhost), using a self signed cert.

However whenever I run my tests with the https url I get the following error:

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:131)
    at com.sun.jersey.api.client.Client.handle(Client.java:629)
    at com.sun.jersey.oauth.client.OAuthClientFilter.handle(OAuthClientFilter.java:137)
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:601)
    at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
    at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:459)
    at test.helper.Helper.sendSignedRequest(Helper.java:174)
    ... And so on

I know this is because my self signed cert is not in the java keystore. Is there any way I can make the Client not check the validity of the ssl cert and just use it regardless?

This code will only ever be run against test servers so I don't want to go to the hassle of adding new trusted certs each time we set up a new test server.

Here's the code which is making the call:

OAuthParameters params = new OAuthParameters();

// baseline OAuth parameters for access to resource
params.signatureMethod(props.getProperty("signature_method"));
params.consumerKey(props.getProperty("consumer_key"));
params.setToken(props.getProperty("token"));
params.setVersion("1.0");
params.nonce();

// OAuth secrets to access resource
OAuthSecrets secrets = new OAuthSecrets();
secrets.consumerSecret(props.getProperty("consumer_secret"));
secrets.setTokenSecret(props.getProperty("token_secret"));

// Jersey client to make REST calls to token services
Client client = Client.create();

// OAuth test server resource
WebResource resource = client.resource(props.getProperty("url"));

// if parameters and secrets remain static, filter cab be added to each web resource
OAuthClientFilter filter = new OAuthClientFilter(client.getProviders(), params, secrets);

// filter added at the web resource level
resource.addFilter(filter);
WebResource.Builder wbr = resource.getRequestBuilder().accept(props.getProperty("accept"));

return wbr.get(ClientResponse.class);

Any help would be greatly appreciated.

Chris Salij
  • 2,966
  • 3
  • 24
  • 42
  • Does this answer your question? [Java client certificates over HTTPS/SSL](https://stackoverflow.com/questions/875467/java-client-certificates-over-https-ssl) – Matej J Nov 19 '20 at 12:43

12 Answers12

97

After some searching and trawling through some old stackoverflow questions I've found a solution in a previously asked SO question:

Here's the code that I ended up using.

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager(){
    public X509Certificate[] getAcceptedIssuers(){return null;}
    public void checkClientTrusted(X509Certificate[] certs, String authType){}
    public void checkServerTrusted(X509Certificate[] certs, String authType){}
}};

// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("TLS");
    sc.init(null, trustAllCerts, new SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
    ;
}
Community
  • 1
  • 1
Chris Salij
  • 2,966
  • 3
  • 24
  • 42
  • Chris, do you have a version that works with Java 7? In you code you did not provide a KeyStore at all, did you specify a keystore using SSL properties to the VM with -D? – Uri Lukach Dec 19 '13 at 12:45
  • I did not specify a KeyStore. I used the above code without any other VM arguements. If I believe the code works because it doesn't check if its it is signed by a trusted signer, it only checks if it is well formed. – Chris Salij Jan 24 '14 at 19:05
  • 8
    I had to replace `public X509Certificate[] getAcceptedIssuers(){return null;}` with `public X509Certificate[] getAcceptedIssuers(){return new X509Certificate[0];}` to make it work. – Frederic Leitenberger May 19 '14 at 14:04
  • 6
    This answer sets *all* HTTPS connections in Java to disregard the SSL certificate... this may not be what you want, as it is possible to do it only for the Client in question as shown in the other answer by @eitan and others. – Renato Nov 06 '16 at 19:44
  • 1
    This answer also does not conform to the contract of `TrustManager.getAcceptedIssuers()`. Do not use. – user207421 Jun 29 '18 at 06:40
70

For Jersey 2.* (Tested on 2.7) and java 8:

import java.security.cert.CertificateException; 
import java.security.cert.X509Certificate; 
import javax.net.ssl.SSLContext; 
import javax.net.ssl.TrustManager; 
import javax.net.ssl.X509TrustManager; 

public static Client ignoreSSLClient() throws Exception {

    SSLContext sslcontext = SSLContext.getInstance("TLS");

    sslcontext.init(null, new TrustManager[]{new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
    }}, new java.security.SecureRandom());

    return ClientBuilder.newBuilder()
                        .sslContext(sslcontext)
                        .hostnameVerifier((s1, s2) -> true)
                        .build();
}
Andrea Ligios
  • 46,329
  • 24
  • 102
  • 208
eitan
  • 1,145
  • 9
  • 7
  • 4
    where is the import package from? java or javax? – Dejell Jun 30 '15 at 14:54
  • 2
    import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; – omni Jan 27 '17 at 17:47
  • I've found the hostname verification being optional. It may be because TLS does not require such checks, as opposed to https for example. – lcfd Jul 23 '18 at 13:24
12

I had the same problem adn did not want this to be set globally, so I used the same TrustManager and SSLContext code as above, I just changed the Client to be created with special properties

 ClientConfig config = new DefaultClientConfig();
 config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(
     new HostnameVerifier() {
         @Override
         public boolean verify( String s, SSLSession sslSession ) {
             // whatever your matching policy states
         }
     }
 ));
 Client client = Client.create(config);
Ransom Briggs
  • 2,927
  • 3
  • 30
  • 46
  • 1
    Removed arg, letting HTTPSProperites use this constructor https://jersey.java.net/nonav/apidocs/1.12/jersey/com/sun/jersey/client/urlconnection/HTTPSProperties.html#HTTPSProperties(javax.net.ssl.HostnameVerifier) – Ransom Briggs Jul 09 '13 at 14:00
9

Since I am new to stackoverflow and have lesser reputation to comment on others' answers, I am putting the solution suggested by Chris Salij with some modification which worked for me.

            SSLContext ctx = null;
            TrustManager[] trustAllCerts = new X509TrustManager[]{new X509TrustManager(){
                public X509Certificate[] getAcceptedIssuers(){return null;}
                public void checkClientTrusted(X509Certificate[] certs, String authType){}
                public void checkServerTrusted(X509Certificate[] certs, String authType){}
            }};
            try {
                ctx = SSLContext.getInstance("SSL");
                ctx.init(null, trustAllCerts, null);
            } catch (NoSuchAlgorithmException | KeyManagementException e) {
                LOGGER.info("Error loading ssl context {}", e.getMessage());
            }

            SSLContext.setDefault(ctx);
Mukesh
  • 263
  • 2
  • 11
8

This code will only ever be run against test servers so I don't want to go to the hassle of adding new trusted certs each time we set up a new test server.

This is the kind of code that will eventually find its way in production (if not from you, someone else who's reading this question will copy and paste the insecure trust managers that have been suggested into their applications). It's just so easy to forget to remove this sort of code when you have a deadline, since it doesn't show up as a problem.

If you're worried about having to add new certificates every time you have a test server, create your own little CA, issue all the certificates for the test servers using that CA and import this CA certificate into your client trust store. (Even if you don't deal with things like online certificate revocation in a local environment, this is certainly better than using a trust manager that lets anything through.)

There are tools to help you do this, for example TinyCA or XCA.

hlovdal
  • 23,353
  • 10
  • 78
  • 148
Bruno
  • 110,518
  • 24
  • 258
  • 357
  • And while the original TinyCA project seems quite dead, it is currently [maintained by Debian](https://tracker.debian.org/pkg/tinyca). – hlovdal Nov 24 '20 at 21:15
6

For anyone on Jersey 2.x without lambdas, use this:

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;

public static Client getUnsecureClient() throws Exception 
{
    SSLContext sslcontext = SSLContext.getInstance("TLS");
    sslcontext.init(null, new TrustManager[]{new X509TrustManager() 
    {
            public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException{}
            public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException{}
            public X509Certificate[] getAcceptedIssuers()
            {
                return new X509Certificate[0];
            }

    }}, new java.security.SecureRandom());


    HostnameVerifier allowAll = new HostnameVerifier() 
    {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    return ClientBuilder.newBuilder().sslContext(sslcontext).hostnameVerifier(allowAll).build();
}

Tested with jersey-client 2.11 on JRE 1.7.

omni
  • 2,986
  • 6
  • 42
  • 62
3

Just adding the same code with the imports. Also contains the unimplemented code that is needed for compilation. I initially had trouble finding out what was imported for this code. Also adding the right package for the X509Certificate. Got this working with trial and error:

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.security.cert.CertificateException;
import javax.security.cert.X509Certificate;
import javax.ws.rs.core.MultivaluedMap;

 TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {

     public java.security.cert.X509Certificate[] getAcceptedIssuers() {
         java.security.cert.X509Certificate[] chck = null;
         ;
         return chck;
     }

     public void checkServerTrusted(X509Certificate[] arg0, String arg1)
             throws CertificateException {
         // TODO Auto-generated method stub

     }

     public void checkClientTrusted(X509Certificate[] arg0, String arg1)
             throws CertificateException {

     }

     public void checkClientTrusted(
             java.security.cert.X509Certificate[] arg0, String arg1)
                     throws java.security.cert.CertificateException {
         // TODO Auto-generated method stub

     }

     public void checkServerTrusted(
             java.security.cert.X509Certificate[] arg0, String arg1)
                     throws java.security.cert.CertificateException {
         // TODO Auto-generated method stub

     }
 } };

 // Install the all-trusting trust manager
 try {
     SSLContext sc = SSLContext.getInstance("TLS");
     sc.init(null, trustAllCerts, new SecureRandom());
     HttpsURLConnection
     .setDefaultSSLSocketFactory(sc.getSocketFactory());
 } catch (Exception e) {
     ;
 }
2

For Jersey 2.*:

Client client = ClientBuilder.newBuilder()
                .hostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                }).build();

-> https://jersey.java.net/documentation/latest/migration.html

Andrew
  • 6,396
  • 3
  • 25
  • 38
Marcelo C.
  • 3,494
  • 2
  • 19
  • 11
  • Further simplification with lambda: Client client = ClientBuilder.newBuilder() .hostnameVerifier((hostname, session) -> true) .build(); – Ramsharan Sep 10 '20 at 10:11
1

I noticed that when using the Apache http client configuration with a pooling manager, the accepted answer doesn't work.

In this case it appears that the ClientConfig.sslContext and ClientConfig.hostnameVerifier setters are silently ignored. So if you are using connection pooling with the apache client http client config, you should be able to use the following code to get ssl verification to be ignored:

  ClientConfig clientConfig = new ClientConfig();
  // ... configure your clientConfig
  SSLContext sslContext = null;
  try {
    sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, new TrustManager[] {
        new X509TrustManager() {
          @Override
          public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
          }

          @Override
          public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
          }

          @Override
          public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[] {};
          }
        }
    }, null);
  } catch (NoSuchAlgorithmException e) {
    //logger.debug("Ignoring 'NoSuchAlgorithmException' while ignoring ssl certificate validation.");
  } catch (KeyManagementException e) {
    //logger.debug("Ignoring 'KeyManagementException' while ignoring ssl certificate validation.");
  }
  Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
      .register("http", PlainConnectionSocketFactory.getSocketFactory())
      .register("https", new SSLConnectionSocketFactory(sslContext, new AbstractVerifier() {
        @Override
        public void verify(String host, String[] cns, String[] subjectAlts) {
        }
      }))
      .build();
  connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
  clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager);
  return ClientBuilder.newClient(clientConfig);
Nicholas DiPiazza
  • 8,329
  • 8
  • 63
  • 123
0

For Jersey 1.X

    TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {

        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {}

        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {}

        public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
            // or you can return null too
            return new java.security.cert.X509Certificate[0];
        }
    }};


    SSLContext sc = SSLContext.getInstance("TLS");
    sc.init(null, trustAllCerts, new SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
        public boolean verify(String string, SSLSession sslSession) {
            return true;
        }
    });
grep
  • 4,615
  • 10
  • 48
  • 96
  • 1
    You cannot return null too. See the Javadoc. – user207421 Dec 29 '16 at 09:13
  • please test and you will see the result! – grep Dec 29 '16 at 09:19
  • also sometimes you may return null to work everything well. please read comments. http://stackoverflow.com/a/6055903/2590960 – grep Dec 29 '16 at 09:22
  • This is all irrelevant. You can't cite a StackOverflow answer in another StackOverflow answer when the Javadoc contradicts both of them. Any answer here or elsewhere that returns null is as wrong as this one. Please read what it says in the Javadoc and conform to the required contract. – user207421 Jun 29 '18 at 06:41
0

Okay, I'd like to just add my class only because there might be some dev out there in the future that wants to connect to a Netbackup server (or something similar) and do stuff from Java while ignoring the SSL cert. This worked for me and we use windows active directory for auth to the Netbackup server.

public static void main(String[] args) throws Exception {
    SSLContext sslcontext = null;
    try {
        sslcontext = SSLContext.getInstance("TLS");
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(main.class.getName()).log(Level.SEVERE, null, ex);
    }
    try {
        sslcontext.init(null, new TrustManager[]{new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
            @Override
            public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
            }

            @Override
            public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
            }
        }}, new java.security.SecureRandom());
    } catch (KeyManagementException ex) {
        Logger.getLogger(main.class.getName()).log(Level.SEVERE, null, ex);
    }
    //HttpAuthenticationFeature feature = HttpAuthenticationFeature.basicBuilder().credentials(username, password).build();
    ClientConfig clientConfig = new ClientConfig();
    //clientConfig.register(feature);
    Client client = ClientBuilder.newBuilder().withConfig(clientConfig)
            .sslContext(sslcontext)
            .hostnameVerifier((s1, s2) -> true)
            .build();

    //String the_url = "https://the_server:1556/netbackup/security/cacert";
    String the_token;
    {
        String the_url = "https://the_server:1556/netbackup/login";
        WebTarget webTarget = client.target(the_url);

        Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON);
        String jsonString = new JSONObject()
                .put("domainType", "NT")
                .put("domainName", "XX")
                .put("userName", "the username")
                .put("password", "the password").toString();
        System.out.println(jsonString);
        Response response = invocationBuilder.post(Entity.json(jsonString));
        String data = response.readEntity(String.class);
        JSONObject jo = new JSONObject(data);
        the_token = jo.getString("token");
        System.out.println("token is:" + the_token);

    }
    {
        String the_url = "https://the_server:1556/netbackup/admin/jobs/1122012"; //job id 1122012 is an example
        WebTarget webTarget = client.target(the_url);
        Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON).header(HttpHeaders.AUTHORIZATION, the_token).header(HttpHeaders.ACCEPT, "application/vnd.netbackup+json;version=1.0");
        Response response = invocationBuilder.get();
        System.out.println("response status:" + response.getStatus());
        String data = response.readEntity(String.class);
        //JSONObject jo = new JSONObject(data);
        System.out.println(data);
    }
}

I know it can be considered off-topic, but I bet the dev that tries to connect to a Netbackup server will probably end up here. By the way many thanks to all the answers in this question! The spec I'm talking about is here and their code samples are (currently) missing a Java example.

***This is of course unsafe since we ignore the cert!

xtsoler
  • 1,690
  • 1
  • 9
  • 7
-3

worked for me with this code. May be its for Java 1.7

    TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {
            // TODO Auto-generated method stub

        }

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {
            // TODO Auto-generated method stub

        }
    }};

    // Install the all-trusting trust manager
    try {
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (Exception e) {
        ;
    }
laalto
  • 137,703
  • 64
  • 254
  • 280
Tapas
  • 7