Effective Internal/External Secure WCF Services

We have a service-based application which has both internal (intranet) and external (internet) customers. We want to expose a secure WCF service for this application using appropriate and effective protocols based on the kind of connection.

Originally, the “obvious” answer appeared to be use a WCF routing service. A WCF router can be placed on an externally-facing web server and proxy requests to the internal server which actually serves the requests. However, upon further investigation, it turns out that the WCF router is extremely limited in the default implementation when security is in use:

It turns out that the WCF team did not provide a very good solution here. The only use case that supports security context forwarding is message security with Windows credentials. … Other use cases such as username password , X.509 or federated credentials does not allow security context forwarding. It means that the router can be configured to enforce message security but the service must be configured to disable security and it cannot access the security context such as the user’s Identity. (Source)

Well that’s a total non-starter. Since we have external users, we support custom username/password authentication. The server’s behavior is tightly integrating with the user’s identity, which must be known. Furthermore, the idea of transporting messages completely in the open between the router and primary server was also not appealing. We could enable this message transport by re-attaching the client’s credentials at the router, however, this would require loading the primary server’s private key certificate on the router server (which is a DMZ server). Neither secure nor appealing.

The solution was to use our NetScaler DMZ device to accept HTTP connections and forward them to an HTTP WCF endpoint on the primary server. Encryption is delegated to the message level, using a certificate, with authentication handled by username/password also at the message level. The client (whether internal or external) encrypts and signs the message with the server’s public key certificate. The private key only exists on the server. Thus, the communication is secure at all points.

In order to ensure no lapses in security implementation occur, we can set the “EncryptAndSign” protection level on the service interface. This ensures that the service will reject any circumstance in which the message is not encrypted.

[ServiceContract(ProtectionLevel = ProtectionLevel.EncryptAndSign)]
public interface IWsbisService { ... }

Since the requests will be forwarded from the NetScaler, the URL that the client requests will not match the actual answering host. By default, WCF will reject connections of this type. It is necessary to modify the service behavior to disable address filtering.

