2011-01-12 12 views
5

これはWeb上の最初の質問です。それが意味をなさないことを願っています。WCFサービスからJava WebサービスへのX.509証明書を使用してSOAPメッセージに署名する

私はこの問題に関連するブログをウェブ上で見てきましたが、私はそれらの中で提示されたアイデアのいくつかを成功させずに試しました。ここに私の状況です:

私はWebアプリケーションを呼び出してJava Webサービスを呼び出すWebアプリケーションを持っています。それらはすべて異なるサーバーにあります。 Java WebサービスへのWCF Webサービス間の呼び出しは、証明書が呼び出し元を識別するのに十分であるため、httpsを超えていません(したがって、メッセージセキュリティ)。

  • のJava Webサービス(ブラックボックス)

は、Java Webサービスは、署名されたメッセージを受信する必要があり、以下の通り動作する:
各要求が処理される前に、ハンドラはすべての着信メッセージを傍受
1.メッセージにセキュリティーヘッダーが含まれていますか
2.メッセージに正しいセキュリティヘッダーIDが含まれていますか

6.有効な証明書(有効期限が切れていないですベースの設定 - 10 3.メッセージが
4.メッセージがキー情報509
5.信頼されたCAから発行された証明書された証明書が含まれています正しく署名されてです
7.証明書に正しいポリシーが含まれていますか。

これらの手順がすべて完了したら、メッセージを処理できます。手順が失敗すると、SOAPメッセージ例外が返されます。

SOAPセキュリティヘッダーは、xxx ... w3.org/TR/SOAP-dsig/デジタル署名の仕様に対して検証する必要があります。

最も完全な説明は、xxx ... ibm.com/developerworks/webservices/library/ws-security.htmlこのIBMの記事では、各WS-Securityヘッダーの詳細とサンプル署名付きSOAPメッセージが提供されている。

SOAPメッセージに署名するときは、メッセージKeyInfoにx.509証明書を追加する必要があります。これは、証明書の検証に必要です。私は私のWCFのWebインストール1つのサーバ証明書(信頼できるCAからp7bフォーマット)を持っている

<?xml version="1.0" encoding="UTF-8"?> 
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> 
<S:Header> 
<ds:Signature xmlns:ds="xxx...w3.org/2000/09/xmldsig#" Id="Signature001"> 
<ds:SignedInfo> 
<ds:CanonicalizationMethod Algorithm="xxx...w3.org/TR/2001/REC-xml-c14n-20010315"/> 
<ds:SignatureMethod Algorithm="xxx...w3.org/2000/09/xmldsig#rsa-sha1"/> 
<ds:Reference URI=""> 
<ds:Transforms> 
<ds:Transform Algorithm="xxx...w3.org/2000/09/xmldsig#enveloped-signature"/> 
</ds:Transforms> 
<ds:DigestMethod Algorithm="xxx...w3.org/2000/09/xmldsig#sha1"/> 
<ds:DigestValue>soe1PnaGXVGrsauC61JSHD+uqGw=</ds:DigestValue> 
</ds:Reference> 
<ds:Reference URI="#KeyInfo001"> 
<ds:DigestMethod Algorithm="xxx...w3.org/2000/09/xmldsig#sha1"/> 
<ds:DigestValue>Y9SRPQ9TcDu+GazO3LFwodEdhaA=</ds:DigestValue> 
</ds:Reference> 
</ds:SignedInfo> 
<ds:SignatureValue>jBX/8XkY2aCte7qgXEp1sbNWmQcK/90iVL58sAvwYAEcBABGzOk2agxR0HvWrNa6ixkocAQ205lggwOxnxZJvoVozVYAAjcLtayPBOUYrnSEBFrwKWP/vxgvUDRIdXeIuw5GLY87NrTQMm1Ehf/HvMX9hTBJn4Nm8RdDiUmPcIo=</ds:SignatureValue> 
<ds:KeyInfo Id="KeyInfo001"> 
<ds:X509Data> 
<ds:X509Certificate>MIIEbZCCA1WgAwIBAgIES1XpMjANBgkqhkiG9w0BAQUFADBYMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxFzAVBgoJkiaJk/IsZAEZFgdlbnRydXN0MRIwEAYDVQQDEwllbnRydXN0U00xEjAQBgNVBAMTCWVudHJ1c3RDQTAeFw0xMDA0MjIxMDQ4MDBaFw0xMzA0MjIxMTE4MDBaMGoxFTATBgoJkiaJk/IsZAEZFgVsb2NhbDEXMBUGCgmSJomT8ixkARkWB2VudHJ1c3QxEjAQBgNVBAMTCWVudHJ1c3RTTTESMBAGA1UEAxMJZW50cnVzdENBMRAwDgYDVQQDEwdSYnMgUmJzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMf88L2JjLPG1hNmTA/KBiC53WVwS2WU9Jh3lC1Rob6RMzOojomZ/dNrvSRB6nzWeXJpZXwik4XFrsAq24By2SZpLTO4p8Vcq71mTAfDu33cnO49Au2pwNvcMn5qIKBk1Xx+oVb4fzK9ncTRu7bW46HsIYth+qkGhbI2JEHwr/zwIDAQABo4IBrzCCAaswCwYDVR0PBAQDAgeAMCsGA1UdEAQkMCKADzIwMTAwNDIyMTA0ODAwWoEPMjAxMjA1MjgxNTE4MDBaMCMGA1UdIAQcMBowCwYJYIZIAYb6awoEMAsGCSqGSIb2fQdLAzAbBgNVHQkEFDASMBAGCSqGSIb2fQdEHTEDAgEBMIHGBgNVHR8Egb4wgbswb6BtoGukaTBnMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxFzAVBgoJkiaJk/IsZAEZFgdlbnRydXN0MRIwEAYDVQQDEwllbnRydXN0U00xEjAQBgNVBAMTCWVudHJ1c3RDQTENMAsGA1UEAxMEQ1JMMTBIoEagRIZCZmlsZTovLy8vTVNJREhVLTQ0NUE0RkVFL0NSTC9lbnRydXN0Y2FfZW50cnVzdHNtX2xvY2FsX2NybGZpbGUuY3JsMB8GA1UdIwQYMBaAFBvSL6cPz8L5shubV58yf0pczKzuMB0GA1UdDgQWBBT1/j6OSS8FTjwqluvew16sv7h+VzAJBgNVHRMEAjAAMBkGCSqGSIb2fQdBAAQMMAobBFY4LjADAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQBXxRIA4HUvGSw4L+4uaR51pY4ISjUQWo2Fh7FYBMt29NsKCTdur1OWVVdndt1yjXP4yWXxoAhHtvZL+XNALUFlR2HAWiXuL1nRcxHkB98N5gPqQzW/lJk9cLtL4hVp28EiEpgmKT3I3NP2Pdb2G5MMOdvQ/GFb2y6OwblR8ViPQ8B2aHWzXMrH+0qadPAuBhXyAohwb+mMuYT/ms6xpGi1NMYuYMf6XONz9GkZgnGnMwa+9CCQws1HNz8WYHtmFIxLsVuEWc/0a1vg4IYX1Ds/ttyhJGTVXOSJSkBz8kRyj1pNBDdc1KeG8M++O8m8VgRTJvYaPc7NMiclISukGpea</ds:X509Certificate> </ds:X509Data> 
</ds:KeyInfo> 
</ds:Signature> 
</S:Header> 
<S:Body Id="ABC"> 
<ns2:createUser xmlns:ns2="http://webservice.rbs.emea.ps.entrust.com/" xmlns:ns3="http://webservice.rbs.emea.ps.entrust.com/types/CertificateException" xmlns:ns4="http://webservice.rbs.emea.ps.entrust.com/types/UserException"> 
<userID>0061020051</userID> 
</ns2:createUser> 
</S:Body> 
</S:Envelope> 
  • WCF Webサービス

SOAPリクエストはこれを好きなはずです(証明書がTrusted Publishersにある瞬間)、mmc証明書スナップインを使用することです。私は応答が明確に(署名も暗号化もされていない)必要があるので、私はJavaサーバー上に別の証明書が必要だとは思わない。私はまだこの証明書と一般的な証明書で混乱していますが、公開鍵だけを保持しているようです。

ここにアプリがあります。私のテストプロジェクトの設定:私は簡単なテスト実行

<client> 
    <endpoint address="http://entrust-user-certification-uat.fm.rbsgrp.net/rbs/WebAS" 
    behaviorConfiguration="endpointCredentialsBehavior" binding="wsHttpBinding" 
    bindingConfiguration="WebAsServicePortTypeBinding" contract="IWebAsServicePortType" 
    name="WebAsServicePortType"> 
    <!--<identity> 
     <dns value="entrust-user-certification-uat.fm.rbsgrp.net" /> 
    </identity>--> 
    </endpoint> 
</client> 
<bindings> 
    <wsHttpBinding> 
    <binding name="WebAsServicePortTypeBinding" closeTimeout="00:01:00" 
     openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" 
     bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" 
     maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" 
     textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false"> 
     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 
     maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
     <security mode="Message"> 
     <message clientCredentialType="Certificate" negotiateServiceCredential="false" 
      establishSecurityContext="false" /> 
     </security> 
    </binding> 
    </wsHttpBinding> 
</bindings> 

<behaviors> 
    <endpointBehaviors> 
    <behavior name="endpointCredentialsBehavior"> 
     <clientCredentials> 
     <clientCertificate findValue="entrust-user-certification-uat.fm.rbsgrp.net" 
      storeLocation="LocalMachine" storeName="TrustedPublisher" 
      x509FindType="FindBySubjectName"></clientCertificate> 
     <serviceCertificate> 
      <!-- 
      Setting the certificateValidationMode to PeerOrChainTrust means that if the certificate 
      is in the user's Trusted People store, then it will be trusted without performing a 
      validation of the certificate's issuer chain. This setting is used here for convenience so that the 
      sample can be run without having to have certificates issued by a certificate authority (CA). 
      This setting is less secure than the default, ChainTrust. The security implications of this 
      setting should be carefully considered before using PeerOrChainTrust in production code. 
      --> 
      <authentication certificateValidationMode="None" revocationMode="NoCheck" trustedStoreLocation="LocalMachine"/> 
     </serviceCertificate> 
     </clientCredentials> 
    </behavior> 
    </endpointBehaviors> 
</behaviors> 


          WebASとentrustService =新しいWebASとを();
          ActivationCodes certCodes = entrustService.createUser( "testNomad");          
に失敗しました::System.Web.Services.Protocols.SoapException: javax.xml.soap.SOAPException:
は私が持っているエラーsoapメッセージが見つかりませんSignature要素を

どのようにできました私は各メッセージの署名プロセスを強制しますか?私はWCFの設定を非常に簡単に行うことができると思っていました。どんな助けでも大歓迎です!

+0

こんにちはNomadefv、 どのようにして、IClientMessageInspector/BeforeSendRequesでリクエストにあなた返されたXML文字列を挿入できますか? AJR –

+1

申し訳ありません。週の最後のカップルからちょっと離れた。あなたは試すことができます: – Nomadefv

+0

'公共オブジェクトBeforeSendRequest(ref System.ServiceModel.Channels.Message request、System.ServiceModel。IClientChannel channel) '{// ...セキュリティ設定から異なるvarを取得 ' //証明書ストアから証明書を読み込みます。 'X509Certificate2 cert = GetCertificateBySubject(certificateSubjectName、certificateStoreName、certificateStoreLocation); '//リクエストに署名する ' string signedSoapMessage = SignRequest(request.ToString()、cert、signatureId、keyInfoRefId、bodyId); – Nomadefv

答えて

14

OK。いくつかの試行とエラーの後、ここではSignedXmlとIClientMessageInspector/BeforeSendRequestパターンを使用したソリューションがあります。彼の関連する提案については、Yaron Navehにありがとうございました。

// Sign an XML request and return it 
public static string SignRequest(string request, string SubjectName, string Signature, string keyInfoRefId) 
{ 
    if (string.IsNullOrEmpty(request)) 
     throw new ArgumentNullException("request"); 
    if (string.IsNullOrEmpty(SubjectName)) 
     throw new ArgumentNullException("SubjectName"); 

    // Load the certificate from the certificate store. 
    X509Certificate2 cert = GetCertificateBySubject(SubjectName); 

    // Create a new XML document. 
    XmlDocument doc = new XmlDocument(); 

    // Format the document to ignore white spaces. 
    doc.PreserveWhitespace = false; 

    // Load the passed XML 
    doc.LoadXml(request); 

    // Add the declaration as per Entrust sample provided -don't think it's necessary though 
    if (!(doc.FirstChild is XmlDeclaration)) 
    { 
     XmlDeclaration declaration = doc.CreateXmlDeclaration("1.0", "UTF-8", string.Empty); 
     doc.InsertBefore(declaration, doc.FirstChild); 
    } 

    // Remove the Action (MustUnderstand). 
    // TODO: Need to find a more elegant way to do so 
    XmlNode headerNode = null; 
    XmlNodeList nodeList = doc.GetElementsByTagName("Action"); 
    if (nodeList.Count > 0) 
    { 
     headerNode = nodeList[0].ParentNode; 
     headerNode.RemoveChild(nodeList[0]); 
    } 

    // Set the body id - not in used but could be useful at a later stage of this project 
    XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);  
    ns.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/"); 
    XmlElement body = doc.DocumentElement.SelectSingleNode(@"//s:Body", ns) as XmlElement;  
    if (body == null)  
     throw new ApplicationException("No body tag found"); 
    body.RemoveAllAttributes(); // no need to have namespace 
    body.SetAttribute("Id", "ABC"); // Body Id could be passed as a param 

    // Create a custom SignedXml object so that we could sign the keyinfo 
    CustomSignedXml signedXml = new CustomSignedXml(doc); 

    // Add the key to the SignedXml document. 
    signedXml.SigningKey = cert.PrivateKey; 

    // Create a new KeyInfo object. 
    KeyInfo keyInfo = new KeyInfo(); 
    keyInfo.Id = keyInfoRefId; 

    // Load the certificate into a KeyInfoX509Data object 
    // and add it to the KeyInfo object. 
    KeyInfoX509Data keyInfoData = new KeyInfoX509Data(); 
    keyInfoData.AddCertificate(cert); 
    keyInfo.AddClause(keyInfoData); 

    // Add the KeyInfo object to the SignedXml object. 
    signedXml.KeyInfo = keyInfo; 

    // Create a reference to be signed. 
    Reference reference = new Reference(); 
    reference.Uri = ""; 

    // Add an enveloped transformation to the reference. 
    XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(); 
    reference.AddTransform(env); 

    // Add the reference to the SignedXml object. 
    signedXml.AddReference(reference); 

    Reference reference2 = new Reference(); 
    reference2.Uri = "#" + keyInfoRefId; 
    signedXml.AddReference(reference2); 

    // Add the Signature Id 
    signedXml.Signature.Id = Signature; 

    // Compute the signature. 
    signedXml.ComputeSignature(); 

    // Get the XML representation of the signature and save 
    // it to an XmlElement object. 
    XmlElement xmlDigitalSignature = signedXml.GetXml(); 

    // Append the Signature element to the XML document. 
    if (headerNode != null) 
    {     
     headerNode.AppendChild(doc.ImportNode(xmlDigitalSignature, true)); 
    } 

    return doc.InnerXml; 
} 

public static X509Certificate2 GetCertificateBySubject(string CertificateSubject) 
{ 
    // Check the args. 
    if (string.IsNullOrEmpty(CertificateSubject)) 
     throw new ArgumentNullException("CertificateSubject"); 

    // Load the certificate from the certificate store. 
    X509Certificate2 cert = null; 

    X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser); 

    try 
    { 
     // Open the store. 
     store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); 

     // Find the certificate with the specified subject. 
     cert = store.Certificates.Find(X509FindType.FindBySubjectName, CertificateSubject, false)[0]; 

     // Throw an exception of the certificate was not found. 
     if (cert == null) 
     { 
      throw new CryptographicException("The certificate could not be found."); 
     } 
    } 
    finally 
    { 
     // Close the store even if an exception was thrown. 
     store.Close(); 
    } 

    return cert; 
} 

