Shawn

Shawn Wildermuth

Securing Web Services (Even with OOB)


Silverlight Logo

I was trading tweets today with @pauliom about whether RIA Services would solve some Auth problems he was having out of the browser.  While RIA does do some interesting things with roles/users, I mentioned that typical Forms Auth out of the box should just work.

To that end I have created a simple example of how to protected WCF Services with Forms Auth (works with ADO.NET Data Services as well BTW).  Because I wanted to support it out of the browser as well, I used the new Forms Auth service.  To do so, just add a new .svc file to your project and put this in the body:

<%@ ServiceHost Language="C#"
            Service="System.Web.ApplicationServices.AuthenticationService" %>

 The web.config also needs to know about the service.  So first, add a web extensions like so:

<system.web.extensions>
  <scripting>
    <webServices>
      <authenticationService enabled="true"/>
    </webServices>
  </scripting>
</system.web.extensions>

 Finally, the WCF configuration bits:

<system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <behavior 
          name="OutOfBrowserFormsAuth.Web.AuthServiceBehavior">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="false" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <services>
    <service 
        behaviorConfiguration="OutOfBrowserFormsAuth.Web.AuthServiceBehavior"
             name="System.Web.ApplicationServices.AuthenticationService">
      <endpoint address=""
            binding="basicHttpBinding"
            contract="System.Web.ApplicationServices.AuthenticationService" />
      <endpoint address="mex"
                binding="mexHttpBinding"
                contract="IMetadataExchange" />
    </service>
  </services>
</system.serviceModel>

Once you have all those pieces you can create the proxy like any other service (with "Add Service Reference...").  Then you can login from the Silverlight application:

var authSvc = new AuthenticationServiceClient();
authSvc.LoginCompleted += (s, a) =>
  {
    if (a.Error != null)
    {
      result.Items.Add(string.Concat("Error logging in: ", a.Error.Message));
    }
    else
    {
      result.Items.Add(string.Concat("Login: ", a.Result));
    }
  };
authSvc.LoginAsync("swildermuth", "P@ssw0rd", null, false);

So securing the web service becomes pretty simple.  I created a new "Silverlight WCF Service" inside a secure folder:

Protected Web Service

I created the web service and then the Service Reference before enabling security so adding a Service Reference would work. This is the one pain point in that you must disable the folder security to add the reference then re-enable it afterwards:

<?xml version="1.0"?>
<configuration>
  <system.web>
    <authorization>
      <deny users="?"/>
      <allow users="*"/>
    </authorization>
  </system.web>
</configuration>

Now the web service will only work once the login happens.  You can test this in or out of the browser and with both stacks with the source code.  Here's a quick screenshot showing it working after login and not working after logout:

Screenshot

 You can download the source code here:

http://wilderminds.blob.core.windows.net/downloads/ProtectedWCF.zip

UPDATE: Here are some links to the actual docs for this:

Configuring the Authentication Service: