web-dev-qa-db-ja.com

Javaを使用して、証明書を使用してHTTPS経由でRESTfulサービスを利用する

私はRESTサービスの新規ユーザーです。Jerseyで生成されたRESTful APIサービスを利用する必要があります。問題は、そのサービスがリモートホストでホストされており、証明書付きのhttpsアクセスが必要なためです。

組織から証明書を取得しましたが、REST APIサービスに任意のブラウザー(証明書が設定されている)でアクセスできます)にアクセスできます。

私はここでたくさんの投稿を読みました、そして私はこのトピックに関する答えに従いました: REST)でHTTPSを使用する

Java Keystoreで証明書をセットアップしました。しかし、Javaプログラムでそれを使用する方法がわからないので、証明書を正確に使用しますhttps接続を行う必要があります。

これは、ローカルテスト用の私の単純な接続コードです。

package rest.test.first;
import Java.net.URI;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

import com.Sun.jersey.api.client.Client;
import com.Sun.jersey.api.client.ClientResponse;
import com.Sun.jersey.api.client.WebResource;
import com.Sun.jersey.api.client.config.ClientConfig;
import com.Sun.jersey.api.client.config.DefaultClientConfig;

public class TestClient{
public static void main(String[]args){
    ClientConfig config= new DefaultClientConfig();
    Client client=Client.create(config);
    WebResource service=client.resource(getBaseURI());
    //Fluentinterfaces
    System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_PLAIN).get(ClientResponse.class).toString());
    //Getplaintext
    System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_PLAIN).get(String.class));
    //GetXML
    System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_XML).get(String.class));
    //TheHTML
    System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_HTML).get(String.class));
}

private static URI getBaseURI(){
    return UriBuilder.fromUri("http://localhost:8080/rest.test").build();
}
}

システムセットプロパティを使用して、次のコードでキーストアへのパスを指定する方法について読みます。

System.setProperty("javax.net.ssl.keyStore", "/path/to/keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "password");

それでもリモートサーバーへの接続で401エラーが発生します。

しかし、私はキーストアの私の証明書を使用してSSL接続を行う方法がわかりません。この目的のためにsslSocketFactoryを使用することについても読んでいますが、この投稿で説明されているように機能させることができませんでした: 特定の接続で異なる証明書を使用するにはどうすればよいですか?

このコードを使用して、キーストアから証明書を取得できました。接続に使用する方法を知る必要があります。

package rest.test.first;

    import Java.io.FileInputStream;
    import Java.security.KeyStore;
    import Java.security.cert.Certificate;

    public class keystore {

      public static void main(String[] args) throws Exception {
        String keystoreFilename = "/usr/lib/jvm/jdk1.6.0_32/jre/lib/security/cacerts";

        char[] password = "changeit".toCharArray();
        String alias = "remote_https_server";

        FileInputStream fIn = new FileInputStream(keystoreFilename);
        KeyStore keystore = KeyStore.getInstance("JKS");

        keystore.load(fIn, password);

        Certificate cert = keystore.getCertificate(alias);

        System.out.println(cert);
      }
    }

それが、私が書いた最後のスクリプトです。 httpsサイトに接続できますが、認証のために証明書を送信する必要があるhttpsサイトに接続できません。

package rest.test.first;


import Java.io.*;
import Java.net.*;
import Java.security.*;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;


public class urlConnection{
  public static void main(String args[]) throws Exception {

     System.setProperty("javax.net.ssl.trustStore", "/usr/lib/jvm/jdk1.6.0_32/jre/lib/security/cacerts"); 
  System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
  Security.addProvider(new com.Sun.net.ssl.internal.ssl.Provider());

      //TrustStore..
      char[] passphrase = "changeit".toCharArray(); //password
      KeyStore keystore = KeyStore.getInstance("JKS");
      //KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
      keystore.load(new FileInputStream("/usr/lib/jvm/jdk1.6.0_32/jre/lib/security/cacerts"), passphrase); //path

      //TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); //instance
      TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
      tmf.init(keystore);


      SSLContext context = SSLContext.getInstance("TLS");
      TrustManager[] trustManagers = tmf.getTrustManagers();
      context.init(null, trustManagers, null);
      SSLSocketFactory sf = context.getSocketFactory();
      URL url = new URL("https://www.google.es");

      HttpsURLConnection httpsCon = (HttpsURLConnection) url.openConnection();
      httpsCon.setSSLSocketFactory(sf);
      httpsCon.setRequestMethod("GET");

      /*InputStream inStrm = httpsCon.getInputStream();
      System.out.println("\nContent at " + url);
      int ch;
        while (((ch = inStrm.read()) != -1)){
          System.out.print((char) ch);
        inStrm.close();
      }*/

      System.out.println("Response Message is " + httpsCon.getResponseMessage());

 }
}
13
gmarco

このコードをサーバーにデプロイし、他のすべてを正しく実行したと想定します(キーストアコアを正しく生成し、同じJavaキーストアを生成するためのコードとしてのバージョン)そして、私はあなたがする必要があるのは以下を追加することだと思います

<Connector SSLEnabled="true" clientAuth="false" keystoreFile="pathToKeystore" keystorePass="password" maxThreads="150" port="443" protocol="HTTP/1.1" scheme="https" secure="true" sslProtocol="TLS"/>

クライアントを実行しているサーバーインスタンスのserver.xml

<Connector connectionTimeout="20000" port="80" protocol="HTTP/1.1" redirectPort="8443"/>

IMP:このコードと一緒にSkypeを使用している場合は、追加の接続にも同じポート(80および443)を使用するため、デフォルト値を必ず(チェック解除)変更してください。

3
mayank vats