Labels: Ubuntu
<soapenv:Header>As regularly, in Visual Studio 2008 I added a service reference to the web service, then write code to call it using the auto-generated proxy:
<wsse:Security xmlns:wsse="http://schemas.xmlsoap.org/ws/2003/06/secext" soapenv:mustUnderstand="1">
<wsse:UsernameToken>
<wsse:Username>****Username Here****</wsse:Username>
<wsse:Password>****Password Here****</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
Proxy client = new Proxy();But I got this error message from the service:
client.DoSomething();
Proxy client = new Proxy();Same error as above. After some googling, I think updating the binding config might do the trick.
client.ClientCredentials.UserName.UserName = “Username”;
client.ClientCredentials.UserName.Password = “Password”;
client.DoSomething();
<system.serviceModel>to:
<bindings>
<binding name="serviceBinding" ....>
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</bindings>
</system.serviceModel>
<system.serviceModel>OK, Something different returned from the service:
<bindings>
<binding name="serviceBinding" ....>
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</bindings>
</system.serviceModel>
BindingElementCollection elements = client.Endpoint.Binding.CreateBindingElements();But my error still the same. I used Charles to see the raw request and response:
elements.Find<SecurityBindingElement>().IncludeTimestamp = false;
client.Endpoint.Binding = new CustomBinding(elements);
<s:Header>The user name and password are in the request, seems only the namespace is not matching the service’s expectation. To verify that, I updated the namespace of security header in the above request in Charles and submitted again, yes! The service is responding correctly. I had no experience in WSE, but guess is that our service is sticking to an earlier version of WS-Security, and rejecting requests with namespace defined in newer versions after that. Maybe that’s why the code above works in the post author’s situation but not mine, maybe.
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:UsernameToken u:Id="uuid-4c248cea-1a3d-4a27-99f0-29ee659ed975-1">
<o:Username>
abc
</o:Username>
<o:Password o:Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
123
</o:Password>
</o:UsernameToken>
</o:Security>
</s:Header>
/// <summary>Before making calls with the proxy, add our custom endpoint behavior, we don’t need to set the username and password (we’ve done that in the custom header):
/// Custom Endpoint Behavior
/// </summary>
public class AddWseSecurityHeaderEndpointBehavior : IEndpointBehavior
{
private readonly string userName;
private readonly string password;
public AddWseSecurityHeaderEndpointBehavior(string userName, string password)
{
this.userName = userName;
this.password = password;
}
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters)
{ }
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
AddWseSecurityHeaderMessageInspector inspector =
new AddWseSecurityHeaderMessageInspector(userName, password);
clientRuntime.MessageInspectors.Add(inspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
EndpointDispatcher endpointDispatcher)
{ }
public void Validate(ServiceEndpoint endpoint)
{ }
#endregion
}
/// <summary>
/// Custom Message Inspector to add WSE security header to the request before sending
/// </summary>
internal class AddWseSecurityHeaderMessageInspector : IClientMessageInspector, IDispatchMessageInspector
{
private readonly string userName;
private readonly string password;
public AddWseSecurityHeaderMessageInspector(string userName, string password)
{
this.userName = userName;
this.password = password;
}
#region IClientMessageInspector Members
public void AfterReceiveReply(ref Message reply, object correlationState)
{ }
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
CustomWseSecurityHeader securityHeader =
new CustomWseSecurityHeader(userName, password);
request.Headers.Add(securityHeader);
return request;
}
#endregion
#region IDispatchMessageInspector Members
public object AfterReceiveRequest(ref Message request, IClientChannel channel,
InstanceContext instanceContext)
{
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{ }
#endregion
}
/// <summary>
/// Custom WSE security header
/// </summary>
internal class CustomWseSecurityHeader : MessageHeader
{
private readonly string userName;
private readonly string password;
public CustomWseSecurityHeader(string userName, string password)
{
this.userName = userName;
this.password = password;
}
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer,
MessageVersion messageVersion)
{
writer.WriteStartElement("UsernameToken", Namespace);
writer.WriteElementString("Username", Namespace, userName);
writer.WriteElementString("Password", Namespace, password);
writer.WriteEndElement();
}
public override string Name
{
get { return "Security"; }
}
public override string Namespace
{
get { return "http://schemas.xmlsoap.org/ws/2003/06/secext"; }
}
public override bool MustUnderstand
{
get { return true; }
}
}
Proxy client = new Proxy();Also as we’re setting username and password in our custom header, we need to change the mode attribute of security element (under binding) to Transport.
AddWseSecurityHeaderEndpointBehavior customEndpointBehavior =
new AddWseSecurityHeaderEndpointBehavior(userName, password);
client.Endpoint.Behaviors.Add(customEndpointBehavior);
client.DoSomething();
October 2004 June 2009 January 2010 December 2011
Subscribe to Posts [Atom]