57

Java コードを使用して HTTPS SOAP Web サービスを呼び出しています。jre cacerts キーストアに自己署名証明書を既にインポートしています。今私は得ています:

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

サービス URL のホスト名が、証明書で提供された CN のホスト名と一致しません。カスタム ホスト名ベリファイアを定義する回避策については、こちらを参照してください。しかし、コードで回避策を実装する必要がある場所を作成することはできません。

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

名前空間およびその他の wsdl 属性はこの Bean から取得されるため、WSBean パラメータは無視してください。この例外がいくつかの異なる回避策で解決できる場合は、pls が提案します。

4

2 に答える 2

92

共通名とサブジェクトの別名について教えてくれてありがとう、ブルーノ。ネットワークの DNS 名を持つ CN を使用して証明書が生成され、サブジェクトの別名エントリ (san=ip:10.0.0.1) を使用して新しい証明書の再生成を要求したことがわかりました。これが実際の解決策です。

しかし、開発段階で実行できる回避策を見つけることができました。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;
            }
        });
}

たまたま Java 8 を使用している場合は、同じ結果を達成するためのよりスマートな方法があります。

static {
    HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> hostname.equals("127.0.0.1"));
}
于 2012-04-24T10:52:51.530 に答える
32

一部のブラウザーとは異なり、Java は、サーバー ID の検証 (RFC 2818、セクション 3.1) および IP アドレスに関しては、HTTPS 仕様に厳密に従います。

ホスト名を使用する場合、サブジェクトの別名を使用する代わりに、サーバー証明書のサブジェクト DN の共通名にフォールバックすることができます。

IP アドレスを使用する場合は、証明書に Subject Alternative Name エントリ (DNS 名ではなく IP アドレス タイプ) が必要です。

仕様とそのような証明書を生成する方法の詳細については、この回答を参照してください。

于 2012-04-22T20:15:50.450 に答える