How can I use certificate authentication with HttpsURLConnection?

前端 未结 3 1002
遥遥无期
遥遥无期 2020-12-13 21:39

I\'m trying to connect to an HTTPS URL, but I need to use client authentication with a certificate placed on my system by third party software.

I haven\'t the slight

3条回答
  •  旧时难觅i
    2020-12-13 22:18

    Okay, so your question's title is How can I use certificate authentication with HttpsURLConnection? I have a working example for that. For it to work it has one prerequisite:

    1. you have to have a key store which has your certificate file in it. (I know that your scenario not exactly permits this, but please just follow me here a bit so that we can narrow your problem down a little bit, because it's a bit too complicated to answer right off the bat.)

    So, first get your hand on the actual certificate file. If you're on Windows 7 this can be done by the following steps:

    1. open Internet Explorer,
    2. open Tools (in Internet Explorer 9 it is the cog icon),
    3. click Internet Options,
    4. go to the Content tab,
    5. click Certificates,
    6. find the certificate at hand,
    7. click on it and click Export and save it to a file (DER encoded binary X.509).

    (After exporting it delete it from among the other certificates, making sure Java won't use it one way or another. I don't know if it can use it, but it couldn't hurt.)

    Now, you have to create a key store file and import the exported certificate into it, which can be done by the following.

    > keytool -importcert -file  -keystore  -alias 
    

    (Obviously, keytool has to be on your path to work. It's part of the JDK.)

    It'll prompt you for a password (the key store's password; it doesn't have to do anything with the certificate), which I don't know how to set to "" right now, so set let it be password or whatever.

    After this, with the following steps you can establish a secure connection to your endpoint via a proxy.

    1. First, load the key store file.

      InputStream trustStream = new FileInputStream("path/to/");
      char[] trustPassword = "".toCharArray();
      
    2. Initialize a KeyStore.

      KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
      trustStore.load(trustStream, trustPassword);
      
    3. Initialize TrustManager objects. (I think these handle certificate resolution or something like that, however as far as I'm concerned this is magic.)

      TrustManagerFactory trustFactory =
          TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
      trustFactory.init(trustStore);
      TrustManager[] trustManagers = trustFactory.getTrustManagers();
      
    4. Create a new SSLContext, load the TrustManager objects into it and set it as default. Take care, because SSLContext.getDefault() returns a non-modifiable instance of the class (or more like the default one can't be re-initialized, but whatever), that's why we have to use SSLContext.getInstance("SSL"). Also, don't forget to set this new SSLContext as the default, because without that the code goes poof.

      SSLContext sslContext = SSLContext.getInstance("SSL");
      sslContext.init(null, trustManagers, null);
      SSLContext.setDefault(sslContext);
      
    5. Create your proxy and setup authentication for it. (Instead of using System.setProperty(...) use the Proxy class. Oh and don't be mislead by Type.HTTP.)

      Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("", ));
      
    6. Setup authentication for your proxy. (I've used a free proxy which didn't require authentication so I couldn't test that part of the problem right now.)

      Authenticator.setDefault(new Authenticator() {
      
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
          return new PasswordAuthentication("", "".toCharArray());
        }
      });
      
    7. Connect to your end point by passing the previously created proxy to the connection. (I've used one of my company's service's URL, which asks for a certificate—which certificate I imported in my own key store of course.)

      URL url = new URL("");
      URLConnection connection = url.openConnection(proxy);
      connection.connect();
      

    If it doesn't work like this (you get errors) then try it with HttpsURLConnection.

       HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
       httpsConnection.setAllowUserInteraction(true);
       httpsConnection.setRequestMethod("POST");
    

    Basically, the setAllowUserInteraction thingy kicks in if the server (where the resource pointed by the URL you connect to is located) asks for credentials, right? Now, I couldn't test just that per se, but as I see if you can get this baby working with a server that doesn't require authentication to access its resources, then you're good to go, because the server will ask you to authenticate yourself only after the connection is already established.

    If after these you still receive some error, then please post it.

提交回复
热议问题