13

概要: 私は.NET 4.0 WCFクライアントで作業しており、SOAP1.1とWS-Security1.0を使用してWebサービス(DataPower、もう一方の端ではJavaサービス)を利用しています。WCFクライアントは、トランスポート層での相互認証用のクライアント証明書を実装する必要があります。メッセージ本文は、別のサービス/署名証明書を使用して署名する必要があります。また、SOAPヘッダーには、パスワードダイジェストを含むユーザー名トークンが含まれ、NonceタグとCreatedタグが含まれている必要があります。

BasicHTTPBindingでWSE3.0を使用して、このWebサービスを利用できます。しかし、私はこれまで、WSHttpBindingまたはCustomBindingのいずれかを使用してWCFで同じものを実装することに成功していません。私はすべてのセキュリティバインディング要素を試しましたが、今のところ運がありません。

ここからusernametokenライブラリ(http://blogs.msdn.com/b/aszego/archive/2010/06/24/usernametoken-profile-vs-wcf.aspx)も使用しているので、パスワードダイジェスト/nonceを追加できます。 /SOAPヘッダーのUsernameTokenに作成されます。

私は現在SecurityBindingElement.CreateMutualCertificateBindingElementを使用しています。AsymmetricSecurityBindingElement、TransportSecurityBindingElementなどの他のいくつかも試しました(以下のコードでコメント化されています)

CERTS: クライアント証明書とサービス証明書の両方をMMCを使用して証明書ストアにロードしています(私はWindows 7を使用しています)。クライアント証明書とサービス証明書の両方に秘密鍵があります。両方のPFXファイルをLocalMachine/Personal、LocalMachine / Root、およびLocalMachine/TrustedPeopleにロードしました。また、FindPrivateKey / ICACLSを実行して、「IISアプリプール/DefaultAppPool」アカウントにアクセス許可を付与しました。自分のマシンからWSE3.0コードを実行でき、証明書の問題なしで動作するため、これは問題にはなりません。

コマンドの実行:

FindPrivateKey.exe My LocalMachine -t "thumbprint of client cert"
FindPrivateKey.exe My LocalMachine -t "thumbprint of service cert"
icacls C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\{privateKeyOfClientCert} /grant "IIS AppPool\DefaultAppPool":R      <<Successfully processed 1 files; Failed processing 0 files>>
icacls C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\{privateKeyOfServiceCert} /grant "IIS AppPool\DefaultAppPool":R     <<Successfully processed 1 files; Failed processing 0 files>>

WCFの問題: 現在、DataPowerゲートウェイから「権限'xxcom'でSSL/TLSのセキュリティで保護されたチャネルを確立できませんでした」というメッセージが表示されます。これは、ゲートウェイがサービス証明書を取得し、送信しているクライアント証明書を使用する代わりに、それをクライアント認証に使用していることが原因である可能性があります。これは、エンドポイントのDNS IDを指定しないと、ゲートウェイがDNSIDが「{サービスのサブジェクト名/署名証明書}」であることを期待しているというメッセージが返されるためです。

上記のエラーを発生させているWCFによって生成されたSOAPリクエストは次のとおりです。WCF SOAP要求は、WSESOAP要求と非常によく似ています。上記のエラーは、SSL/トランスポート層での証明書の問題が原因で発生している可能性があります。

WCF SOAP要求:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
    <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        <u:Timestamp u:Id="uuid-8533d9a5-865e-4a4b-a750-fadb7c1ce36c-1">
            <u:Created>2013-02-06T20:53:04.679Z</u:Created>
            <u:Expires>2013-02-06T20:58:04.679Z</u:Expires>
        </u:Timestamp>
        <o:BinarySecurityToken u:Id="uuid-0bab08ce-3e3b-4360-a44b-694b06a3dd67-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">Removed Service Cert Encoded Value</o:BinarySecurityToken>
        <wsse:UsernameToken wsu:Id="7843ab92-f69a-4d00-a5ba-117e32a74f49" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                            xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsse:Username>USER_Removed</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">XXX=</wsse:Password>
            <wsse:Nonce>XXX==</wsse:Nonce>
            <wsu:Created>2013-02-06T20:53:04Z</wsu:Created>
        </wsse:UsernameToken>
        <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SignedInfo>
                <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod>
                <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
                <Reference URI="#_1">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
                    <DigestValue>XXX=</DigestValue>
                </Reference>
                <Reference URI="#uuid-8533d9a5-865e-4a4b-a750-fadb7c1ce36c-1">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
                    <DigestValue>XXX=</DigestValue>
                </Reference>
                <Reference URI="#7843ab92-f69a-4d00-a5ba-117e32a74f49">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
                    <DigestValue>XXX=</DigestValue>
                </Reference>
            </SignedInfo>
            <SignatureValue>XXXLongXXX=</SignatureValue>
            <KeyInfo>
                <o:SecurityTokenReference>
                    <o:Reference URI="#uuid-0bab08ce-3e3b-4360-a44b-694b06a3dd67-2"></o:Reference>
                </o:SecurityTokenReference>
            </KeyInfo>
        </Signature>
    </o:Security>
</s:Header>
<s:Body u:Id="_1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <ping xmlns="https://x.x.com/xxx/v1">
        <pingRequest xmlns="">hello</pingRequest>
    </ping>
</s:Body>

WSE 3.0 SOAPリクエスト(これは機能します):

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
           xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<soap:Header>
    <wsa:Action wsu:Id="Id-4271fb72-464a-467d-ab1f-4d32542e20f0"/>
    <wsa:MessageID wsu:Id="Id-11657f64-d856-47d8-b600-d5379fb91a0d">urn:uuid:ff8becb7-74c2-4844-ab46-8ae23f1355a7</wsa:MessageID>
    <wsa:ReplyTo wsu:Id="Id-40b2e6e8-e67b-4a6c-a545-071ce0f0107a">
        <wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
    </wsa:ReplyTo>
    <wsa:To wsu:Id="Id-d5e0b488-6f8a-479c-940d-2b85833dbc66">https://x.x.com/xxx/v1</wsa:To>
    <wsse:Security soap:mustUnderstand="1">
        <wsu:Timestamp wsu:Id="Timestamp-68476551-5c58-4a47-967b-54ec18257b1b">
            <wsu:Created>2013-02-06T19:38:39Z</wsu:Created>
            <wsu:Expires>2013-02-06T19:43:39Z</wsu:Expires>
        </wsu:Timestamp>
        <wsse:UsernameToken wsu:Id="SecurityToken-e5f65166-a825-48cb-a939-8e515a637e01">
            <wsse:Username>USER_Removed</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">XXX=</wsse:Password>
            <wsse:Nonce>XXX==</wsse:Nonce>
            <wsu:Created>2013-02-06T19:38:39Z</wsu:Created>
        </wsse:UsernameToken>
        <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SignedInfo>
                <ds:CanonicalizationMethod xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                <Reference URI="#Id-4271fb72-464a-467d-ab1f-4d32542e20f0">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue>XXX=</DigestValue>
                </Reference>
                <Reference URI="#Id-11657f64-d856-47d8-b600-d5379fb91a0d">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue>XXX=</DigestValue>
                </Reference>
                <Reference URI="#Id-40b2e6e8-e67b-4a6c-a545-071ce0f0107a">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue>XXX=</DigestValue>
                </Reference>
                <Reference URI="#Id-d5e0b488-6f8a-479c-940d-2b85833dbc66">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue>XXX=</DigestValue>
                </Reference>
                <Reference URI="#Timestamp-68476551-5c58-4a47-967b-54ec18257b1b">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue>XXX=</DigestValue>
                </Reference>
                <Reference URI="#Id-6f76e50e-932c-4878-bbc0-3ef4c8a36990">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue>XXX=</DigestValue>
                </Reference>
            </SignedInfo>
            <SignatureValue>XXXLongXXX=</SignatureValue>
            <KeyInfo>
                <wsse:SecurityTokenReference>
                    <wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier"
                                        EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">XXX=</wsse:KeyIdentifier>
                </wsse:SecurityTokenReference>
            </KeyInfo>
        </Signature>
    </wsse:Security>
</soap:Header>
<soap:Body wsu:Id="Id-6f76e50e-932c-4878-bbc0-3ef4c8a36990">
    <ping xmlns="https://x.x.com/xxx/v1">
        <pingRequest xmlns="">hello</pingRequest>
    </ping>
</soap:Body>

これがすべての設定です。私が間違っていることを教えてください!

WCF web.config:コードですべての構成を行っているため、web.configからすべてを削除しました。

コード内のWCF構成:

var proxy = GetProxy();
pingResponseMessage resp = proxy.ping("hello");
lblStatus.Text = resp.status.ToString();

private XXXClient GetProxy()
{

    System.Net.ServicePointManager.ServerCertificateValidationCallback += (se, cert, chain, sslerror) => { return true; };

    XXXClient proxy = new XXXClient(GetCustomBinding(), new EndpointAddress(new Uri("https://xxx"), EndpointIdentity.CreateDnsIdentity("I am forced to put the signing cert subject here, nothing else works"), new AddressHeaderCollection()));

    proxy.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
    proxy.Endpoint.Behaviors.Add(new UsernameClientCredentials(new UsernameInfo(@"USER_Removed", "X")));

    proxy.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "REMOVED");
    proxy.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "REMOVED");
    proxy.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;

    return proxy;
}

