2

概述

因此,我一直在努力尝试在托管在云服务(使用 webrole)上的 WCF 服务和 Salesforce 标注之间创建相互(2 路)SSL 连接。我正在创建一个大型问题来概述我已采取的所有步骤以及我目前遇到的问题。

过程/进展

1:在 Azure 云服务上设置 SSL(成功)

  • 创建了将 SSL 域(service.mydomain.com)指向 Azure 生产端点(service.cloudapp.net)的CNAME
  • 已将签名证书上传到 Azure
  • 向 WebRole 添加证书并使用证书配置 Https Endpoint
  • 使用 Security Mode="Transport" 创建了 WCF web.config 绑定

执行此操作后,单向 SSL 工作正常

2:使用 Salesforce 创建客户端证书。这是 salesforce 颁发的未签名证书。您可以将其下载为 .cer(完成)

3:使用启动任务安装 Salesforce 客户端证书(请参阅本文)(完成,但我不确定如何确认它确实有效,除了部署时没有引发错误)

4:设置 WCF 以要求客户端证书(完成,请参阅 web.config)

5:使用 WebRole 中的启动任务和 WCF web.config 中的覆盖设置解锁 VM IIS webserver/security/access/sslflags(完成,请参阅 startup.cmd 和 web.config)

显然,对于云服务,启动任务将在虚拟机上实际配置 IIS 之前运行。因此,我不得不使用 ping 来实现 hack 以延迟并在后台运行。这实际上似乎与我收到500-Configuration Error之前一样有效。

6:在SF请求中发送客户端证书(DONE,见SF代码)

结果: 我从服务器收到 403.7 - Forbidden 错误。我相信这与服务不信任 SF 证书有关,但我可以肯定。由于系统的云到云性质,显然几乎不可能进行测试。

更新

因此,我能够通过将商店从“root”更改为“ca”来解决 403.7 错误。但是现在我正在处理一个不一致的问题,有时 start.cmd 似乎可以工作,而其他时候它似乎没有任何或仅部分效果。如果我重新启动我的服务,它会在 500 个错误之间循环,因为配置标志被 IIS 锁定,上面提到的 403.7 错误,它实际上运行良好。

我发现这篇博客文章使用自定义程序 (ExecWithRetries.exe) 来延迟并重试启动任务,直到它们成功完成,但我仍然没有得到不一致的结果(可能是因为 appcmd 即使它在 IIS 之前运行也可能不会抛出错误由VM配置?)。

我的startup.cmd现在看起来像:

%windir%\System32\inetsrv\appcmd.exe unlock config /section:system.webServer/security/access
REM certutil -addstore -enterprise -f -v root Startup\MagnetClient.cer
certutil -addstore ca Startup\MagnetClient.cer

任务配置如下:

<startup>
   <Task commandLine="Startup/ExecWithRetries.exe &quot;/c:AddCert.cmd&quot; /d:60000 /r:20 /rd:5000" executionContext="elevated" taskType="background" />
</startup>

如果有人能找到获得一致结果的解决方案,我将奖励他们。

代码参考

WCF web.config

<configuration>
  <system.web>
    <customErrors mode="Off"></customErrors>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="WCFServiceWebRole1.Service1" behaviorConfiguration="metadata" >
        <endpoint name="basicHttp"  
                  binding="basicHttpBinding" 
                  bindingConfiguration="https" 
                  contract="WCFServiceWebRole1.IService1" >

        </endpoint>
      </service>
    </services>
    <bindings>
      <basicHttpBinding>
        <binding name="https">
          <!-- Step 1 -->
          <security mode="Transport">
            <!-- step 4 -->
            <transport clientCredentialType="Certificate" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="metadata">
          <serviceMetadata httpsGetEnabled="true"  />
          <!--<serviceDebug includeExceptionDetailInFaults="true"/>-->
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>

    <httpErrors errorMode="Detailed"/>
    <asp scriptErrorSentToBrowser="true" />

    <modules runAllManagedModulesForAllRequests="true"/>
    <!-- Override iis config mentioned in step 5 -->
    <security>
      <access sslFlags="SslRequireCert"/>
    </security>
  </system.webServer>