[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
public class WsbisService : IWsbisService { ... }    

In order to implement this technique, we relieve the WCF service of any transport-level security. Although external transport level security (HTTPS) can be provided by the NetScaler, this interferes with WCF (it wants to either encrypt the message, or transport, but not both; since the HTTPS is stripped off, that won’t work). All WCF security (encryption and signing) will be provided at the message level, which can then be passed without inspection by the NetScaler.

We then configure the two server endpoints (HTTP, which will come from the NetScaler and external connections, and Net.TCP, which will be faster for internal connections) to both require message security. Although message security is slower than transport security, WCF cannot provided consistent transport security in these scenarios given that we don’t wish to expose the private key on an externally facing server, which would be necessary to perform the encryption at the transport level.

<netTcpBinding>        
   <binding name="netTcpBindingConfig">
      <security mode="Message">
         <message clientCredentialType="UserName"/>
      </security>
   </binding>
</netTcpBinding>
<wsHttpBinding>
   <binding name="wsHttpBindingConfig" messageEncoding="Mtom">
      <security mode="Message">
         <message clientCredentialType="UserName"/>
      </security>
   </binding>
</wsHttpBinding>

Even though “UserName” is the credential type, a certificate will still be required for encryption. You will need to generate and apply a certificate. We load the certificate in code, and use a custom certificate and certificate validator to ensure the thumbprint matches.

On the server:

X509Certificate2 certificate = new X509Certificate2(certFile);
host.Credentials.ServiceCertificate.Certificate = certificate;

On the client:

client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.Custom;
client.ClientCredentials.ServiceCertificate.Authentication.CustomCertificateValidator = Certificate;

Where “Certificate” is an instance of a certificate validator class (X509CertificateValidator) which loads the public key of the certificate and compares the thumbprint of the presented certificate to the local certificate. This prohibits “man in the middle” type attacks by forcing one specific certificate (whose private key exists only on the primary server) to be used for encryption. Together with a client username/password, mutual authentication is assured. The server is thus authenticated to the client with this certificate, and the client is authenticated to the server with a username/password.

This architecture grants end-to-end security for both intranet and external customers without exposure of keys or dangerous “en route” decryption/re-encryption.

(Note: the diagram shows HTTPS but it’s just HTTP, with the message content being encrypted)
NetScalerWCF

Posted in WCF

Handling Performance Issues with INotifyPropertyChanged and Expensive PropertyChanged Event Handlers

Consider the case of an object which implements INotifyPropertyChanged and has properties that may be dependent on each other. You may have a circumstance where a single user command causes several properties to change, and, depending on the object’s implementation, may generate several PropertyChanged events. If an event handler for the object’s PropertyChanged event executes an expensive or UI intensive task, the multiple PropertyChanged events can cause a real performance problem.

One approach to this problem is to “batch” the PropertyChanged events, combining any duplicate notifications, and dispatch them as a single event after some quiet timeout. The quiet timeout can be very small to maintain the appearance of responsiveness while still capturing multiple change events into a single event dispatch.

I constructed a static class “AccumulatedPropertyChangeNotification” with two public methods: AddHandler, and RemoveHandler. These methods allowed an event handler to be attached to an INotifyPropertyChanged, indirectly, through the accumulator. In order to appropriately handle accumulated property changes (which could be more than one property), I created an event type which supports a sequence of changed properties.

public class AccumulatedPropertyChangedEventArgs : EventArgs 
{
    /// <summary>
    /// A distinct list of properties changed within the last notification cycle. If any notification
    /// of ""/null (meaning possibly all properties) has been submitted, then this property will be null.
    /// </summary>
    public IEnumerable<string> Properties {get;set;}
}

In order to accumulate dispatches, I used a timer which checks which events are queued and, when appropriate, dispatches them in bulk. This means that the AccumulatedPropertyChanged event is dispatched on a different thread than the object that generated the original PropertyChanged event. To address this situation, I also allow listeners to supply an optional ISynchronizeInvoke for the timer.

Adding and removing handlers are performed with these signatures:

public static void AddHandler(INotifyPropertyChanged objectToWatch, AccumulatedPropertyChangedHandler handler, ISynchronizeInvoke syncObject = null);
public static void RemoveHandler(INotifyPropertyChanged objectToWatch, AccumulatedPropertyChangedHandler handler);

When a handler is added, the handler is added to an internal notification list, and the PropertyChanged event of the objectToWatch is wired to an internal handler in the AccumulatedPropertyChangeNotification class. This handler simply puts the event, and the time it occurred, into an internal event queue.

private static List<Tuple<INotifyPropertyChanged, AccumulatedPropertyChangedHandler, ISynchronizeInvoke>> notifications;
private static List<Tuple<INotifyPropertyChanged, PropertyChangedEventArgs, DateTime>> changeNotificationsQueued;

When the timer fires, it looks at the change notification queue, groups by INotifyPropertyChanged instance, and checks for the most recent DateTime of property changed. If it is at least as old as the mandatory delay (by default, 50 milliseconds), then all the changes for that instance are batched and dispatched to all AccumulatedPropertyChangedHandler delegates associated with that object. This was a bit tricky to get correct.

The other issue that was tricky was RemoveHandler, doing a lookup on a given handler to remove it. Apparently Object.ReferenceEquals with methods doesn’t work well (or didn’t for me), so I ended up using .Equals on the delegate, which is not (still isn’t) what I expected to do.

Download implementation and unit tests. You will probably want to change the namespace to match your project.

If you’re using WPF, you’ll need a wrapper for the Dispatcher to implement ISynchronizeInvoke (come on Microsoft, get your shit together). A good implementation can be found at http://blogs.openspan.com/2010/04/hosting-openspan-a-complete-isynchronizeinvoke-wrapper-for-the-dispatcher/, though beware I found that InvokeRequired was returning false when it should have been returning true.