1

我正在针对具有标准 http 和 https 版本的服务编写 gSoap 客户端应用程序。到目前为止,我编写的所有内容都适用于 http 服务,但是当我切换到 https 服务时,突然出现错误。

我对 https 支持的代码所做的唯一更改是在启动时添加以下内容:

 soap_ssl_init();   
 if(soap_ssl_client_context(&_tradeService, SOAP_SSL_SKIP_HOST_CHECK, NULL, NULL, NULL, NULL, NULL)) {
     handleError("Failed to set up SSL connection");
     return;
 }

如果我打开了-DDEBUG标志,我会收到关于证书的错误:“SSL 验证错误或深度 2 的证书警告:证书链中的自签名证书”这不会导致soap_ssl_client_context返回错误,我认为不会很重要,因为在我测试时,我并不真正关心对主机进行身份验证。

真正的问题是这个错误:

SOAP 1.2 错误:SOAP-ENV:Sender [无子代码]“无法处理没有有效动作参数的请求。请提供有效的肥皂动作。”

当我尝试向服务提出请求时得到的。如果查看 gsoap 生成的发送日志,我会在传出标头中看到 SoapAction 参数集。事实上,如果我比较 http/https 服务的发送日志,唯一的区别是安全服务的 url 以 https 为前缀。

然后我想可能是服务器出了问题,所以我使用 curl 发送与 gsoap 记录它发送的完全相同的 XML 数据,并具有完全相同的标头。这很好用,我看到了我期望的数据的正常响应。这让我相信也许我设置的 SSL 不正确?

我遇到的另一个不在文档中的问题是,当我使用-DWITH_OPENSSL -lgsoapssl++ -lssl -lcrypto标志构建时,我仍然收到有关 gsoap 的 ssl 方法的链接器错误。stdsoap2_ssl_cpp.cpp为了解决这些问题,我必须将其包含在我的构建中,我认为这很奇怪。

在此之前有人尝试过这样做可以给我一些指示吗?

4

2 回答 2

0

看起来我们正在同时解决类似的问题。

让我先从这个开始:

我遇到的另一个不在文档中的问题是,当我使用 -DWITH_OPENSSL -lgsoapssl++ -lssl -lcrypto 标志构建时,我仍然收到有关 gsoap 的 ssl 方法的链接器错误。我必须在我的构建中包含 stdsoap2_ssl_cpp.cpp 才能解决这些问题,我认为这很奇怪。

仅供参考:我正在使用 VirtualBox,Ubuntu 14.04。我使用标志--enable-debug--with-openssl=/opt/libraries/openssl/build/1.0.1j 从源代码编译 Gsoap 2.8.21

如您所见,我还从源代码编译了 openssl 以获得libssl.alibcrypto.a档案。此外,我编译了 zlib 以获得libz.a存档。所有这些都到位:

  • 我使用以下命令从 WSDL 生成头文件:

    wsdl2h -v -g -o temporary.h https://something.com?wsdl
    
  • 在生成代理类之前将此行添加到temporary.h:

    #import "wsse.h"
    
  • 使用命令生成的 C++ 代理客户端类:

    soapcpp2 -1 -I/opt/libraries/gsoap/build/2.8.21/share/gsoap/import -C -j temporary.h
    
  • 使用 QT Creator(Plain Project,不幸的是没有 cmake),我的 project.pro 文件看起来像:

    TEMPLATE = app
    CONFIG += console
    CONFIG -= app_bundle
    CONFIG -= qt
    
    QMAKE_CXXFLAGS += -DWITH_OPENSSL
    QMAKE_CXXFLAGS += -DWITH_DOM
    QMAKE_CXXFLAGS += -DDEBUG
    
    QMAKE_CFLAGS += -DWITH_OPENSSL
    QMAKE_CFLAGS += -DWITH_DOM
    QMAKE_CFLAGS += -DDEBUG
    
    SOURCES += main.cpp \
        soapBasicHttpBinding_USCOREIBarcodeWebServiceProxy.cpp \
        soapC.cpp \
        ../../../opt/libraries/gsoap/build/2.8.21/share/gsoap/plugin/wsseapi.cpp \
        ../../../opt/libraries/gsoap/build/2.8.21/share/gsoap/plugin/mecevp.c \
        ../../../opt/libraries/gsoap/build/2.8.21/share/gsoap/plugin/smdevp.c \
    
    HEADERS += \
        BasicHttpBinding_USCOREIBarcodeWebService.nsmap \
        soapBasicHttpBinding_USCOREIBarcodeWebServiceProxy.h \
        soapStub.h \
        soapH.h
    
    include(deployment.pri)
    qtcAddDeployment()
    
    INCLUDEPATH += ../../../opt/libraries/gsoap/build/2.8.21-debug/share/gsoap
    
    unix:!macx: LIBS += -L$$PWD/../../../opt/libraries/gsoap/build/2.8.21-debug/lib/ -lgsoapssl++
    INCLUDEPATH += $$PWD/../../../opt/libraries/gsoap/build/2.8.21-debug/include
    DEPENDPATH += $$PWD/../../../opt/libraries/gsoap/build/2.8.21-debug/include    
    unix:!macx: PRE_TARGETDEPS += $$PWD/../../../opt/libraries/gsoap/build/2.8.21-debug/lib/libgsoapssl++.a
    
    unix:!macx: LIBS += -L$$PWD/../../../opt/libraries/openssl/build/1.0.1j/lib/ -lssl
    INCLUDEPATH += $$PWD/../../../opt/libraries/openssl/build/1.0.1j/include
    DEPENDPATH += $$PWD/../../../opt/libraries/openssl/build/1.0.1j/include
    unix:!macx: PRE_TARGETDEPS += $$PWD/../../../opt/libraries/openssl/build/1.0.1j/lib/libssl.a
    
    unix:!macx: LIBS += -L$$PWD/../../../opt/libraries/openssl/build/1.0.1j/lib/ -lcrypto
    INCLUDEPATH += $$PWD/../../../opt/libraries/openssl/build/1.0.1j/include
    DEPENDPATH += $$PWD/../../../opt/libraries/openssl/build/1.0.1j/include
    unix:!macx: PRE_TARGETDEPS += $$PWD/../../../opt/libraries/openssl/build/1.0.1j/lib/libcrypto.a
    
    unix:!macx: LIBS += -L$$PWD/../../../opt/libraries/zlib/build/1.2.8/lib/ -lz
    INCLUDEPATH += $$PWD/../../../opt/libraries/zlib/build/1.2.8/include
    DEPENDPATH += $$PWD/../../../opt/libraries/zlib/build/1.2.8/include
    unix:!macx: PRE_TARGETDEPS += $$PWD/../../../opt/libraries/zlib/build/1.2.8/lib/libz.a
    
    LIBS += -ldl
    