</configuration>

Web角色服务定义

<ServiceDefinition name="WindowsAzureProject1" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2013-03.2.0">
  <WebRole name="WCFServiceWebRole1">
    <!-- step 3 & 5 -->
    <Startup>
      <Task commandLine="Startup/startup.cmd" executionContext="elevated" taskType="background">
      </Task>
    </Startup>
    <Sites>
      <Site name="Web">
        <Bindings>
          <Binding name="Endpoint1" endpointName="Endpoint1" />
          <Binding name="Endpoint2" endpointName="Endpoint2" />
        </Bindings>
      </Site>
    </Sites>
    <Endpoints>
      <InputEndpoint name="Endpoint1" protocol="http" port="80" />
      <!-- step 1 -->
      <InputEndpoint name="Endpoint2" protocol="https" port="443" certificate="example.example.com" />
    </Endpoints>
    <Imports>
      <Import moduleName="Diagnostics" />
    </Imports>
    <LocalResources>
      <LocalStorage name="WCFServiceWebRole1.svclog" sizeInMB="1000" cleanOnRoleRecycle="false" />
    </LocalResources>
    <Certificates>
      <!-- Step 1 -->
      <Certificate name="example.example.com" storeLocation="LocalMachine" storeName="My" />
      <Certificate name="Go Daddy Secure Certification Authority" storeLocation="LocalMachine" storeName="Trust" />
      <Certificate name="Go Daddy Class 2 Certification Authority" storeLocation="LocalMachine" storeName="Trust" />
    </Certificates>
    <ConfigurationSettings>
    </ConfigurationSettings>
  </WebRole>
</ServiceDefinition>

启动.cmd

REM *HACK to wait a ridiculously long time until we can be
REM *pretty sure the VM has initialized IIS
ping -n 600 127.0.0.1 nul
%windir%\System32\inetsrv\appcmd.exe unlock config /section:system.webServer/security/access
REM add SF client certy to root store
certutil -addstore -enterprise -f -v root Statup\ClientCert.cer

销售人员示例代码

string b = '';
b = b + '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body>';
b = b + '<TestService xmlns="http://tempuri.org/">';
b = b + '<echoString>test Message</echoString>';
b = b + '</TestService></s:Body></s:Envelope>';

Http h = new Http();
HttpRequest req = new HttpRequest();
//this should add the certificate created by salesforce
req.setClientCertificateName('MyClientCert');
req.setMethod('POST');
req.setEndpoint('https://service.mydomain.com/service1.svc');
req.setHeader('Content-type','text/xml');
req.setHeader('SoapAction', 'http://tempuri.org/IService1/TestService');
req.setBody( b );
HttpResponse res = h.send(req);
string m = res.getbody();

System.Debug(m);
4

2 回答 2

1

我将提供几个建议:

  1. 为您的 Azure 部署启用 RemoteAccess并重新部署。然后登录并 MMC 到 Cert 商店以查看 SalesForce 客户端证书是否实际安装。
  2. <Runtime executionContext="elevated" />在您的服务配置中添加<WebRole name="WCFServiceWebRole1">(请参阅我对此SO Post的回答)以确保工作进程可以访问证书存储。
于 2013-08-15T23:44:32.077 回答
1

注意:延迟的可靠方法是使用 CHOICE 命令:

:: Delay for 60 seconds

%windir%\System32\choice.exe /D Y /T 60 > NUL:

要捕获命令的输出,将错误和标准输出重定向到一个文件,您可以访问:

certutil -addstore ca Startup\sfdc-client.cert.cer 2>&1 >> %temp%\AddCerts.out

2> 告诉控制台捕获“ERROUT”句柄

&1 将该输出绑定到 STDOUT 句柄

>> 将 STDOUT 句柄附加到文件

于 2015-07-29T02:17:27.630 回答