具有两个URL连接的Java webapp:基本身份验证和证书身份验证

时间:2017-03-21 14:59:32

标签: java authentication certificate httpurlconnection basic-authentication

我有一个java webapp,它使用此类通过使用基本auth和cert连接到服务器。它可以单独工作(不创建其他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>

如何在一个webapp中解决两个连接的证书问题?

1 个答案:

答案 0 :(得分:0)

通过修改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 获取建议。

相关问题