This post takes you through basics of Secure Conversation concepts through an example written in WCF.
You can download the sample solution[VS 2008] from here.
The solution contains two projects.
- StockQuoteService [The WCF service]
- StockQuoteClient
Set StockQuoteService as the 'Startup Project' and then press Ctrl+F5 to run the service.
Then run the StockQuoteClient by setting it as the 'Startup Project' and pressing Ctrl+F5.
Let's look at service and client configurations and you'll find that we use basicHttpBinding.
<!--[StockQuoteService]\app.config -->
<service name="wso2.org.stockquotes.StockQuoteService" behaviorConfiguration="stockquotebehaviour">
<endpoint address="http://localhost/stocks"
binding="basicHttpBinding"
contract="wso2.org.stockquotes.StockQuoteService" />
<endpoint contract="IMetadataExchange"
binding="mexHttpBinding"
address="mex" />
</service>
Now to enable logging, add following to the [StockQuoteService]\app.config.
<!--[StockQuoteClient]\app.config -->
<client>
<endpoint address="http://localhost/stocks"
binding="basicHttpBinding"
contract="StockQuoteServiceProxy.StockQuoteService" />
</client>
Now lets start both the service and the client.
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging"
switchValue="Warning, ActivityTracing">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelMessageLoggingListener">
<filter type="" />
</add>
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="c:\messages.svclog"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
</sharedListeners>
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true" logMessagesAtTransportLevel="true" />
</diagnostics>
</system.serviceModel>
You can view the log file with SvcTraceViewer tool comes with .NET - launch the tool and simply open the file c:\messages.svclog. You'll find everything in clear text.
Let's change the binding from basicHttpBinding to wsHttpBinding in both the client and service configuration files, delete the file c:\messages.svclog and run both the service and the client.
WCF turns on Secure Conversation by default for all bindings that support WS-Security (WsHttpBinding, NetTcpBinding, netMsmqBinding).
Once again let's open the c:\messages.svclog file in SvcTraceViewer.
Now you'll see 8 messages instead of one.
Let's go through each and every one of them to understand Secure Conversation.
There are different ways to create a Security Context Token[SCT] to establish a Secure Conversation.
One way is through a Security Token Service[STS], which I discussed in this post.
The other two ways are,
1. The SCT is created by one of the communicating parties and propagated with the message.
2. The SCT created through negotiation/exchanges.
The example which we just discussed occupies the second option, that is the SCT created through negotiation/exchanges.
For this scenario the initiating party first sends a RquestSecurityToken[RST]. That is in our case from the client to the service.
Now the service will create a RequestSecurityTokenResponse[RSTR] and will send it back to the client.
<s:Envelope xmlns:s="..." xmlns:a="...">
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>
<a:MessageID>urn:uuid:d55bd2a7-bae8-4751-a010-07e95fd82ee2</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">http://localhost/stocks</a:To>
</s:Header>
<s:Body>
<t:RequestSecurityToken Context="uuid-f422503c-7974-42ab-9b8a-c330727290e9-1"
xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
<t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct
<t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
<t:KeySize>256</t:KeySize>
<t:BinaryExchange
ValueType="http://schemas.xmlsoap.org/ws/2005/02/trust/spnego"
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
TlRMTVNTUAABAAAAt7IY4gQABAA0AAAADAAMACgAAAAFAs4OAAAAD1BSQUJBVEgtSE9NRUhPTUU=
</t:BinaryExchange>
</t:RequestSecurityToken>
</s:Body>
</s:Envelope>
To complete the initial handshaking process client once again sends an RSTR.
<s:Envelope xmlns:s="..." xmlns:a="...">
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue
<a:RelatesTo>urn:uuid:d55bd2a7-bae8-4751-a010-07e95fd82ee2</a:RelatesTo>
</s:Header>
<s:Body>
<t:RequestSecurityTokenResponse
Context="uuid-f422503c-7974-42ab-9b8a-c330727290e9-1"
xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust"
xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<t:BinaryExchange
ValueType="http://schemas.xmlsoap.org/ws/2005/02/trust/spnego"
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
TlRMTVNTUAACAAAACAAIADgAAAA1wpnipKbRWTHfQGhYyuMAAAAAAIIAggBAAAAABQLODgAAAA9
IAE8ATQBFAAIACABIAE8ATQBFAAEAGABQAFIAQQBCAEEAVABIAC0ASABPAE0ARQAEABAAaABvAG0
AZQAuAGMAbwBtAAMAKgBwAHIAYQBiAGEAdABoAC0AaABvAG0AZQAuAGgAbwBtAGUALgBjAG8
AbQAFABAAaABvAG0AZQAuAGMAbwBtAAAAAAA=
</t:BinaryExchange>
</t:RequestSecurityTokenResponse>
</s:Body>
</s:Envelope>
<s:Envelope xmlns:s="..." xmlns:a="">
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue
<a:MessageID>urn:uuid:da46b6f3-b168-4aae-95fb-b9412cecf177</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">http://localhost/stocks</a:To>
</s:Header>
<s:Body>
<t:RequestSecurityTokenResponse
Context="uuid-f422503c-7974-42ab-9b8a-c330727290e9-1"
xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<t:BinaryExchange
ValueType="http://schemas.xmlsoap.org/ws/2005/02/trust/spnego"
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
TlRMTVNTUAADAAAAAAAAAEgAAAAAAAAASAAAAAAAAABIAAAAAAAA
</t:BinaryExchange>
</t:RequestSecurityTokenResponse>
</s:Body>
</s:Envelope>

