2012-04-21 9 views
49

Sto richiamando il servizio Web SOAP HTTPS tramite codice java. Ho già importato il certificato autofirmato nel keystore di jre cacerts. Ora sto ottenendo:SSLHandshakeException: nessun nome alternativo di soggetto presente

com.sun.xml.internal.ws.com.client.ClientTransportException: HTTP transport error: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present 

L'hostname del URL del servizio non corrisponde quella della NC fornite in cert. Ho letto di una soluzione alternativa per definire un verificatore di nome host personalizzato here. Ma non riesco a capire dove dovrei implementare la soluzione alternativa nel mio codice.

public SOAPMessage invokeWS(WSBean bean) throws Exception { 

    SOAPMessage response=null; 
    try{ 

    /** Create a service and add at least one port to it. **/ 
    String targetNameSpace = bean.getTargetNameSpace(); 
    String endpointUrl = bean.getEndpointUrl(); 
    QName serviceName = new QName(targetNameSpace, bean.getServiceName()); 
    QName portName = new QName(targetNameSpace, bean.getPortName()); 
    String SOAPAction = bean.getSOAPAction(); 
    HashMap<String, String> map = bean.getParameters(); 


    Service service = Service.create(serviceName); 
    service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointUrl); 

    /** Create a Dispatch instance from a service. **/ 
    Dispatch dispatch = service.createDispatch(portName, SOAPMessage.class, 
      Service.Mode.MESSAGE); 

    // The soapActionUri is set here. otherwise we get a error on .net based 
    // services. 
    dispatch.getRequestContext().put(Dispatch.SOAPACTION_USE_PROPERTY, 
      new Boolean(true)); 
    dispatch.getRequestContext().put(Dispatch.SOAPACTION_URI_PROPERTY, 
      SOAPAction); 

    /** Create SOAPMessage request. **/ 
    // compose a request message 
    MessageFactory messageFactory = MessageFactory.newInstance(); 
    SOAPMessage message = messageFactory.createMessage(); 

    // Create objects for the message parts 
    SOAPPart soapPart = message.getSOAPPart(); 
    SOAPEnvelope envelope = soapPart.getEnvelope(); 
    SOAPBody body = envelope.getBody(); 

    SOAPElement bodyElement = body.addChildElement(bean.getInputMethod(), 
      bean.getPrefix(), bean.getTargetNameSpace()); 

      ...more code to form soap body goes here 

    // Print request 
    message.writeTo(System.out); 

    // Save the message 
    message.saveChanges(); 

    response = (SOAPMessage)dispatch.invoke(message); 
    } 
    catch (Exception e) { 
     log.error("Error in invokeSiebelWS :"+e); 
    } 
    return response; 
} 

Si prega di ignorare il parametro WSBean come gli spazi dei nomi e altri attributi WSDL sono provenienti da questo fagiolo. E se questa eccezione può essere risolta con alcune soluzioni alternative, i pls suggeriscono.

+0

è il vostro servizio URI utilizzando un indirizzo IP o un nome host? – Bruno

+0

suo usando l'indirizzo IP. – shashankaholic

risposta

82

Grazie, Bruno per avermi dato l'Head in Common Name e Subject Alternative Name. Come abbiamo capito, il certificato è stato generato con CN con il nome DNS della rete e ha chiesto la rigenerazione del nuovo certificato con la voce Nome alternativo oggetto, ad esempio san = ip: 10.0.0.1. che è la soluzione reale .

Ma, siamo riusciti a trovare una soluzione con la quale siamo in grado di eseguire in fase di sviluppo. Basta aggiungere un blocco statico nella classe da cui stiamo creando la connessione SSL.

static { 
    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() 
     { 
      public boolean verify(String hostname, SSLSession session) 
      { 
       // ip address of the service URL(like.23.28.244.244) 
       if (hostname.equals("23.28.244.244")) 
        return true; 
       return false; 
      } 
     }); 
} 

Se vi capita di essere utilizzando Java 8, c'è un modo molto più impermeabile di ottenere lo stesso risultato:

static { 
    HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> hostname.equals("127.0.0.1")); 
} 
+0

Potrebbe invece essere stato generato un certificato con 'CN = localhost'. – Bruno

+1

OK. C'è ancora un leggero rischio che un MITM possa produrre un certificato con quell'indirizzo IP (dal momento che non stai verificando che corrisponda al certificato che stai cercando). Detto questo, è improbabile che una CA appropriata rilascerà un certificato ad un indirizzo IP. – Bruno

+0

In realtà, questo era un caso di sviluppo dell'organizzazione interna, in cui i ragazzi del server non volevano andare per un certificato CA approvato, né vogliono provare dolore (sarcasmo) per rigenerare il certificato. Quindi, questa piccola modifica che dobbiamo fare nel nostro codice lato client. – shashankaholic

28

A differenza di alcuni browser, Java segue rigorosamente le specifiche HTTPS quando si tratta della verifica dell'identità del server (RFC 2818, Sezione 3.1) e degli indirizzi IP.

Quando si utilizza un nome host, è possibile tornare al Nome comune nel DN oggetto del certificato del server, anziché utilizzare il Nome alternativo oggetto.

Quando si utilizza un indirizzo IP, deve essere presente una voce Nome alternativo oggetto (di tipo indirizzo IP, non nome DNS) nel certificato.

Troverete ulteriori dettagli sulle specifiche e su come generare un tale certificato in this answer.

+0

thnks, lo capisco perché il certificato autofirmato generato sul server utilizza un nome DNS che non corrisponde all'ip che sto colpendo. Ma non c'è nulla che io possa fare al riguardo, dal momento che non è sotto il mio controllo. Ho bisogno di un rimedio che può essere cattivo nella corsa sbagliata, ma almeno per risolvere il mio problema per il momento. – shashankaholic

+3

Se il nome host nel certificato non viene risolto nell'indirizzo, il server è configurato in modo errato. Ciononostante, dovresti essere in grado di modificare la tua risoluzione DNS locale per puntare quel nome a questo indirizzo IP nel tuo file '/ etc/hosts' (se sotto Linux, o il suo equivalente Windows). – Bruno

Problemi correlati