web-dev-qa-db-fra.com

SSLHandshakeException: aucun autre nom de sujet n'est présent

J'appelle HTTPS SOAP le service Web via Java. J'ai déjà importé un certificat auto-signé dans le magasin de clés jre cacerts. Maintenant, je reçois:

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

Le nom d'hôte de l'URL de service ne correspond pas à celui du CN fourni dans cert. J'ai lu des informations sur une solution de contournement consistant à définir un vérificateur de nom d'hôte personnalisé ici . Mais je ne peux pas faire où je devrais implémenter la solution de contournement dans mon code.

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;
}

Veuillez ignorer le paramètre WSBean car les espaces de noms et autres attributs wsdl proviennent de ce bean. Et si cette exception peut être résolue avec des solutions de contournement différentes, les pls le suggèrent.

56
shashankaholic

Merci, Bruno de m'avoir prévenu sur le nom commun et le nom alternatif du sujet. Comme nous l’avons découvert, le certificat a été généré avec CN avec le nom DNS du réseau et il a été demandé de régénérer un nouveau certificat avec l’entrée Autre nom du sujet, c.-à-d. San = ip: 10.0.0.1. qui est le solution actuelle.

Mais nous avons réussi à trouver une solution de contournement avec laquelle nous pouvons fonctionner en phase de développement. Ajoutez simplement un bloc statique dans la classe à partir de laquelle nous établissons une connexion 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;
            }
        });
}

Si vous utilisez Java 8, il existe un moyen beaucoup plus simple d’atteindre le même résultat:

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

Contrairement à certains navigateurs, Java suit strictement les spécifications HTTPS en ce qui concerne la vérification de l'identité du serveur (RFC 2818, Section 3.1) et les adresses IP.

Lorsque vous utilisez un nom d'hôte, il est possible de revenir au nom commun dans le DN du sujet du certificat de serveur, au lieu d'utiliser le nom alternatif du sujet.

Lors de l'utilisation d'une adresse IP, le certificat doit contenir une entrée de nom d'objet secondaire (de type adresse IP, pas de nom DNS).

Vous trouverez plus de détails sur la spécification et comment générer un tel certificat dans cette réponse .

31
Bruno