【问题标题】:Java webapp with two URL connections: basic auth and cert auth具有两个 URL 连接的 Java webapp:基本身份验证和证书身份验证
【发布时间】:2017-08-13 07:58:00
【问题描述】:

我有一个 java webapp,它使用此类通过基本身份验证和证书连接到服务器。它单独工作正常(无需创建其他 url 连接):

public void connectCert(String jsonParams) {
    try {

        KeyStore clientStore = KeyStore.getInstance("PKCS12");
        clientStore.load(new FileInputStream("d:\\certs\\api\\xx.p12"), "W*53as_G".toCharArray());

        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(clientStore, "W*53as_G".toCharArray());
        KeyManager[] kms = kmf.getKeyManagers();

        KeyStore trustStore = KeyStore.getInstance("JKS");
        trustStore.load(new FileInputStream("c:\\jdk1.8.0_51\\jre\\lib\\security\\cacerts"), "changeit".toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);
        TrustManager[] tms = tmf.getTrustManagers();

        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(kms, tms, new SecureRandom());

        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        URL url = new URL("https://apis2s.ee/test");

        HttpsURLConnection urlConn = (HttpsURLConnection) url.openConnection();
        urlConn.setRequestProperty("Authorization", "Basic " + Base64.encode("andrey:pass_1".getBytes()));
        urlConn.setUseCaches(false);
        urlConn.setAllowUserInteraction(true);
        urlConn.setRequestProperty("Pragma", "no-cache");
        urlConn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
        urlConn.setRequestProperty("Content-length", Integer.toString(jsonParams.length()));

        urlConn.setDoOutput(true);
        urlConn.setRequestProperty("Content-Length", Integer.toString(jsonParams.length()));
        PrintStream out = new PrintStream(urlConn.getOutputStream());
        out.print(jsonParams);
        out.flush();
        out.close();

        StringBuilder builder = new StringBuilder();
        int responseCode = urlConn.getResponseCode();
        builder.append(responseCode).append(" ").append(urlConn.getResponseMessage()).append("\n");

        InputStream inputStream = null;

        if (responseCode == 200) inputStream = urlConn.getInputStream();
        else inputStream = urlConn.getErrorStream();//this returns 400
        Scanner in = new Scanner(inputStream);
        String responseStr = "";
        while (in.hasNextLine()) {
            String str = in.nextLine();
            responseStr += str;
        }
        System.out.println(builder);
        System.out.println("responseStr: " + responseStr);
    } catch (Exception e) {
    }
}

我还需要在我的 webapp 中使用基本身份验证(无证书)创建与另一台服务器的连接:

  private InputStream connectHTTPS(String loginData, String url, String params) {
  TrustManager[] trustAllCerts =
  new TrustManager[]{
    new X509TrustManager(){
      public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return null;
      }
      public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType){
      }
      public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
      }
      public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) {
        return true;
      }

      public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) {
        return true;
      }
  }};
  HostnameVerifier verifier = new HostnameVerifier() {
    public boolean verify(String string, SSLSession sSLSession) {
      return true;
    }
    public boolean verify(String string, String string2) {
      return true;
    }
  };
  SSLContext sc = null;
  try{
      sc = SSLContext.getInstance("SSL");
      sc.init(null, trustAllCerts, new java.security.SecureRandom());
      javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(verifier);
  }catch(Exception e){
      e.printStackTrace();
  }
  javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(verifier);
  URL serverURL = null;
  try{
      serverURL = new URL(null,url,new sun.net.www.protocol.https.Handler());
  }catch (Exception e){
       e.printStackTrace();
  }
  javax.net.ssl.HttpsURLConnection urlConn = null;
  try{
      urlConn = (javax.net.ssl.HttpsURLConnection)serverURL.openConnection();
      urlConn.setSSLSocketFactory(sc.getSocketFactory());
      urlConn.setRequestMethod("POST");
  }catch(Exception i){
    i.printStackTrace();
  }
  InputStream res = null;
  urlConn.setDoOutput(true);
  if(useLogin)
    urlConn.setRequestProperty("Authorization", "Basic " + loginData);
  urlConn.setUseCaches(false);
  urlConn.setAllowUserInteraction(true);
  urlConn.setRequestProperty("Pragma", "no-cache");
  urlConn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
  urlConn.setRequestProperty("Content-length", Integer.toString(params.length()));
  try{
      PrintStream out = new PrintStream(urlConn.getOutputStream());
      out.print(params);
      out.flush();
      out.close();
      res = urlConn.getInputStream();
  }catch(Exception o){
      o.printStackTrace();
  }
  return res;
  }

如果 connectCert() 之前调用了 connectHTTPS() 那么我得到

<html><head><title>400 No required SSL certificate was sent</title></head><body
bgcolor="white"><center><h1>400 Bad Request</h1></center><center>No required SSL certificate was sent</center><hr><center>nginx</center></body></html>

如何解决一个 web 应用中的两个连接的证书问题?

【问题讨论】:

  • 什么方法导致显示的错误,connectHTTPS 或 connectCert?
  • connectCert() 导致此块中显示的错误(我稍微编辑了代码) if (responseCode == 200) inputStream = urlConn.getInputStream(); else inputStream = urlConn.getErrorStream();//这个返回400
  • 似乎connectHttps的某些配置干扰了connectCert。我建议删除所有静态配置。例如,在 connectCert 中将 HttpsURLConnection.setDefaultHostnameVerifier 更改为 urlConn.setHostnameVerifier. Call urlConn.setSSLSocketFactory 。同时添加-Djavax.net.debug = all调试SSL连接

标签: java authentication certificate httpurlconnection basic-authentication


【解决方案1】:

问题已通过修改 connectHTTPS() 并删除所有 ssl 工厂/上下文配置得到解决。 connectCert() 没有改变。更新后的方法如下所示

private InputStream connectHTTPS(boolean useLogin, boolean showServerError, String loginData, String url, String params) {
InputStream res = null;
    HttpURLConnection connect =null;
    try{
    URL theURL = new URL(url);
    connect = (HttpURLConnection)theURL.openConnection();
    connect.setRequestMethod("POST");
    connect.setUseCaches(false);
    connect.setDoOutput(true);
    if(useLogin)
    connect.setRequestProperty("Authorization", "Basic " + loginData);
    connect.setRequestProperty("Pragma", "no-cache");
    connect.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
    connect.setRequestProperty("Content-length", Integer.toString(params.length()));
    PrintStream out = new PrintStream(connect.getOutputStream());
    out.print(params);
    out.flush();
    out.close();
    res = connect.getInputStream();
}catch(IOException iox){
    if (showServerError && connect != null){
        res = connect.getErrorStream();
    } else {
       res = new ByteArrayInputStream((iox.getMessage()).getBytes());
    }
}
return res;
}

感谢 pedrofb 的建议。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-20
    • 1970-01-01
    • 2013-06-06
    • 1970-01-01
    相关资源
    最近更新 更多