private Binding GetCustomBinding()
{
    //TransportSecurityBindingElement secBE = SecurityBindingElement.CreateCertificateOverTransportBindingElement(MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10);
    //AsymmetricSecurityBindingElement secBE = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
    //secBE.InitiatorTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient, RequireDerivedKeys = false, X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier };
    //secBE.RecipientTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.AlwaysToInitiator, RequireDerivedKeys = false, X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier };
    //secBE.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
    //secBE.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters() { InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient, RequireDerivedKeys = false });
    //secBE.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters(X509KeyIdentifierClauseType.SubjectKeyIdentifier, SecurityTokenInclusionMode.Never) { InclusionMode = SecurityTokenInclusionMode.Never, RequireDerivedKeys = false, X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier });
    //secBE.ProtectionTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient };
    //secBE.DefaultAlgorithmSuite = new CustomSecurityAlgorithm();

    SecurityBindingElement secBE = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
    secBE.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
    secBE.EndpointSupportingTokenParameters.Signed.Add(new UsernameTokenParameters() { InclusionMode= SecurityTokenInclusionMode.AlwaysToRecipient, ReferenceStyle = SecurityTokenReferenceStyle.External, RequireDerivedKeys = false });
    secBE.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
    //secBE.AllowInsecureTransport = false;
    //secBE.AllowSerializedSigningTokenOnReply = false;
    secBE.EnableUnsecuredResponse = true;
   secBE.IncludeTimestamp = true;
    secBE.SetKeyDerivation(false);

    TextMessageEncodingBindingElement textEncBE = new TextMessageEncodingBindingElement(MessageVersion.Soap11, System.Text.Encoding.UTF8);

    HttpsTransportBindingElement httpsBE = new HttpsTransportBindingElement();
    httpsBE.RequireClientCertificate = true;
    //httpsBindingElement.AllowCookies = false;
    //httpsBindingElement.AuthenticationScheme = System.Net.AuthenticationSchemes.Basic;
    httpsBE.BypassProxyOnLocal = false;
    httpsBE.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
    //httpsBindingElement.KeepAliveEnabled = false;
    httpsBE.TransferMode = TransferMode.Buffered;
    httpsBE.UseDefaultWebProxy = true;

    CustomBinding myBinding = new CustomBinding();
    myBinding.Elements.Add(secBE);
    myBinding.Elements.Add(textEncBE);
    myBinding.Elements.Add(httpsBE);

    return myBinding;
}

メッセージ本文に署名するだけでよいので、ServiceContractとOperationContractsにProtectionLevel.Signを追加しました。私はまだそれを確認するためにここまで得ていません。

[System.ServiceModel.ServiceContractAttribute(Namespace = "https://x.x.com/xxx/v1", ConfigurationName = "x.x", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)]
public interface XXXService {
    [System.ServiceModel.OperationContractAttribute(Action = "", ReplyAction = "*", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)]
    [System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
    [return: System.ServiceModel.MessageParameterAttribute(Name="return")]
    XXX.pingResponse ping(XXX.ping request);

[System.ServiceModel.ServiceContractAttribute(Namespace = "https://x.x.com/xxx/v1", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)]
public partial class XXXClient : System.ServiceModel.ClientBase<XXXService> {
    [System.ServiceModel.OperationContractAttribute(Action = "", ReplyAction = "*", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)]
    public XXX.pingResponseMessage ping(string pingRequest) {

以下をweb.configに追加して、piiデータを含むsoap全体のログを記録できるようにしました。

(for pii, also added <machineSettings enableLoggingKnownPii="true" /> under <system.serviceModel> to C:\Windows\Microsoft.NET\Framework\vX\CONFIG\machine.config)

<system.serviceModel>
<diagnostics>
  <messageLogging logKnownPii="true" logEntireMessage="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" maxMessagesToLog="3000"/>
</diagnostics>
</system.serviceModel>
<system.diagnostics>
<sources>
  <source name="System.ServiceModel.MessageLogging" logKnownPii="true">
    <listeners>
      <add initializeData="C:\trace.log" type="System.Diagnostics.XmlWriterTraceListener" name="messages"/>
    </listeners>
  </source>
</sources>
</system.diagnostics>

===============

WSE 3.0(動作する構成とコード): web.config:

<system.serviceModel>
<bindings>
  <basicHttpBinding>
    <binding name="myBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
      <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
      <security mode="Transport">
        <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
        <message clientCredentialType="UserName" algorithmSuite="Default"/>
      </security>
    </binding>
  </basicHttpBinding>
</bindings>
<client>
  <endpoint address="https://x.x.com/xxx/v1" binding="basicHttpBinding" bindingConfiguration="myBinding" contract="XXXService" name="XXX"/>
</client>
</system.serviceModel>
<appSettings>
<add key="XXXImplService" value="https://x.x.com/xxx/v1"/>
</appSettings>

...およびWSE3コード:

var proxy = new XXXImplServiceWse();

UsernameToken usernameToken = new UsernameToken(@"USER_Removed", "X");
proxy.RequestSoapContext.Security.Tokens.Add(usernameToken);

X509Certificate2 mutualCert = LoadCertFromStore(StoreLocation.LocalMachine, StoreName.My, "Client Cert Subject Name");
proxy.ClientCertificates.Add(mutualCert);

X509Certificate2 signCert = LoadCertFromStore(StoreLocation.LocalMachine, StoreName.My, "Service Cert Subject Name");

X509SecurityToken signatureToken = new X509SecurityToken(signCert);

MessageSignature signature = new MessageSignature(signatureToken); // <!-- IS THIS SAME AS THIS STEP IN WCF: secBE.EndpointSupportingTokenParameters.Signed.Add(new UsernameTokenParameters()) -->

proxy.RequestSoapContext.Security.Elements.Add(signature);

==========

では、上記のWSE 3.0コードをWCFに変換するにはどうすればよいですか?

4

2 に答える 2

7

問題を解決し、次のWCF CustomBinding(CertificateOverTransport)とCustomCredentials(パスワードダイジェスト付きのUsernameToken、トランスポート認証用のクライアント証明書、メッセージ本文署名用のサービス証明書)を使用してDataPower(IBM Xi50)Webサービスゲートウェイに接続できました。何が問題を正確に修正したかはわかりませんが、これが私の動作するWCFコードです!これが私と同じような状況にある他の人たちに役立つことを願っています。

DataPowerXi50ゲートウェイもWCF用に構成されていることを確認してください。IBMから:「SSLでBasicHttpBindingを使用する場合:disable-ssl-cipher-checkパラメーターを使用して、TransportBindingアサーションの暗号チェックを無効にすることができます。基本認証ヘッダーは、Webサービスプロキシではデフォルトでサポートされていません。 WCFと相互運用するには、WWW-Authenticateヘッダーを挿入するためのエラー時ルールが必要です。」詳細については、https ://publib.boulder.ibm.com/infocenter/ieduasst/v1r1m0/index.jsp?topic = / com.ibm.iea.wdatapower / wdatapower / 1.0 / xa35 / 380DataPowerWCFIntegration/player.htmlにアクセスしてください。 。

メッセージ本文のみに署名する(暗号化しない)場合は、ProtectionLevel.Signをサービスコントラクトに設定していることを確認してください。

以前に問題があったDNSIDの場合、クライアント証明書のサブジェクト名を入力できるようになりました。以前はこれは機能しませんでした。

web.configに設定がありません。

CustomBindingを使用したプロキシは次のとおりです。

private ClientProxy GetProxy()
{
    XXXServiceClient proxy = new XXXServiceClient(GetCustomBinding(), new EndpointAddress(new Uri("<<GatewayURLHere>>"), EndpointIdentity.CreateDnsIdentity("<<DNS or Client Cert Subject Name>>"), new AddressHeaderCollection()));
    proxy.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
    proxy.Endpoint.Behaviors.Add(new CustomCredentials(<clientCertHere>, <signingCertHere>));
    proxy.ClientCredentials.UserName.UserName = @"XXX";
    proxy.ClientCredentials.UserName.Password = "yyy";
    return proxy;
}

private Binding GetCustomBinding()
{
    TransportSecurityBindingElement secBE = SecurityBindingElement.CreateCertificateOverTransportBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
    secBE.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.Never, RequireDerivedKeys = false });
    secBE.EnableUnsecuredResponse = true;
    secBE.IncludeTimestamp = true;
    TextMessageEncodingBindingElement textEncBE = new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressingAugust2004, System.Text.Encoding.UTF8);
    HttpsTransportBindingElement httpsBE = new HttpsTransportBindingElement();
    httpsBE.RequireClientCertificate = true;

    CustomBinding myBinding = new CustomBinding();
    myBinding.Elements.Add(secBE);
    myBinding.Elements.Add(textEncBE);
    myBinding.Elements.Add(httpsBE);

    return myBinding;
}

これが、上記のUsernameTokenライブラリを含む複数のソースから集めたCustomCredentialsクラスです-トランスポート層での(相互?)認証用のクライアント証明書、メッセージ本文に署名するためのサービス/署名証明書、およびSOAPのパスワードダイジェストを使用したUsernameTokenを設定しますヘッダ:

using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Security;
using System.Text;

namespace XXX_WCF
{
    public class CustomCredentials : ClientCredentials
    {
        private X509Certificate2 clientAuthCert;
        private X509Certificate2 clientSigningCert;

        public CustomCredentials() : base() { }

        public CustomCredentials(CustomCredentials other)
            : base(other)
        {
            clientSigningCert = other.clientSigningCert;
            clientAuthCert = other.clientAuthCert;
        }

        protected override ClientCredentials CloneCore()
        {
            CustomCredentials scc = new CustomCredentials(this);
            return scc;
        }

        public CustomCredentials(X509Certificate2 ClientAuthCert, X509Certificate2 ClientSigningCert)
            : base()
        {
            clientAuthCert = ClientAuthCert;
            clientSigningCert = ClientSigningCert;
        }

        public X509Certificate2 ClientAuthCert
        {
            get { return clientAuthCert; }
            set { clientAuthCert = value; }
        }

        public X509Certificate2 ClientSigningCert
        {
            get { return clientSigningCert; }
            set { clientSigningCert = value; }
        }

        public override SecurityTokenManager CreateSecurityTokenManager()
        {
            return new CustomTokenManager(this);
        }
    }

    public class CustomTokenManager : ClientCredentialsSecurityTokenManager
    {
        private CustomCredentials custCreds;

        public CustomTokenManager(CustomCredentials CustCreds)
            : base(CustCreds)
        {
            custCreds = CustCreds;
        }

        public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
        {
            if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate)
            {
                x509CustomSecurityTokenProvider prov;
                object temp = null;
                TransportSecurityBindingElement secBE = null;

                if (tokenRequirement.Properties.TryGetValue("http://schemas.microsoft.com/ws/2006/05/servicemodel/securitytokenrequirement/SecurityBindingElement", out temp))
                {
                    secBE = (TransportSecurityBindingElement)temp;
                }

                if (secBE == null)
                    prov = new x509CustomSecurityTokenProvider(custCreds.ClientAuthCert);
                else
                    prov = new x509CustomSecurityTokenProvider(custCreds.ClientSigningCert);
                return prov;
            }

            return base.CreateSecurityTokenProvider(tokenRequirement);
        }

        public override System.IdentityModel.Selectors.SecurityTokenSerializer CreateSecurityTokenSerializer(System.IdentityModel.Selectors.SecurityTokenVersion version)
        {
            return new CustomTokenSerializer(System.ServiceModel.Security.SecurityVersion.WSSecurity10);
        }
    }

    class x509CustomSecurityTokenProvider : SecurityTokenProvider
    {
        private X509Certificate2 clientCert;

        public x509CustomSecurityTokenProvider(X509Certificate2 cert)
            : base()
        {
            clientCert = cert;
        }

        protected override SecurityToken GetTokenCore(TimeSpan timeout)
        {
            return new X509SecurityToken(clientCert);
        }
    }

    public class CustomTokenSerializer : WSSecurityTokenSerializer
    {
        public CustomTokenSerializer(SecurityVersion sv) : base(sv) { }

        protected override void WriteTokenCore(System.Xml.XmlWriter writer, System.IdentityModel.Tokens.SecurityToken token)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }
            if (token == null)
            {
                throw new ArgumentNullException("token");
            }

            if (token.GetType() == new UserNameSecurityToken("x", "y").GetType())
            {
                UserNameSecurityToken userToken = token as UserNameSecurityToken;

                if (userToken == null)
                {
                    throw new ArgumentNullException("userToken: " + token.ToString());
                }

                string tokennamespace = "o";

                DateTime created = DateTime.Now;
                string createdStr = created.ToString("yyyy-MM-ddThh:mm:ss.fffZ");
                string phrase = Guid.NewGuid().ToString();
                string nonce = GetSHA1String(phrase);
                string password = GetSHA1String(nonce + createdStr + userToken.Password);
                //string password = userToken.Password;

                writer.WriteStartElement(tokennamespace, "UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
                writer.WriteAttributeString("u", "Id", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", token.Id);
                writer.WriteElementString(tokennamespace, "Username", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", userToken.UserName);
                writer.WriteStartElement(tokennamespace, "Password", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
                writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest");
                writer.WriteValue(password);
                writer.WriteEndElement();
                writer.WriteStartElement(tokennamespace, "Nonce", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
                writer.WriteAttributeString("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
                writer.WriteValue(nonce);
                writer.WriteEndElement();
                writer.WriteElementString(tokennamespace, "Created", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", createdStr);
                writer.WriteEndElement();
                writer.Flush();
            }
            else
            {
                base.WriteTokenCore(writer, token);
            }
        }

        protected string GetSHA1String(string phrase)
        {
            SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
            byte[] hashedDataBytes = sha1Hasher.ComputeHash(Encoding.UTF8.GetBytes(phrase));
            return Convert.ToBase64String(hashedDataBytes);
        }
    }//CustomTokenSerializer
}

幸運を!

于 2013-02-11T22:07:59.850 に答える
3

私はあなたのコードを調べました、そしてそれは正しいように見えます。WSEとWCFのSOAPメッセージにはわずかな違いがありますが、違いは、メッセージの署名に使用される証明書の参照方法のみです。

ここでの中心的な問題は、証明書の誤った使用法だと思います。トランスポートとメッセージの相互セキュリティの両方を使用しています。理論的には、これには4つの証明書が必要です。あなたが必要です

  • トランスポートセキュリティのサービス証明書-この証明書は、SSL接続を構築するためにサーバーによって使用されます。接続を正常に構築するには、クライアントは証明書を信頼する必要があります(証明書を発行した機関を信頼するか、サーバー証明書を信頼できる人のストアに配置する必要があります)。
  • トランスポートセキュリティ用のクライアント証明書-この証明書は、トランスポートレベルでサーバー上のクライアントを認証するために使用されます-個人ストアに証明書とその秘密鍵が必要です
  • メッセージセキュリティのサービス証明書-この証明書は、要求の暗号化と応答の署名(WS-Security 1.0の場合)に使用されます。この証明書は、マシンのどこかにある必要があります(証明書のロードに使用される場所はあなた次第です)。
  • メッセージセキュリティ用のクライアント証明書-この証明書は、応答の暗号化と要求への署名(WS-Security 1.0の場合)に使用されます。この証明書とその秘密鍵をマシンのどこかに持っている必要があります(証明書のロードに使用される場所はあなた次第です)。

証明書は2つしかないようです。1つはクライアント、もう1つはサーバーです。このような場合、トランスポートとメッセージの両方のセキュリティに使用する必要があります。しかし、ここで興味深い問題が発生します。WSEの例のクライアント側の「署名」証明書は、実際にはサービス証明書です。それが実際に当てはまる場合、それはクライアントがサーバーの秘密鍵にアクセスできる必要があることを意味します-それは決して起こらないはずです。これは、PKIインフラストラクチャの最悪の違反です。PKIインフラストラクチャは、認証局への信頼と、各参加者が他の誰もアクセスできない独自の秘密鍵を持っている秘密鍵の保護に基づいています。秘密鍵を共有すると、セキュリティが低下します。最悪の場合、秘密鍵にアクセスできる人は誰でもメッセージの通信や偽の署名を傍受する可能性があるため、セキュリティがまったくないことになります。

私が正しければ、WSE 3.0を使用して、それに満足する必要があります。WCFにHTTPSとメッセージセキュリティに異なるクライアント証明書を使用させるだけでは、非常に困難な場合があります。プロパティは1つClientCertificateですが、HTTPSとメッセージセキュリティのために別の証明書をロードする必要があります。ClientCredentials2つのプロパティを持つカスタムを作成し、正しい証明書プロバイダーを返すためのカスタムを作成する必要がありSecurityTokenManagerます(使用法ごとに実装することによって(これは理論です-私は試したことがありません)。

ところで。問題EndpointIdentityは、サービスが何らかのDNSで公開されているという事実に基づいており、サービス証明書のサブジェクト(この場合は署名証明書でもあります)が異なる場合は、エンドポイントの新しいDNSIDを作成する必要があります。そうしないと、WCFは証明書を信頼しません。サーバー証明書は、サーバーへのアクセスに使用されるDNS名と一致するサブジェクトを使用して発行する必要があります。

于 2013-02-10T18:38:01.513 に答える