(updated to reflect Feb CTP changes)
One of the cool things in PeerChannel is the ability to secure application messages. say, you are writing an app that uses peerchannel to download content or broadcast stock quotes, you want to be sure that the message originated from a known source. This is because, in a peer mesh, you are not directly connected to the source, but thru other peer application instances. so a secure connection by itself doesnt guarantee application message security. What you also want to do is, to make sure that the message is not tampered in-flight while the message is traveling across the mesh. For this purpose, PeerChannel provides a property to enable message authentication. This property is available conviniently on NetPeerTcpBinding.
How it works?
for OutputChannels, each message is signed using the certificate provided thru PeerCredential.Certificate. All messages, before delivered to the application, are checked to tally the message credential using the validator(an instance of X509CertificateValidator) provided in PeerCredential.MessageSenderAuthentication.
lets consider an example. assume the following service contract for the mesh:
[
{
}
Sender
sender's code looks like this:
//load the certificate of the sender.
X509Certificate2 senderCredentials = GetCertificate(StoreName.My, StoreLocation.CurrentUser, recognizedSender, X509FindType.FindBySubjectDistinguishedName);
cf.Credentials.Peer.Certificate = senderCredentials;
//specify a validator that is invoked during message signature verification.
cf.Credentials.Peer.MessageSenderAuthentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
cf.Credentials.Peer.MessageSenderAuthentication.CustomCertificateValidator =
sender.Open();
// The price change message is signed with sender credentials before sending on the mesh.
sender.PriceChange(name, change, currentValue);
Receiver
on the receiver side, peerchannel passes the message thru message signature verification before forwarding it to the application. the OperationContext holds security properties that resulted after the message verification. Here is the receiver of price change messages: This sample simply finds a claim in the operation context object and prints it:
Claim
result = claims.Current;
source = claim.Resource
MessageValidator
lastly, how to implement a message validator:
the validator that you pass to the method PeerSecurityBehavior.SetMessageX509Authentication() must implement a single method that identifies the known message source.
A sample implementation looks like this:
class
//single method that needs to be overriden. the single parameter certificate is extracted from the incoming message and passed to this function.
//all you need to do is to check if the certificate is valid and is one of the authenticated message senders that your application accepts.
public override void Validate(X509Certificate2 certificate)
if (0 != String.CompareOrdinal(certificate.Thumbprint, senderThumbprint))
throw new SecurityTokenValidationException("Unrecognized sender");
here is the complete exampe:
sender.cs
// Copyright (c) Microsoft Corporation. All Rights Reserved.
using
// M:N broadcast application that enables senders to send announcements to multiple receivers
// using Peer Channel (a multi-party channel). The receiver is implemented by a different program.
// If you are unfamiliar with new concepts used in this sample, refer to the Indigo Basic\GettingStarted sample.
namespace
node.Online +=
node.Offline +=
store.Open(
matches = store.Certificates.Find(findType, key,
result = matches[0];
store.Close();
Sender.config
<?
<
<!--
</
Receiver.cs
// using Peer Channel (a multi-party channel). The sender is implemented by a different program.
publisherCredentials = GetCertificate(
receiver.Credentials.Peer.MessageSenderAuthentication.CertificateValidationMode = X509CertificateValidationMode.Custom; receiver.Credentials.Peer.MessageSenderAuthentication.CustomCertificateValidator = new PublisherValidator(publisherCredentials);
// Retrieve the PeerNode associated with the receiver and register for online/offline events
EndpointAddress lookFor = new EndpointAddress(baseAddress + "Stocks"); for (int i=0; i<receiver.ChannelDispatchers.Count; ++i) { ChannelDispatcher channelDispatcher = receiver.ChannelDispatchers[i] as ChannelDispatcher; if (channelDispatcher != null) { for (int j=0; j<channelDispatcher.Endpoints.Count; ++j) { EndpointDispatcher endpointDispatcher = channelDispatcher.Endpoints[j]; if (endpointDispatcher.EndpointAddress == lookFor) { IOnlineStatus ostat = (IOnlineStatus)channelDispatcher.Listener.GetProperty<IOnlineStatus>(); if (ostat != null) { ostat.Online += OnOnline; ostat.Offline += OnOffline; if (ostat.IsOnline) { Console.WriteLine("** Online"); } } } } } }
// Open the ServiceHostBase to create listeners and start listening for messages.
receiver.Open();
receiver.Close();
Receiver.config
Note: MessageAuthentication works independent of PeerNodeAuthenticationMode setting. For best security, turn both settings on.
-Ram Pamulapati
This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at: http://www.microsoft.com/info/cpyright.htm"