Now the service will reply with the RequestedSecurityToken.
<s:Envelope xmlns:s="..." xmlns:a="...">
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue</a:Action>
<a:RelatesTo>urn:uuid:da46b6f3-b168-4aae-95fb-b9412cecf177</a:RelatesTo>
</s:Header>
<s:Body>
<t:RequestSecurityTokenResponseCollection xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
<t:RequestSecurityTokenResponse
Context="uuid-f422503c-7974-42ab-9b8a-c330727290e9-1"
xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</t:TokenType>
<t:RequestedSecurityToken>
<c:SecurityContextToken u:Id="uuid-06c81281-3c66-4122-b7ef-07744a68756e-1" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
<c:Identifier>
urn:uuid:05adf263-f2bb-4edf-8597-00c7c7f5e858
</c:Identifier>
</c:SecurityContextToken>
</t:RequestedSecurityToken>
<t:RequestedAttachedReference>
<o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" URI="#uuid-06c81281-3c66-4122-b7ef-07744a68756e-1">
</o:Reference>
</o:SecurityTokenReference>
</t:RequestedAttachedReference>
<t:RequestedUnattachedReference>
<o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:Reference URI="urn:uuid:05adf263-f2bb-4edf-8597-00c7c7f5e858" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct">
</o:Reference>
</o:SecurityTokenReference>
</t:RequestedUnattachedReference>
<t:RequestedProofToken>
<e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod Algorithm="http://schemas.xmlsoap.org/2005/02/trust/spnego#GSS_Wrap">
</e:EncryptionMethod>
<e:CipherData>
<e:CipherValue>
AQAAAMaisligvVhlAAAAAINLoPtv3Zq34T52WXoXBI1YaL+V8cNjc+BxdMVKu
</e:CipherValue>
</e:CipherData>
</e:EncryptedKey>
</t:RequestedProofToken>
<t:Lifetime>
<u:Created>2008-11-03T10:11:04.437Z</u:Created>
<u:Expires>2008-11-03T10:26:04.437Z</u:Expires>
</t:Lifetime>
<t:KeySize>256</t:KeySize>
</t:RequestSecurityTokenResponse>
<t:RequestSecurityTokenResponse
Context="uuid-f422503c-7974-42ab-9b8a-c330727290e9-1"
xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<t:Authenticator>
<t:CombinedHash>Zc9/3FeaG8b6/cs7jeTsHpZC8JlPjCgeun5I/4RRbd0=</t:CombinedHash>
</t:Authenticator>
</t:RequestSecurityTokenResponse>
</t:RequestSecurityTokenResponseCollection>
</s:Body>
</s:Envelope>

