简体   繁体   English

使用Java在https上使用REST来使用RESTful服务

[英]Consuming RESTful service over https with certificate using Java

I'm a new user to REST services. 我是REST服务的新用户。 I need to consume a RESTful API service generated with Jersey. 我需要使用Jersey生成的RESTful API服务。 The problem comes because that service is hosted on remote host and it requires https access with certificate. 问题出现是因为该服务托管在远程主机上,并且需要https访问证书。

I got my certificate from the organization and i'm able to access that REST API service with any of my browsers (with certificate set on them). 我从组织获得了我的证书,并且我能够使用我的任何浏览器访问该REST API服务(其上设置了证书)。

I've read lot of posts over here, and I've followed the answer on this topic: Using HTTPS with REST in Java 我在这里阅读了很多帖子,我已经按照这个主题的答案: 在Java中使用HTTPS和REST

Now I've my certificate setup on my Java Keystore. 现在我在我的Java Keystore上设置了证书。 But i don't know how to use that on my Java program so it uses exactly the certificate i need to do the https connection. 但我不知道如何在我的Java程序中使用它,所以它使用我需要进行https连接的证书。

This is my simple connection code for local tests. 这是我用于本地测试的简单连接代码。

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();
}
}

I'v read about using system set properties to specify path to keystore with this code: 我读到了使用系统集属性来指定密钥库的路径,使用以下代码:

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

I still get 401 Error on connection to the remote server. 我仍然在连接到远程服务器时遇到401错误。

But then i don't know how to make SSL connection using my certificate on keystore. 但后来我不知道如何在密钥库上使用我的证书进行SSL连接。 I've been also reading about using sslSocketFactory for this purpose but i couldn't make it work as explained on this post: How can I use different certificates on specific connections? 我也一直在阅读有关使用sslSocketFactory的信息,但是我无法按照这篇文章的说明工作: 如何在特定连接上使用不同的证书?

I've managed to retrieve my cert from keystore with this code.. now I just need to know how to use it in connection: 我已经设法使用此代码从密钥库中检索我的证书..现在我只需要知道如何在连接中使用它:

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);
      }
    }

Ok that's the last script I've wrote. 好的,这是我写的最后一个脚本。 I can connect to https sites but i still can't connect to https sites which require to send my certificate to authenticate. 我可以连接到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());

 }
}

Assuming that you are deploying this code on a server and you have done Everything else correctly (Like generating keystore core correctly and placing it at a location where it can be accessed by your server ,using same java version as your code to generate the keystore )then i think what you need to do is add following 假设您正在服务器上部署此代码并且您已正确完成所有其他操作(例如正确生成密钥库核心并将其放置在服务器可以访问的位置,使用与您的代码相同的Java版本来生成密钥库)那么我认为你需要做的是添加以下内容

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

in server.xml of your Server instance on which you are running the client and 在运行客户端的Server实例的server.xml中

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

IMP: If you are using Skype alongside this code be sure to (uncheck) change the default value as it also uses the same ports (80 and 443) for additional connections IMP:如果您在此代码旁边使用Skype,请务必(取消选中)更改默认值,因为它还使用相同的端口(80和443)进行其他连接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM