Reputation: 41
Have been struggling for last few days with this error Authentication of type {http://service.soap.xcompany.com}AuthenticationHeader had undefined attribute {http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Id
while invoking a service call from a C# WCF client (targeting .Net 4.5 framework) to a Java Soap Service hosted externally with end-to-end encryption (both client and service certificates are used). When I tested the service using SoapUI with a JKS file, request was processed successfully.
So to see what's difference between the two requests, I did the followings:
My questions are:
Some codes used binding and endpoint behavior:
private static CustomBinding BuildCustomBinding()
{
var binding = new CustomBinding();
var textMessageEncoding = new TextMessageEncodingBindingElement()
{
MessageVersion = MessageVersion.Soap11
};
var securityBindingElement =
SecurityBindingElement.CreateMutualCertificateBindingElement(
MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10, true);
binding.Elements.AddRange(textMessageEncoding, securityBindingElement, new HttpsTransportBindingElement());
return binding;
}
private static void CallAccountService()
{
//credential for test
const string applId = "testuser";
const string pwd = "password";
//for client certificate, import client.pfx to LocalMachine's Trusted Root Certification Authorities and make sure the thumbprint matches
var client = new NOLWSAccountSvc.WSAccountv1Client(BuildCustomBinding(), GetAccountServiceEndpointAddress());
client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine,
StoreName.Root, X509FindType.FindByThumbprint, "thumbprintvalue");
//for service certificate, import service-provider.cer to same store location and store name and make sure the thumbprint matches
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.Root,
X509FindType.FindByThumbprint, "thumprintvalue");
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.PeerOrChainTrust;
client.Open();
var header = new NOLWSAccountSvc.AuthenticationHeader()
{
application_id = applId,
password = pwd
};
var getActiveAccountsFunc = new NOLWSAccountSvc.getActiveAccounts() { applRef = "softact-dev", resetRows = true };
try
{
var response = client.getActiveAccounts(header, getActiveAccountsFunc);
Console.WriteLine(response.moreData);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
client.Close();
}
}
Thanks for your time! Your help will be highly appreciated.
Upvotes: 3
Views: 839
Reputation: 41
Well, my colleague helped me figure out way to remove the extra headers from the request before it was posted to the Java SOAP service endpoint - the key was to use IClientMessageInspector and implement some logic in the BeforeSendRequest to remove the unwanted headers that were rejected by the service provider; then add a custom FormattingBehavior class to inherit from IEndpointBheavior and in the IEndPointBehavior.ApplyClientBehavior, attach the MyClientMessageInspector; finally add the customer endpoint behavior to the web service client. Here are the codes:
Where and how to remove unwanted request headers:
public class MyClientMessageInspector : IClientMessageInspector
{ public MyClientMessageInspector(ServiceEndpoint endpoint) { }
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
//Console.WriteLine(request.ToString());
var lstUnwantedStuff = new[]
{
new KeyValuePair<string, string>("Action", "http://www.w3.org/2005/08/addressing"),
new KeyValuePair<string, string>("VsDebuggerCausalityData",
"http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink")
};
foreach (var kv in lstUnwantedStuff)
{
var indexOfUnwantedHeader = request.Headers.FindHeader(kv.Key, kv.Value);
if (indexOfUnwantedHeader>=0)
{
request.Headers.RemoveAt(indexOfUnwantedHeader);
}
}
...
Where and how to use the custom ClientMessageInspector:
internal class MyFaultFormatterBehavior : IEndpointBehavior
{ ...
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyClientMessageInspector(endpoint));
}
}
Where and how to attach custom EndpointBehavior:
private static void CallAccountService()
{
var client = new WSAccountv1Client(BuildCustomBinding(), GetAccountServiceEndpointAddress());
//Set client certificate
client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine,
StoreName.Root, X509FindType.FindByThumbprint, "xxxxxxxxxx");
//for service certificate
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople,
X509FindType.FindByThumbprint, "xxxxxxxxxxxxxxxxy");
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.PeerOrChainTrust;
//add faultformattingbehavior so we can intercept the fault reply message
client.Endpoint.EndpointBehaviors.Add(new MyFaultFormatterBehavior());
client.Open();
var header = new AuthenticationHeader()
{
application_id = applId,
password = pwd
};
var getActiveAccountsFunc = new getActiveAccounts() { applRef = "test", resetRows = true };
try
{
//MyClientMessageInspector.BeforeSendRequest is entered when this called is made
var response = client.getActiveAccounts(header, getActiveAccountsFunc);
Console.WriteLine(response.moreData);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
client.Close();
}
}
What else? In the proxy classes, need to set the Authentication ProtectionLevel to None while on the Service level it needs to be set as ProtectionLevel.Sign:
Request level:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(IsWrapped = false)]
public partial class getActiveAccountsRequest
{
[System.ServiceModel.MessageHeaderAttribute(Namespace = "http://service.xcompany.com"
, ProtectionLevel = System.Net.Security.ProtectionLevel.None
)]
public AuthenticationHeader Authentication;
Service (Interface) Level:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace = "http://service.xcompany.com",
ConfigurationName = "WSAccount"
, ProtectionLevel = ProtectionLevel.Sign
)]
public interface WSAccount
{
Upvotes: 1
Reputation: 127
@jdweng Yes, I did; here were two request bodies, first from .Net and 2nd from SoapUI:
.Net Request:
<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><h:Authentication u:Id="_2" xmlns:h="http://service.soap.xcompany.com" xmlns="http://service.soap.xcompany.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><application_id>testuserid</application_id><password>testpassword</password></h:Authentication><ActivityId CorrelationId="d7085e6f-b757-46e8-b3eb-319a51d568a3" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">00000000-0000-0000-0000-000000000000</ActivityId><VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo8DAzaQVkApDpl1Tc1YTHQwAAAAAMbeMEvBLCUqoD7kEDPHDKYukgggNOf5FtHBB/Sa7ggkACQAA</VsDebuggerCausalityData><o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><o:BinarySecurityToken u:Id="uuid-eb310312-396a-4d00-8922-f77de97138cb-3" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">MIIDYzCCAkugAwIBAgIEaGKzJDANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJ1czEPMA0GA1UEChMGU3ByaW50MREwDwYDVQQLEwhQcm9qZWN0czEMMAoGA1UECxMDQk1QMQwwCgYDVQQLEwNUUEExEzARBgNV</o:BinarySecurityToken><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI="#_1"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>WCpRwVjx89ceVctR8lp9LNGKHeA=</DigestValue></Reference><Reference URI="#_2"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>8/PErh8BL9To5zazpP9CbPFTAa8=</DigestValue></Reference></SignedInfo><SignatureValue>hOtpz7lXvZPPbBD6sV1hxyx3Hc39vj0q2GYKMd8oQbgTbbuKC7QKcZOjktqUxayrzc6h/V0j7Kx3APPONe4F3A2581nK4AQ72yYonsaeXQW0yzSxW/VTsN04uoqCP6IpKXqlAz40VeWGUPJOeGthCKy/9A+NSuqS</SignatureValue><KeyInfo><o:SecurityTokenReference><o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-eb310312-396a-4d00-8922-f77de97138cb-3"/></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"><getActiveAccounts xmlns="http://service.soap.xcompany.com"><applRef>dev</applRef><resetRows>false</resetRows></getActiveAccounts></s:Body></s:Envelope>
SoapUI Request:
(somehow it won't let me past whole xml here.. )
Upvotes: 1