とCustomSignedXmlクラス:

public class CustomSignedXml : SignedXml 
{ 
    public CustomSignedXml(XmlDocument doc) : base(doc) 
    { 
     return; 
    } 
    public override XmlElement GetIdElement(XmlDocument doc, string id) 
    { 
     // see if this is the key info being referenced, otherwise fall back to default behavior 
     if (String.Compare(id, this.KeyInfo.Id, StringComparison.OrdinalIgnoreCase) == 0) 
      return this.KeyInfo.GetXml(); 
     else 
      return base.GetIdElement(doc, id); 
    } 
} 
+0

こんにちは、BeforeSendRequestメソッドでこれを使用する方法はあまり明確ではありません。説明できますか? –

0

あなたのWCFサービスからのメッセージをキャプチャできますか? Btw。 WSDLで説明されているJavaサービスで使用されるメッセージセキュリティです。これにより、作業がはるかに簡単になります。

私はあなたの設定が間違っていると思います。なぜなら、証明書クライアントの資格情報が使用されると、公開鍵と秘密鍵を持つクライアント証明書と公開鍵を持つサーバー証明書が必要になるからです。

また、おそらくあなたの要件で説明されています

Does the message contain a KeyInfo x.509 certificate

Is the certificate issued from a trusted CA – configuration based

は、なぜあなたはすでにそのサーバにインストールされているサービス証明書を返送する必要があるでしょうか?証明書が信頼できるCAからのものであるかどうかをサービスがチェックする理由は何ですか?私はあなたのクライアントのための新しい証明書を作成する必要がありますこれらの要件を言うと思います。

しかし、実際の要件は通常、共有言語 - WSDL + WS-Securityアサーションで記述されるため、これは前提です。

制御署名と暗号化は複数のレベルで可能です。まず、ServiceContractMessageContractのプロパティはProtectionLevelで、デフォルトではEncryptAndSignです。 Signに変更できます。

+0

ありがとうございました。この問題をもう一度見て、Java開発者と話す激しい1日の後、クライアント(wcf)上に1つの証明書だけが必要で、すべての送信メッセージに署名するだけです。私はもう少し見て、IClientMessageInspectorを実装することが解決策になるかもしれません。私はまだ掘り下げています... – Nomadefv

+0

JavaのwevサービスメッセージセキュリティはWSDLに記述されていません。 IClientMessageInspectorとBeforeSendRequestを見てください。 – Nomadefv

関連する問題