gsoap wcf https

客户端采用Gsoap 2.8.15 ,服务端WCF / web service

实现基于https 的web service通信,有完整代码配置(我的资源下载)


1. gsoap-2.8.15\gsoap\samples\ssl 下面是Gsoap自带完整例子,基本解决问题

客户端用户名密码校验:

	soap_ssl_init();
	soap_init(&soap);
	soap.userid = "michael";
	soap.passwd = "gaga";
	int result = soap_ssl_client_context(&soap,
	  /* SOAP_SSL_NO_AUTHENTICATION, */ /* for encryption w/o authentication */
	  /* SOAP_SSL_DEFAULT | SOAP_SSL_SKIP_HOST_CHECK, */	/* if we don't want the host name checks since these will change from machine to machine */
	  SOAP_SSL_NO_AUTHENTICATION,	/* use SOAP_SSL_DEFAULT in production code */
	  NULL, 		/* keyfile (cert+key): required only when client must authenticate to server (see SSL docs to create this file) */
	  NULL, 		/* password to read the keyfile */
	  NULL,	/* optional cacert file to store trusted certificates, use cacerts.pem for all public certificates issued by common CAs */
	  NULL,		/* optional capath to directory with trusted certificates */
	  NULL		/* if randfile!=NULL: use a file with random data to seed randomness */
	);
客户端证书校验:

	soap_ssl_init();
	soap_init(&soap);
	int result = soap_ssl_client_context(&soap,
	  /* SOAP_SSL_NO_AUTHENTICATION, */ /* for encryption w/o authentication */
	  /* SOAP_SSL_DEFAULT | SOAP_SSL_SKIP_HOST_CHECK, */	/* if we don't want the host name checks since these will change from machine to machine */
	  SOAP_SSL_REQUIRE_SERVER_AUTHENTICATION|SOAP_SSL_SKIP_HOST_CHECK,	/* use SOAP_SSL_DEFAULT in production code */
	  "client.pem", 		/* keyfile (cert+key): required only when client must authenticate to server (see SSL docs to create this file) */
	  "123456", 		/* password to read the keyfile */
	  "cacert.pem",	/* optional cacert file to store trusted certificates, use cacerts.pem for all public certificates issued by common CAs */
	  NULL,		/* optional capath to directory with trusted certificates */
	  NULL		/* if randfile!=NULL: use a file with random data to seed randomness */
	);

证书校验的时候,修改stdsoap2.c::ssl_verify_callback,直接返回1:(因为客户端发起https时,服务器首先返回自己证书和公钥,ssl_verify_callback选择是否信任,不信任的话立即导致失败)

ssl_verify_callback(int ok, X509_STORE_CTX *store)
{
#ifdef SOAP_DEBUG
  if (!ok)
  { char buf[1024];
    int err = X509_STORE_CTX_get_error(store);
    X509 *cert = X509_STORE_CTX_get_current_cert(store);
    fprintf(stderr, "SSL verify error or warning with certificate at depth %d: %s\n", X509_STORE_CTX_get_error_depth(store), X509_verify_cert_error_string(err));
    X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
    fprintf(stderr, "certificate issuer %s\n", buf);
    X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
    fprintf(stderr, "certificate subject %s\n", buf);
    /* accept self signed certificates and certificates out of date */
    switch (err)
    { case X509_V_ERR_CERT_NOT_YET_VALID:
      case X509_V_ERR_CERT_HAS_EXPIRED:
      case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
      case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
        X509_STORE_CTX_set_error(store, X509_V_OK);
        ok = 1;
    }
  }
#endif
  /* Note: return 1 to continue, but unsafe progress will be terminated by OpenSSL */
  return 1;
}

补充soap.header, Action to

	memset(wsa5__Action, 0, sizeof(wsa5__Action));
	sprintf_s(wsa5__Action, 250, "%s%s", "http://tempuri.org/INMSServiceSSLV1/", funcname);

	header->wsa5__MessageID = wsa5__MessageID;
	header->wsa5__To = wsa5__To;
	header->wsa5__Action = wsa5__Action;
利用Gsoap / vs 生成代码:

:: vs 环境
call "D:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat
:: get wsdl
wsdl2h -s -c -o NMSServiceSSLV1.h http://localhost:19996/NMSServiceV1/?wsdl
::copy /b thewsdl.h+test.h NMSServiceSSLV1.h
:: change -I path
soapcpp2 -c -L -x NMSServiceSSLV1.h -I../../../;../../../import


编译客户端需要openssl,下载OpenSSL-Win32,这里使用的是1.1.0g

http://slproweb.com/products/Win32OpenSSL.html

将OpenSSL-Win32\include 加入包含目录,将OpenSSL-Win32\lib加入库目录,window下面还要将libcrypto.lib/libssl.lib/libcrypto.lib等作为依赖库