现在回答您的第一部分问题,我认为以下指南应该可以解决您当前面临的问题:

仅供参考:在 main.cpp 文件中,我包括:

#include <iostream>
#include "BasicHttpBinding_USCOREIBarcodeWebService.nsmap"
#include "soapBasicHttpBinding_USCOREIBarcodeWebServiceProxy.h"
#include "soapStub.h"
#include "soapH.h"
#include "plugin/wsseapi.h"

后来在我添加的文件中:

// creating empty soap struct with SOAP_IO_FLUSH
soap *soap = soap_new();
// setting flags: SOAP_SSL_REQUIRE_SERVER_AUTHENTICATION | SOAP_TLSv1
soap->ssl_flags = SOAP_SSL_DEFAULT;
// registering plugin
soap_register_plugin(soap, soap_wsse);
// file with CA certs of peers (downloaded https://www.cs.fsu.edu/~engelen/cacerts.pem.zip)
soap->cafile = "cacerts.pem";
// I placed cacerts.pem file in the same folder where your program executable will be created

因此,回到您的案例,我认为在您使用soap_ssl_client_context的方法中,其中一个参数还负责设置cacerts.pem位置。

如果这仍然不起作用,您始终可以将 ssl_flags 设置为SOAP_SSL_NO_AUTHENTICATION

不知道这样能不能解决这个问题:

SOAP 1.2 错误:SOAP-ENV:Sender [无子代码]“无法处理没有有效动作参数的请求。请提供有效的肥皂动作。”

但是,可能存在从 gsoap 插件附加正确文件的情况。我正在使用 SOAP 1.1 并禁用为 SOAP 1.2 生成代理客户端类。

无论如何,我期待着你的回应。希望我可以在第一次与 Gsoap 打交道时帮助您并节省很多挫败感 :)

于 2015-01-12T19:08:01.343 回答
0

如果我打开 -DDEBUG 标志,我会收到关于证书的错误:“SSL 验证错误或使用深度 2 的证书发出警告:证书链中的自签名证书”这不会导致 soap_ssl_client_context 返回错误,而我没有t 认为这是一件大事,因为当我测试时,我并不真正关心验证主机。

-DDEBUG当您删除以供生产使用时,此错误可能不会消失。您可以通过添加验证回调来接受自签名证书:

soap->fsslverify = verify_callback;

int ssl_verify_callback(int ok, X509_STORE_CTX *store)
{
  if (!ok)
  {
    int err = X509_STORE_CTX_get_error(store);
    switch (err)
    {
      case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
        X509_STORE_CTX_set_error(store, X509_V_OK);
        ok = 1;
        break;
    }
  }
  return ok;
}

SOAP 1.2 错误:SOAP-ENV:Sender [无子代码]“无法处理没有有效动作参数的请求。请提供有效的肥皂动作。”

HTTP/S 标头中可能缺少 SOAP 操作,或者由于某种原因不正确。此 SOAP 操作应在 WSDL 中定义,并且特定于调用的每个服务操作。

要在 HTTP/S 标头中设置 SOAP Action 参数,请确保在进行调用时传递 NULL 或 SOAP Action 字符串作为第三个参数:

soap_call_SomeMethod(soap, "endpoint URL", "SOAP Action string", ...);

当您传递 NULL 时,将使用 WSDL 中定义的 SOAP Action 字符串。检查 wsdl2h 生成的代码,了解服务操作用作 SOAP 操作的内容。gSOAP 服务并不真正需要 SOAP 操作,但其他服务(例如 WCF)会向您抛出错误。

当使用 C++ 代理对象时,上面的调用被一个简单的方法调用代替:

proxy.SomeMethod("endpoint URL", "SOAP Action string", ...);

如果要使用 WSDL 定义的端点和 SOAP 操作,则省略这些参数:

proxy.SomeMethod(...);

就这样。

于 2017-07-05T21:04:26.343 回答