I am building a client to some STS service and for more than one day now I am trying to add a Header to a WCF message. In my call to RequestSecurityToken I have to include a UsernameToken.
I'm not sure how to accomplish that. For the moment I defined an endpoint behavior and a message inspector (took me long enough to discover those...). In the BeforeSendRequest() of the latter I create an object of the custom class 'Security' which derives from MessageHeader. Security includes an instance of UsernameToken.
public class MessageInspector : IClientMessageInspector {
public object BeforeSendRequest(ref Message request, IClientChannel channel) {
Security uns = new Security();
uns.UsernameToken = new UsernameToken();
// ...
var Header = new MessageHeader<Security>(uns);
var untyped = Header.GetUntypedHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
request.Headers.Add(untyped);
return null;
}
}
public class Security : MessageHeader {
public UsernameToken UsernameToken = new UsernameToken();
public override string Name {
get { return "Security"; }
}
public override string Namespace {
get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
}
}
public class UsernameToken {
public String Username = "";
public Password Password = new Password();
}
This is what is being serialised
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:RequestSecurityToken</Action>
<Security xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<UsernameToken xmlns="http://schemas.datacontract.org/2004/07/Tarifrechner.Kfz">
<Password>
<Type>http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText</Type>
<password>******</password>
</Password>
<Username>******</Username>
</UsernameToken>
</Security>
</s:Header>
<s:Body />
</s:Envelope>
Especially the namespace of UsernameToken seems to be wrong. I know it comes from the data contract serialization but i need a different namespace.
This is what I would like the serialised data to look like
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="...">
<soap:Header>
<Security xmlns:q1="http://www.bipro.net/namespace" xsi:type="q1:UserNameSecurity"
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<UsernameToken>
<Username>******</Username>
<Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">******</Password>
</UsernameToken>
</Security>
<wsa:Action>urn:RequestSecurityToken</wsa:Action>
<wsse:Security>
<wsu:Timestamp wsu:Id="Timestamp-b9dd599d-5901-451d-8321-6a309091f273">
<wsu:Created>2012-03-11T16:02:56Z</wsu:Created>
<wsu:Expires>2012-03-11T16:07:56Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</soap:Header>
<soap:Body>
<RequestSecurityToken xmlns="http://schemas.xmlsoap.org/ws/2005/02/trust">
<TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</TokenType>
<RequestType>
http://schemas.xmlsoap.org/ws/2005/02/trust/Issue
</RequestType>
</RequestSecurityToken>
</soap:Body>
</soap:Envelope>
Is my approach about right? And how can I manipulate things like the namespace of a header detail or whether data is being serialised as attribute or element?
Update
As Ladislav already noted, I don't have to implement classes like UsernameToken myself. I did that only because my knowledge of WCF is so limited.
By now, I discovered, that WS2007HttpBinding, configured to use SecurityMode.TransportWithMessageCredential and with EstablishSecurityContext set to false produces almost the XML I am looking for. How should I have known that?
But there's one problem left: My request has an empty body element, where the request I want to produce, features a RequestSecurityToken element inside the body element. Does anyone know, how I can achieve that?
Using EstablishSecurityContext = true helps but at the same time changes my Soap-Action from the desired "urn:RequestSecurityToken" into the non-working "http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/SCT".
I appreciate any answer!
Thanks a lot!
Björn
One alternative way is to define a MessageContract type for your request, which allows you to define what shows up in the header and body of the SOAP message and adjust the namespace used. For example, consider the following service definition:
[ServiceContract]
public interface IMyService
{
[OperationContract]
MyResponse DoSomething(MyRequest request);
}
public class MyService : IMyService
{
public MyResponse DoSomething(MyRequest request)
{
return new MyResponse()
{
Details = "Service did something awesome.",
Timestamp = DateTime.Now
};
}
}
[MessageContract(IsWrapped = true, WrapperNamespace = "http://myservice/messages/")]
public class MyRequest
{
[MessageHeader(Namespace = "http://myservice/security")]
public string TokenThingy
{
get;
set;
}
}
[MessageContract(IsWrapped = true, WrapperNamespace = "http://myservice/messages")]
public class MyResponse
{
[MessageBodyMember]
public string Details
{
get;
set;
}
[MessageBodyMember]
public DateTime Timestamp
{
get;
set;
}
}
Sending a request produces the following SOAP:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IMyService/DoSomething</Action>
<h:TokenThingy xmlns:h="http://myservice/security">fda</h:TokenThingy>
</s:Header>
<s:Body>
<MyRequest xmlns="http://myservice/messages/" />
</s:Body>
</s:Envelope>
And a response from the service looks like this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body>
<MyResponse xmlns="http://myservice/messages">
<Details xmlns="http://tempuri.org/">Service did something awesome.</Details>
<Timestamp xmlns="http://tempuri.org/">2012-05-04T17:04:36.5980424-04:00</Timestamp>
</MyResponse>
</s:Body>
</s:Envelope>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With