WITH_OPENSSL加入编译选项

#define M_ASN1_STRING_data(x)   ((x)->data)

2. 服务器端服务非常简单

    [ServiceContract]
    interface INMSServiceSSLV1
    {
        [OperationContract]
        int Add(int a, int b);
    }
    public class NMSServiceSSLV1 : INMSServiceSSLV1
    {
		public int Add(int a, int b)
        {
            return a+b;
        }
    }
用户名密码app.config:

<?xml version="1.0"?>
<configuration>
  <system.net>
    <settings>
      <httpWebRequest useUnsafeHeaderParsing="true"/>
    </settings>
  </system.net>
  <system.runtime.remoting>
    <application>
      <channels>
        <channel ref="http" clientConnectionLimit="500">
          <clientProviders>
            <formatter ref="soap"/>
          </clientProviders>
        </channel>
        <channel ref="tcp" clientConnectionLimit="500">
          <clientProviders>
            <formatter ref="soap"/>
          </clientProviders>
        </channel>
      </channels>
    </application>
  </system.runtime.remoting>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="sslBehavior">
          <!--不提供通过浏览器输入https访问元数据的方式,必要时候关闭之-->
          <serviceMetadata httpsGetEnabled="true" httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
          <!--服务器端提供证书-->
          <serviceCredentials>
            <clientCertificate>
              <authentication certificateValidationMode="None"/>
            </clientCertificate>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="SSLSoap.CustomIdentityVerification,SSLSoap"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <wsHttpBinding>
        <binding name="has_security">
          <security mode="Transport">
            <!--采用传输安全,客户端凭证=Basic-->
            <transport clientCredentialType="Basic"/>
            <message clientCredentialType="None"/>
          </security>
        </binding>
        <binding name="no_security">
          <security mode="None">
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>

    <services>
      <service name="SSLSoap.NMSServiceSSLV1" behaviorConfiguration="sslBehavior">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="has_security" contract="SSLSoap.INMSServiceSSLV1"/>
        <endpoint address="mexs" binding="mexHttpsBinding" contract="IMetadataExchange"/>
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="no_security" contract="SSLSoap.INMSServiceSSLV1"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <host>
          <baseAddresses>
            <!--基地址是https-->
            <add baseAddress="https://localhost:9996/NMSServiceSSLV1/"/>
            <!--基地址是http-->
            <add baseAddress="http://localhost:19996/NMSServiceV1/"/>            
          </baseAddresses>
        </host>
      </service>
    </services>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="false"/>
  </system.serviceModel>
</configuration>

证书app.config:

<?xml version="1.0"?>
<configuration>
  <system.net>
    <settings>
      <httpWebRequest useUnsafeHeaderParsing="true"/>
    </settings>
  </system.net>
  <system.runtime.remoting>
    <application>
      <channels>
        <channel ref="http" clientConnectionLimit="500">
          <clientProviders>
            <formatter ref="soap"/>
          </clientProviders>
        </channel>
        <channel ref="tcp" clientConnectionLimit="500">
          <clientProviders>
            <formatter ref="soap"/>
          </clientProviders>
        </channel>
      </channels>
    </application>
  </system.runtime.remoting>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="sslBehavior">
          <!--不提供通过浏览器输入https访问元数据的方式-->
          <serviceMetadata httpsGetEnabled="true" httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
          <!--服务器端提供证书-->
          <serviceCredentials>
            <serviceCertificate storeName="My" x509FindType="FindBySubjectName" findValue="michael-xj" storeLocation="LocalMachine"/>
            <clientCertificate>
              <!--SSLSoap.CustomCertificateVerification,SSLSoap ,后面是程序集名称-->
              <authentication certificateValidationMode="Custom"  customCertificateValidatorType="SSLSoap.CustomCertificateVerification,SSLSoap"/>
            </clientCertificate>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <wsHttpBinding>
        <binding name="has_security">
          <security mode="Transport">
            <!--采用传输安全,客户端凭证=Basic-->
            <transport clientCredentialType="Certificate"/>
            <message clientCredentialType="None"/>
          </security>
        </binding>
        <binding name="no_security">
          <security mode="None">
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>

    <services>
      <service name="SSLSoap.NMSServiceSSLV1" behaviorConfiguration="sslBehavior">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="has_security" contract="SSLSoap.INMSServiceSSLV1"/>
        <endpoint address="mexs" binding="mexHttpsBinding" contract="IMetadataExchange"/>
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="no_security" contract="SSLSoap.INMSServiceSSLV1"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <host>
          <baseAddresses>
            <!--基地址是https-->
            <add baseAddress="https://localhost:9996/NMSServiceSSLV1/"/>
            <!--基地址是http-->
            <add baseAddress="http://localhost:19996/NMSServiceV1/"/>            
          </baseAddresses>
        </host>
      </service>
    </services>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="false"/>
  </system.serviceModel>
