2010-02-18 16 views
16

मैं CommWeb नामक एक व्यापारी खाते के साथ एकीकृत कर रहा हूं और मैं अपने यूआरएल (https://migs.mastercard.com.au/vpcdps) में एक एसएसएल पोस्ट भेज रहा हूं।एसएसएल कनेक्शन बनाने के दौरान PKIX पथ निर्माण विफल रहा

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 

कोड (जो मैं नहीं लिखा था, और कहा कि पहले से ही हमारे codebase में मौजूद है) कि पोस्ट करता है:

public static HttpResponse sendHttpPostSSL(String url, Map<String, String> params) throws IOException { 
    PostMethod postMethod = new PostMethod(url); 
    for (Map.Entry<String, String> entry : params.entrySet()) { 
     postMethod.addParameter(entry.getKey(), StringUtils.Nz(entry.getValue())); 
    } 

    HttpClient client = new HttpClient(); 
    int status = client.executeMethod(postMethod); 
    if (status == 200) { 
     StringBuilder resultBuffer = new StringBuilder(); 
     resultBuffer.append(postMethod.getResponseBodyAsString()); 
     return new HttpResponse(resultBuffer.toString(), ""); 
    } else { 
     throw new IOException("Invalid response code: " + status); 
    } 
} 
जब मैं पोस्ट भेजने का प्रयास करें, मैं निम्नलिखित अपवाद

व्यापारी खाता एकीकरण के लिए प्रलेखन प्रमाणपत्रों के बारे में कुछ भी नहीं कहता है। वे कुछ नमूना JSP कोड है कि आँख बंद करके प्रमाण पत्र स्वीकार करने के लिए लगता है प्रदान किया:

<%! // Define Static Constants 
    // *********************** 
public static X509TrustManager s_x509TrustManager = null; 
public static SSLSocketFactory s_sslSocketFactory = null; 

static { 
     s_x509TrustManager = new X509TrustManager() { 
     public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[] {}; } 
     public boolean isClientTrusted(X509Certificate[] chain) { return true; } 
     public boolean isServerTrusted(X509Certificate[] chain) { return true; } 
    }; 

    java.security.Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); 
    try { 
     SSLContext context = SSLContext.getInstance("TLS"); 
     context.init(null, new X509TrustManager[] { s_x509TrustManager }, null); 
     s_sslSocketFactory = context.getSocketFactory(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
     throw new RuntimeException(e.getMessage()); 
    } 
} 

... 
... 
      // write output to VPC 
      SSLSocket ssl = (SSLSocket)s_sslSocketFactory.createSocket(s, vpc_Host, vpc_Port, true); 
      ssl.startHandshake(); 
      os = ssl.getOutputStream(); 
      // get response data from VPC 
      is = ssl.getInputStream(); 
... 
... 
%> 

हमारे webapp एक कीस्ट्रोक है, और मैं प्रमाण पत्र (जो मैं फ़ायरफ़ॉक्स से निर्यात) keytool आदेश का उपयोग कर जोड़ने की कोशिश की, लेकिन वह नहीं था काम और मुझे एक ही त्रुटि मिली। मैंने वेब पर समाधान की कोशिश की है (कुंजी आयात कर रहा है और System.setProperty का उपयोग कर रहा है) लेकिन ऐसा लगता है कि यह गुंजाइश है और यह काम नहीं करता (मुझे NoSuchAlgorithmError दिया गया)। किसी भी मदद की सराहना की है!

+0

http://stackoverflow.com/questions/21076179/pkix-path-building-failed-and-unable-to-find-valid-certification-path-to-requ/36427118#36427118 – MagGGG

उत्तर

13

स्पष्ट रूप से वैलिकार्ट क्लास 3 सीए प्रमाणपत्र आपके डिफ़ॉल्ट ट्रस्टस्टोर में नहीं है (जो शायद आपकी जेआरई lib/सुरक्षा निर्देशिका में कैकर्ट फ़ाइल है, लेकिन पूरी कहानी के लिए JSSE documentation देखें)।

आप इस प्रमाणपत्र को cacerts फ़ाइल में जोड़ सकते हैं, लेकिन मैं इसकी अनुशंसा नहीं करता हूं। इसके बजाए, मुझे लगता है कि आपको अपनी खुद की ट्रस्टस्टोर फ़ाइल बनाना चाहिए (जो कैकर्ट फ़ाइल की एक प्रति हो सकती है) और इसमें वैलिकर्ट रूट सीए जोड़ें। फिर javax.net.ssl.trustStore सिस्टम प्रॉपर्टी के साथ इस फ़ाइल को इंगित करें।

+0

मैं इसे आज़माउंगा आने वाला कल। अभी के लिए, मुझे यह एक नया सॉकेट फैक्ट्री बनाकर काम करने के लिए मिला है जो 'commons.httpclient' से 'SecureProtocolSocketFactory' लागू करता है। यह अंधेरे से प्रमाण पत्र स्वीकार करता है। हालांकि, मैं इसे बदलना चाहता हूं और इसे सही तरीके से काम करना चाहता हूं। मैं आपको बता दूंगा कि क्या होता है। धन्यवाद! –

+0

मैं अभी आगे बढ़ने जा रहा हूं और अपना समाधान स्वीकार कर सकता हूं और एक टिप्पणी के रूप में अपना जोड़ सकता हूं। मैं आपको उस दस्तावेज को देखने के बाद ही इसे समझने में सक्षम था जिसे आपने मुझे इंगित किया था! –

+0

