Securing Applications Built on Silverlight and WCF

Posted Thu May 7, 2009 @ 7:41 AM


Having recently released our initial offering of Silverlight controls, we are starting to get a feel for the sorts of issues Silverlight developers commonly encounter in designing and developing their applications. One question which seems to pop up frequently is how security and authentication should be handled in the context of a Silverlight application which interacts with WCF services. In applications that include Web.UI controls, especially those with SOA.UI integration, this question becomes even more important.

In this post, I will attempt to shine a bit of light on what we see as a typical approach to authentication and how it can be elegantly integrated into a Silverlight 2 application and the WCF services it employs. We will use the example of simple ASP.NET forms authentication.

Step 1. Configure authentication for the application in its web.config file:

<system.web>
  ...
  <authentication mode="Forms">
    <forms name="secure">
      <credentials passwordFormat="Clear">
        <user name="milos" password="secret" />
      </credentials>
    </forms>
  </authentication>
  ...


This is all we need to do to be able to rely on ASP.NET and its session cookies for authentication and session management. We do still need to do a couple of things in order to connect our Silverlight and web service logic to this underlying mechanism.

Step 2. Write a simple WCF authentication service:

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class AuthenticationService
{
  [OperationContract]
  public bool Authenticate(string sUser, string sPass)
  {
    if (FormsAuthentication.Authenticate(sUser, sPass))
    {
      FormsAuthentication.SetAuthCookie(sUser, false);
      return true;
    }

    return false;
  }

  [OperationContract]
  public bool IsAuthenticated()
  {
    return HttpContext.Current.User.Identity.IsAuthenticated;
  }
}


In this example, we implement two methods: one for checking whether the user is authenticated and another for authenticating her. We rely entirely on built-in FormsAuthentication functionality.

With the AuthenticationService in place, we can plug it into our Silverlight application and its associated WCF services (including standard SOA.UI services). For the former, we can create a service reference in the Silverlight application and use it in this sort of way:

Step 3. Implement authentication logic in the Silverlight application:

public partial class Page : UserControl
{
  public Page()
  {
    InitializeComponent();

    // When the page initializes, perform authentication if necessary:
    AuthenticateAndInitialize();
  }

  void AuthenticateAndInitialize()
  {
    // Check whether the user is authenticated:
    AuthenticationService.AuthenticationServiceClient oAuthClient = 
      new AuthenticationService.AuthenticationServiceClient(...);
    oAuthClient.IsAuthenticatedCompleted += 
      new EventHandler(oAuthClient_IsAuthenticatedCompleted);
    oAuthClient.IsAuthenticatedAsync();
  }

  void oAuthClient_IsAuthenticatedCompleted(object sender, 
    AuthenticationService.IsAuthenticatedCompletedEventArgs e)
  {
    if (e.Result)
    {
      // The user is already authenticated, proceed with initializing the application:
      InitializeApplication();
    }
    else
    {
      // Show login screen, get username and password (code not shown here), and authenticate:
      Authenticate(sUsername, sPassword);
    }
  }

  void Authenticate(string sUser, string sPass)
  {
    // Attempt to authenticate the given credentials:
    AuthenticationService.AuthenticationServiceClient oAuthClient = 
      new AuthenticationService.AuthenticationServiceClient(...);
    oAuthClient.AuthenticateCompleted += 
      new EventHandler(oAuthClient_AuthenticateCompleted);
    oAuthClient.AuthenticateAsync(sUser, sPass);
  }

  void oAuthClient_AuthenticateCompleted(object sender, 
    AuthenticationService.AuthenticateCompletedEventArgs e)
  {
    if (e.Result)
    {
      // The user is now authenticated, proceed with initializing the application:
      InitializeApplication();
    }
    else
    {
      // Login failed, repeat the login screen procedure (code not shown here).
    }
  }

  ...


The (pseudo-)code above outlines the general approach to a simple login procedure which can be integrated into any Silverlight application. We need to interface into this procedure from Silverlight because that is our client-side platform, but the authentication is actually needed not for the client-side Silverlight operations, but for the server-side WCF layer. This brings us to the last step, and the real point of the whole exercise: securing the service.

Step 4. Secure the service:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class SoaFeedReaderDataGridService : SoaDataGridService
{
  public override SoaDataGridSelectResponse Select(SoaDataGridSelectRequest request)
  {
    if (HttpContext.Current.User.Identity.IsAuthenticated)
    {
      // Implement service logic
      ...


The idea is to have the service check the user's credentials before proceeding to fetch data or perform other potentially sensitive operations. In the example above, we are using a standard SOA.UI SoaDataGridService, but the same approach is used for any WCF service.

I hope this basic example clarifies things a bit when it comes to security and Silverlight+WCF applications. For more elaborate authentication mechanisms, other options also exist, such as the ability to pass around custom data using SOA.UI APIs, but that is a topic for another day.

Cheers!

Posted to For the Love of Data by milos

Posted on Thu May 7, 2009 @ 7:41 AM

Filed under: , , , ,

Comments

Thor Arne Johansen
Posted on Thu May 7, 2009 @ 7:41 AM
Can you please comment on how this can/will work in a claims based application (as advocated by Microsoft's "Geneva" technology?
Anonymous comments are not allowed. Click here to log in or create an account.