</configuration>


3. 证书、证书端口绑定

以管理员权限运行cmd,制作测试证书

:: 创建根证书CA
:: .pvk 私钥文件;.cer 公钥文件 .pem base64编码秘钥 
makecert -n "CN=test" -r -sv testSSL.pvk testSSL.cer
makecert -n "CN=svr-test" -ic testSSL.cer -iv testSSL.pvk -sr LocalMachine -ss My -pe -sky exchange
:: 创建客户端证书
Makecert -n "CN=cli-test" -ic testSSL.cer -iv testSSL.pvk -sr CurrentUser -ss My -pe -sky exchange
:: 证书端口绑定,管理员权限
netsh 
http add sslcert ipport=0.0.0.0:9996 certhash=‎8a7741422a335160171f7656d7f277c1b84fd188 appid={af01c789-ce96-43c1-9789-4e0a9ab11dd0}
::Save encoded certificate to store failed => 0x5 (5) Failed,以管理员权限运行
mmc查看证书时将证书导出,然后用openssl命令将证书转换为pem等格式,用于客户端gsoap提交证书

:: pfx -> pem
openssl pkcs12 -in client.pfx -nodes -out client.pem
:: cer -> pem
openssl x509 -inform der -in certificate.cer -out certificate.pem

4. FAQ

::FAQ:
Could not establish trust relationship for the SSL/TLS secure channel with authority 'localhost:9996'.
ServicePointManager.ServerCertificateValidationCallback += RemoteCertificateValidate;

:: ssl_verify_callback / return 1 / 校验服务器返回证书
SOAP 1.2 fault: SOAP-ENV:Sender [no subcode]
"SSL_ERROR_SSL
error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed"
Detail: SSL_connect error in tcp_connect()

:: SSL_get_verify_result failed / SOAP_SSL_NO_AUTHENTICATION
SOAP 1.2 fault: SOAP-ENV:Sender [no subcode]
"unsupported certificate purpose"
Detail: SSL/TLS certificate presented by peer cannot be verified in tcp_connect()

:: 填充SOAP_ENV__Header
SOAP 1.2 fault: SOAP-ENV:Sender [wsa5:DestinationUnreachable]
"The message with To '' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher.  Check that the sender and receiver's EndpointAddresses agree."
Detail: [no detail]

:: wsHttpBinding <-> basicHttpBinding 相互修正
Detail: HTTP/1.1 415 Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'.
Detail: HTTP/1.1 415 Cannot process the message because the content type 'application/soap+xml; charset=utf-8; action=""' was not the expected type 'text/xml; charset=utf-8'.

:: 检查客户端是否校验不通过,异常!
Error 403 fault: SOAP-ENV:Server [no subcode]
"HTTP Error"
Detail: HTTP/1.1 403 Forbidden

The HTTP request was forbidden with client authentication scheme 'Basic'.

:: netsh -> http add sslcert
:: 端口没有证书
SOAP 1.2 fault: SOAP-ENV:Sender [no subcode]
"Error observed by underlying BIO: No error"
Detail: SSL_connect error in tcp_connect()

An error occurred while making the HTTP request to https://192.168.1.5:9996/NMSServiceSSLV1/. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.






  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
gSOAP是一个用于开发基于SOAP(Simple Object Access Protocol)的Web服务的工具包。它最初是为C和C++开发的,但也提供了Python的绑定。 要在Python中使用gSOAP,您需要执行以下步骤: 1. 安装gSOAP:首先,您需要从gSOAP的官方网站下载并安装gSOAP工具包。根据您的操作系统,选择合适的版本进行安装。 2. 生成SOAP客户端和服务器代码:使用gSOAP工具包提供的命令行工具,根据您的Web服务定义(通常是使用WSDL描述的),生成相应的SOAP客户端和服务器代码。例如,可以使用`soapcpp2`命令生成C++代码,然后使用`wsdl2h`和`soapcpp2`命令生成C和C++代码。 3. 使用Python绑定:gSOAP提供了Python绑定,使您可以在Python中使用SOAP客户端和服务器。您可以使用`swig`工具为生成的C或C++代码生成Python绑定。然后,将生成的绑定文件编译为Python模块。 4. 开发和使用Python代码:一旦您完成了上述步骤,您就可以在Python中编写代码来使用gSOAP生成的SOAP客户端和服务器。您可以调用相应的函数来执行SOAP调用和处理返回结果。 需要注意的是,使用gSOAP进行Python开发需要一些额外的工作,并且涉及到多个步骤。因此,在决定使用gSOAP之前,建议先评估您的项目需求,以确定是否真正需要使用SOAP和gSOAP。在许多情况下,使用更简单的RESTful API或其他Web服务技术可能更加合适和方便。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值