概要
そのため、クラウド サービス (Web ロールを使用) でホストされている WCF サービスと Salesforce コールアウトとの間の相互 (双方向) SSL 接続を作成するために、炎上するフープを飛び越えてきました。私が行ったすべての手順と現在行き詰まっている場所を概説するために、巨大な質問を作成しています。
プロセス/進捗
1: Azure Cloud Service で SSL を設定する (成功)
- SSL ドメイン(service.mydomain.com)を Azure 運用エンドポイント(service.cloudapp.net)にポイントするCNAMEを作成しました。
- 署名済み証明書を Azure にアップロードしました
- 証明書を WebRole に追加し、証明書を使用して Https エンドポイントを構成しました
- 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 を参照)。
どうやらクラウド サービスでは、VM で IIS が実際に構成される前に、スタートアップ タスクが実行されるようです。このため、ping を使用して遅延させ、バックグラウンドで実行するハックを実装する必要がありました。これは実際には500 - Configuration Errorが発生する前と同じように機能しているようです。
6: クライアント証明書を SF リクエストで送信 (完了、SF コードを参照)
結果: サーバーから 403.7 - Forbidden エラーが表示されます。SF証明書がサービスによって信頼されていないことに関係があると思いますが、確信できます. システムのクラウドからクラウドへの性質のため、テストすることは明らかにほぼ不可能です。
アップデート
そのため、ストアを「root」から「ca」に変更することで、403.7 エラーを解決できました。ただし、現在、start.cmd が機能しているように見える場合もあれば、まったく効果がないか、部分的な効果しかないように見える場合もあるという矛盾の問題に対処しています。サービスを再起動すると、IIS によってロックされている構成フラグの 500 エラー、上記の 403.7 エラーが繰り返され、実際には完全に機能します。
カスタム プログラム (ExecWithRetries.exe) を使用してスタートアップ タスクを遅延させ、正常に完了するまで再試行しているこのブログ記事を見つけましたが、それでも一貫性のない結果が得られません (おそらく、IIS の前に実行された場合でも appcmd がエラーをスローしない可能性があるためです)。 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 "/c:AddCert.cmd" /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>
スタートアップ.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);