我正在针对具有标准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:证书链中的自签名证书”,这不会导致{{1}返回错误,我认为这不是一个大问题,因为我在测试时并不真正关心验证主机。
真正的问题是这个错误:
当我尝试向服务提出请求时,我得到了SOAP 1.2错误:SOAP-ENV:发件人[没有 子代码]“无法处理请求 没有有效的动作参数。 请提供有效的肥皂行动。“
。如果我查看gsoap生成的发送日志,我会看到传出标头中设置的SoapAction参数。事实上,如果我比较http / https服务的发送日志,唯一的区别是安全服务的网址以https为前缀。
然后我想也许有些东西搞砸了服务器,所以我使用curl发送与gsoap记录的完全相同的XML数据,并使用完全相同的标头。这工作正常,我看到我期望的数据的正常响应。这让我相信也许我错误地设置了SSL?
我遇到的另一个问题不是在文档中,当我使用soap_ssl_client_context
标记构建时,我仍然遇到关于gsoap的ssl方法的链接器错误。我必须在我的构建中包含-DWITH_OPENSSL -lgsoapssl++ -lssl -lcrypto
以便解决这些问题,我认为这很奇怪。
之前有人试过这样做可以给我一些指示吗?
答案 0 :(得分: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.a 和 libcrypto.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:发件人[无子代码]&#34;无法处理请求 没有有效的动作参数。请提供有效的肥皂活动。&#34;
但是可能存在从gsoap插件附加正确文件的情况。我正在使用SOAP 1.1并禁用为SOAP 1.2生成代理客户端类。
无论如何,我期待你的回应。希望我能帮助你一点,并在第一次与Gsoap交易时节省很多挫折:)
答案 1 :(得分:0)
如果我打开了-DDEBUG标志,则会收到有关证书的错误:&#34; SSL验证错误或警告,证书深度为2:证书链中的自签名证书&#34;哪个不会导致soap_ssl_client_context返回错误,我认为这不是一个大问题,因为在我测试时我并不真正关心验证主机。
删除-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:发件人[无子代码]&#34;无法处理没有有效操作参数的请求。请提供有效的肥皂活动。&#34;
HTTP / S标头中可能缺少SOAP操作,或者由于某种原因导致SOAP操作不正确。此SOAP Action应在WSDL中定义,并且特定于调用的每个服务操作。
要在HTTP / S标头中设置SOAP Action参数,请确保在进行调用时将NULL或SOAP Action字符串作为第三个参数传递:
soap_call_SomeMethod(soap, "endpoint URL", "SOAP Action string", ...);
传递NULL时,将使用WSDL中定义的SOAP Action字符串。检查wsdl2h生成的代码,了解服务操作用作SOAP Action的内容。使用gSOAP服务并不需要SOAP Action,但其他服务例如WCF会向您抛出错误。
使用C ++代理对象时,上面的调用将被简单的方法调用替换:
proxy.SomeMethod("endpoint URL", "SOAP Action string", ...);
如果要使用WSDL定义的端点和SOAP操作,请省略以下参数:
proxy.SomeMethod(...);
这就是全部。