Azure Cloud Service和Salesforce之间的相互(双向)SSL

时间:2013-08-06 16:57:04

标签: azure ssl salesforce ssl-certificate

概述

所以我一直在试图在云服务托管的WCF服务(使用webrole)和Salesforce标注之间创建一个Mutual(双向)SSL连接。我正在创建一个大问题来概述我所采取的所有步骤以及我目前所处的位置。

过程/进展

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

  • 创建 CNAME ,将SSL域(service.mydomain.com)指向azure生产端点(service.cloudapp.net)
  • 将已签名的证书上载到Azure
  • 将证书添加到WebRole并使用证书
  • 配置了Https端点
  • 使用安全模式=“传输”
  • 创建了WCF web.config绑定

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

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

3:使用启动任务(see this article)安装Salesforce客户端证书(完成,但我不确定如何确认它确实有效,除了没有引发错误的事实部署)

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

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

显然,对于云服务,启动任务将在VM实际配置IIS之前运行。因此,我不得不使用ping实现一个hack来延迟并在后台运行。这实际上似乎与我之前的 500 - 配置错误

一样

6:在SF请求中发送客户端证书(完成,请参阅SF代码)

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

更新

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

我发现这个blog post使用自定义程序(ExecWithRetries.exe)来延迟和重试启动任务,直到它们成功完成,但我仍然没有得到不一致的结果(可能是因为appcmd可能不会引发错误即使它在VM配置IIS之前运行了吗?)。

我的 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>

WebRole服务定义

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

STARTUP.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);

2 个答案:

答案 0 :(得分:1)

我会提出一些建议:

  1. Enable RemoteAccess到您的azure部署并重新部署。然后登录并将MMC发送到Cert存储,以查看是否实际安装了SalesForce客户端证书。
  2. 在服务配置<Runtime executionContext="elevated" />之后添加<WebRole name="WCFServiceWebRole1">(请参阅我对此SO Post的回答),以确保工作进程可以访问证书存储区。

答案 1 :(得分:1)

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

TestHelper.handleCreate('task-local');

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

:: Delay for 60 seconds

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

2&gt;告诉控制台捕获“ERROUT”句柄

&amp; 1将输出绑定到STDOUT句柄

&gt;&gt;将STDOUT句柄附加到文件