Now the client sends following message to the service.
<s:Envelope xmlns:s="..." xmlns:a="..." xmlns:u="...">
<s:Header>
<a:Action s:mustUnderstand="1" u:Id="_4">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT</a:Action>
<a:MessageID u:Id="_5">urn:uuid:b534d3de-1bcc-42fb-81b6-e472c797281f</a:MessageID>
<a:ReplyTo u:Id="_6">
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1" u:Id="_7">http://localhost/stocks</a:To>
<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-f422503c-7974-42ab-9b8a-c330727290e9-5">
<u:Created>2008-11-03T10:11:04.453Z</u:Created>
<u:Expires>2008-11-03T10:16:04.453Z</u:Expires>
</u:Timestamp>
<c:SecurityContextToken u:Id="uuid-06c81281-3c66-4122-b7ef-07744a68756e-1" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
<c:Identifier>urn:uuid:05adf263-f2bb-4edf-8597-00c7c7f5e858</c:Identifier>
</c:SecurityContextToken>
<c:DerivedKeyToken u:Id="_0" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
<o:SecurityTokenReference>
<o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" URI="#uuid-06c81281-3c66-4122-b7ef-07744a68756e-1"></o:Reference>
</o:SecurityTokenReference>
<c:Offset>0</c:Offset>
<c:Length>24</c:Length>
<c:Nonce>
<!-- Removed-->
</c:Nonce>
</c:DerivedKeyToken>
<c:DerivedKeyToken u:Id="_1" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
<o:SecurityTokenReference>
<o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" URI="#uuid-06c81281-3c66-4122-b7ef-07744a68756e-1">
</o:SecurityTokenReference>
<c:Nonce>
<!-- Removed-->
</c:Nonce>
</c:DerivedKeyToken>
<e:ReferenceList xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:DataReference URI="#_3">
<e:DataReference URI="#_8">
</e:ReferenceList>
<e:EncryptedData Id="_8" Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"></e:EncryptionMethod>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<o:SecurityTokenReference>
<o:Reference URI="#_1">
</o:SecurityTokenReference>
</KeyInfo>
<e:CipherData>
<e:CipherValue>.....
</e:CipherData>
</e:EncryptedData>
</o:Security>
</s:Header>
<s:Body u:Id="_2">
<e:EncryptedData Id="_3" Type="http://www.w3.org/2001/04/xmlenc#Content" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"></e:EncryptionMethod>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:Reference URI="#_1"></o:Reference>
</o:SecurityTokenReference>
</KeyInfo>
<e:CipherData>
<e:CipherValue>...</e:CipherValue>
</e:CipherData>
</e:EncryptedData>
</s:Body>
</s:Envelope>

Finally the service will repond with the following.
Now the client will invoke the bussiness logic.
<s:Envelope xmlns:s="..." xmlns:a="..." xmlns:u="...">
<s:Header>
<a:Action s:mustUnderstand="1" u:Id="_4">http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT
<a:RelatesTo u:Id="_5">urn:uuid:b534d3de-1bcc-42fb-81b6-e472c797281f</a:RelatesTo>
<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-06c81281-3c66-4122-b7ef-07744a68756e-6">
<u:Created>2008-11-03T10:11:04.468Z</u:Created>
<u:Expires>2008-11-03T10:16:04.468Z</u:Expires>
</u:Timestamp>
<c:DerivedKeyToken u:Id="_0" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
<o:SecurityTokenReference>
<o:Reference URI="urn:uuid:05adf263-f2bb-4edf-8597-00c7c7f5e858" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct">
</o:SecurityTokenReference>
<c:Offset>0</c:Offset>
<c:Length>24</c:Length>
<c:Nonce>
<!-- Removed--<
</c:Nonce>
</c:DerivedKeyToken>
<c:DerivedKeyToken u:Id="_1" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
<o:SecurityTokenReference>
<o:Reference URI="urn:uuid:05adf263-f2bb-4edf-8597-00c7c7f5e858" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct">
</o:SecurityTokenReference>
<c:Nonce>
<!-- Removed-->
</c:Nonce>
</c:DerivedKeyToken>
<e:ReferenceList xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:DataReference URI="#_3"></e:DataReference>
<e:DataReference URI="#_6"></e:DataReference>
</e:ReferenceList>
<e:EncryptedData Id="_6" Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"></e:EncryptionMethod>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<o:SecurityTokenReference>
<o:Reference URI="#_1"></o:Reference>
</o:SecurityTokenReference>
</KeyInfo>
<e:CipherData>
<e:CipherValue>...</e:CipherValue>
</e:CipherData>
</e:EncryptedData>
</o:Security>
</s:Header>
<s:Body u:Id="_2">
<e:EncryptedData Id="_3" Type="http://www.w3.org/2001/04/xmlenc#Content" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"></e:EncryptionMethod>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:Reference URI="#_1"></o:Reference>
</o:SecurityTokenReference>
</KeyInfo>
<e:CipherData>
<e:CipherValue>...</e:CipherValue>
</e:CipherData>
</e:EncryptedData>
</s:Body>
</s:Envelope>
1 comments:
Very nice!
Notice that the case you have showed here is relatively complex one as it uses the SPNego proprietary protocol to bootstrap the secure conversation. In general if negotiation is not used in WCF then one RST and one RSTR are enough.
Keep on writing interesting stuff!
Post a Comment