ग्रेग, क्या आप मुझे समझा सकते हैं "इस पर वैलिकर्ट रूट सीए जोड़ें"। इसका क्या अर्थ है, और यह कैसे किया जाना चाहिए? – Less

7

मुझे लगता है कि मुझे यह जवाब वास्तव में जो किया गया है उसके साथ अपडेट करना चाहिए। ग्रेग्स प्रदान किए गए दस्तावेज का उपयोग करके, मैंने वैलिकार्ट के लिए एक ट्रस्ट मैनेजर बनाया। ट्रस्ट प्रबंधक में, मैं प्रमाणपत्र फ़ाइलें लोड:

public class ValicertSSLProtocolSocketFactory implements ProtocolSocketFactory { 

    private SSLContext sslContext = null; 

    public ValicertSSLProtocolSocketFactory() { 
     super(); 
    } 

    private static SSLContext createValicertSSLContext() { 
     try { 
      ValicertX509TrustManager valicertX509TrustManager = new ValicertX509TrustManager(); 
      SSLContext context = SSLContext.getInstance("TLS"); 
      context.init(null, new ValicertX509TrustManager[] { valicertX509TrustManager}, null); 
      return context; 
     } 

     catch(Exception e) { 
      Log.error(Log.Context.Net, e); 
      return null; 
     } 
    } 

    private SSLContext getSSLContext() { 
     if(this.sslContext == null) { 
      this.sslContext = createValicertSSLContext(); 
     } 

     return this.sslContext; 
    } 

    public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException { 
     return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort); 
    } 

    public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort, final HttpConnectionParams params) throws IOException { 
     if(params == null) { 
      throw new IllegalArgumentException("Parameters may not be null"); 
     } 

     int timeout = params.getConnectionTimeout(); 
     SocketFactory socketFactory = getSSLContext().getSocketFactory(); 

     if(timeout == 0) { 
      return socketFactory.createSocket(host, port, localAddress, localPort); 
     } 

     else { 
      Socket socket = socketFactory.createSocket(); 
      SocketAddress localAddr = new InetSocketAddress(localAddress, localPort); 
      SocketAddress remoteAddr = new InetSocketAddress(host, port); 
      socket.bind(localAddr); 
      socket.connect(remoteAddr, timeout); 
      return socket; 
     } 
    } 

    public Socket createSocket(String host, int port) throws IOException { 
     return getSSLContext().getSocketFactory().createSocket(host, port); 
    } 

    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { 
     return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); 
    } 

    public boolean equals(Object obj) { 
     return ((obj != null) && obj.getClass().equals(ValicertSSLProtocolSocketFactory.class)); 
    } 

    public int hashCode() { 
     return ValicertSSLProtocolSocketFactory.class.hashCode(); 
    } 
} 

अब मैं सिर्फ एक नए प्रोटोकॉल रजिस्टर:

public class ValicertX509TrustManager implements X509TrustManager { 

    X509TrustManager pkixTrustManager; 

    ValicertX509TrustManager() throws Exception { 

     String valicertFile = "/certificates/ValicertRSAPublicRootCAv1.cer"; 
     String commwebDRFile = "/certificates/DR_10570.migs.mastercard.com.au.crt"; 
     String commwebPRODFile = "/certificates/PROD_10549.migs.mastercard.com.au.new.crt"; 

     Certificate valicert = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(valicertFile)); 
     Certificate commwebDR = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(commwebDRFile)); 
     Certificate commwebPROD = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(commwebPRODFile)); 

     KeyStore keyStore = KeyStore.getInstance("JKS"); 
     keyStore.load(null, "".toCharArray()); 
     keyStore.setCertificateEntry("valicert", valicert); 
     keyStore.setCertificateEntry("commwebDR", commwebDR); 
     keyStore.setCertificateEntry("commwebPROD", commwebPROD); 

     TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX"); 
     trustManagerFactory.init(keyStore); 

     TrustManager trustManagers[] = trustManagerFactory.getTrustManagers(); 

     for(TrustManager trustManager : trustManagers) { 
      if(trustManager instanceof X509TrustManager) { 
       pkixTrustManager = (X509TrustManager) trustManager; 
       return; 
      } 
     } 

     throw new Exception("Couldn't initialize"); 
    } 

    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
     pkixTrustManager.checkServerTrusted(chain, authType); 
    } 

    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
     pkixTrustManager.checkServerTrusted(chain, authType); 
    } 

    public X509Certificate[] getAcceptedIssuers() { 
     return pkixTrustManager.getAcceptedIssuers(); 
    } 
} 

अब, यह विश्वास प्रबंधक का उपयोग कर, मैं एक सॉकेट कारखाना बनाने के लिए किया था

Protocol.registerProtocol("vhttps", new Protocol("vhttps", new ValicertSSLProtocolSocketFactory(), 443)); 
PostMethod postMethod = new PostMethod(url); 
for (Map.Entry<String, String> entry : params.entrySet()) { 
    postMethod.addParameter(entry.getKey(), StringUtils.Nz(entry.getValue())); 
} 

HttpClient client = new HttpClient(); 
int status = client.executeMethod(postMethod); 
if (status == 200) { 
    StringBuilder resultBuffer = new StringBuilder(); 
    resultBuffer.append(postMethod.getResponseBodyAsString()); 
    return new HttpResponse(resultBuffer.toString(), ""); 
} else { 
    throw new IOException("Invalid response code: " + status); 
} 

एकमात्र नुकसान यह है कि मुझे इस विशेष प्रमाणपत्र के लिए एक विशिष्ट प्रोटोकॉल (vhttps) बनाना था।

संबंधित मुद्दे