Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/google-app-engine/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在Apache HttpClient中使用SSL客户端证书?_Java_Apache Httpclient 4.x - Fatal编程技术网

Java 如何在Apache HttpClient中使用SSL客户端证书?

Java 如何在Apache HttpClient中使用SSL客户端证书?,java,apache-httpclient-4.x,Java,Apache Httpclient 4.x,在Python中,我使用了如下请求: requests.put( webdavURL, auth=(tUsername, tPassword), data=webdavFpb, verify=False, cert=("/path/to/file.pem", "/path/to/file.key")) 容易极了 现在我需要使用ApacheHttpC

在Python中,我使用了如下请求:

requests.put(
              webdavURL, 
              auth=(tUsername, tPassword), 
              data=webdavFpb, 
              verify=False, 
              cert=("/path/to/file.pem", "/path/to/file.key"))
容易极了


现在我需要使用ApacheHttpClient在Java中实现同样的事情。使用HttpClient发出请求时,如何传递客户端证书?

如果要使用Apache HTTP客户端而不是Java HTTP客户端,必须向SSLFactory提供密钥库,并配置DefaultHTTPClient以在HTTPS协议中使用它

你可以找到一个有效的例子


我希望这会有所帮助。

我认为主要的区别在于,在java中,您通常将密钥和证书放在a中,然后从那里使用它。正如您经常提到的,人们确实希望为它使用单独的库,就像前面提到的(就像您在python示例中使用的一样)

下面是一个使用密钥存储中的客户端证书的示例,使用前面提到的库:

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.junit.Test;

import javax.net.ssl.SSLContext;
import java.io.InputStream;
import java.security.KeyStore;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class MyClientCertTest {

    private static final String KEYSTOREPATH = "/clientkeystore.jks"; // or .p12
    private static final String KEYSTOREPASS = "keystorepass";
    private static final String KEYPASS = "keypass";

    KeyStore readStore() throws Exception {
        try (InputStream keyStoreStream = this.getClass().getResourceAsStream(KEYSTOREPATH)) {
            KeyStore keyStore = KeyStore.getInstance("JKS"); // or "PKCS12"
            keyStore.load(keyStoreStream, KEYSTOREPASS.toCharArray());
            return keyStore;
        }
    }
    @Test
    public void readKeyStore() throws Exception {
        assertNotNull(readStore());
    }
    @Test
    public void performClientRequest() throws Exception {
        SSLContext sslContext = SSLContexts.custom()
                .loadKeyMaterial(readStore(), KEYPASS.toCharArray()) // use null as second param if you don't have a separate key password
                .build();

        HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
        HttpResponse response = httpClient.execute(new HttpGet("https://slsh.iki.fi/client-certificate/protected/"));
        assertEquals(200, response.getStatusLine().getStatusCode());
        HttpEntity entity = response.getEntity();

        System.out.println("----------------------------------------");
        System.out.println(response.getStatusLine());
        EntityUtils.consume(entity);
    }
}
依赖版本的Maven pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.acme</groupId>
    <artifactId>httptests</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.3</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.9</version>
                <!-- this is not needed, but useful if you want to debug what's going
                     on with your connection -->
                <configuration>
                    <argLine>-Djavax.net.debug=all</argLine>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
这是第三个版本,代码量最少,但这取决于以下事实:a)密钥库是磁盘上的文件,而不是jar中的文件;b)密钥密码必须与密钥库密码相同

import org.junit.BeforeClass;
import org.junit.Test;

import java.net.URL;
import java.io.*;
import javax.net.ssl.HttpsURLConnection;

public class PlainJavaHTTPSTest {

    @BeforeClass
    public static void setUp() {
        System.setProperty("javax.net.ssl.keyStore", "/full/path/to/clientkeystore-samepassword.jks");
        System.setProperty("javax.net.ssl.keyStorePassword", "keystorepass");
    }

    @Test
    public void testPlainJavaHTTPS() throws Exception {
        String httpsURL = "https://slsh.iki.fi/client-certificate/protected/";
        URL myUrl = new URL(httpsURL);
        HttpsURLConnection conn = (HttpsURLConnection)myUrl.openConnection();
        try (InputStream is = conn.getInputStream()) {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);

            String inputLine;

            while ((inputLine = br.readLine()) != null) {
                System.out.println(inputLine);
            }
        }
    }
}

当然,上面代码中设置的属性也可以作为启动参数提供,
-Djavax.net.ssl.keyStore=/full/path/to/clientkeystore samepassword.jks
-Djavax.net.ssl.keystrepassword=keystrepass

您能给出一些使用Java HTTP客户端的指针吗?我在使用Apache one时遇到了困难。我可能弄错了,但该示例似乎只是关于使用自定义信任库(例如,信任通常不受信任的证书),而不是提供客户端证书来验证客户端。这并不能回答问题。这将只添加自定义信任存储,而不是客户端证书。此示例是关于自定义信任存储的。这并没有说明如何提供客户端证书。如果密钥库包含多个密钥,代码如何知道使用哪一个密钥?@DavidBrossard我已经尝试了好几天让证书代码工作;我已经用多种方法尝试了这段代码,但仍然没有效果。我没有jks或p12文件,只有/C/Program Files/Java/jdk1.8.0_271/jre/lib/security/cacerts文件-我得到“PKIX路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:找不到请求目标的有效认证路径”我已经尝试了很多帖子-;这是否只适用于.jks/.p12文件;我怎么得到这些?请帮助。@ASheppardWork如果您只有cacerts文件,听起来您没有客户端证书,所以它与此问题或此代码无关?
import org.junit.BeforeClass;
import org.junit.Test;

import java.net.URL;
import java.io.*;
import javax.net.ssl.HttpsURLConnection;

public class PlainJavaHTTPSTest {

    @BeforeClass
    public static void setUp() {
        System.setProperty("javax.net.ssl.keyStore", "/full/path/to/clientkeystore-samepassword.jks");
        System.setProperty("javax.net.ssl.keyStorePassword", "keystorepass");
    }

    @Test
    public void testPlainJavaHTTPS() throws Exception {
        String httpsURL = "https://slsh.iki.fi/client-certificate/protected/";
        URL myUrl = new URL(httpsURL);
        HttpsURLConnection conn = (HttpsURLConnection)myUrl.openConnection();
        try (InputStream is = conn.getInputStream()) {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);

            String inputLine;

            while ((inputLine = br.readLine()) != null) {
                System.out.println(inputLine);
            }
        }
    }
}