Freigeben über


Mocking RIA Services Authentication and Authorization

I’m about to embark on a series of Silverlight Authorization-related posts using a shared sample project. I use this base project as a template to share functionality and visual consistency to my sample applications. Most of the template is pretty straightforward. I have a MasterPage that imports (using MEF) a few different things for each sample application. The most interesting of these is the list of Users the sample will be working against. The template puts these users in a ListBox, and when a user is selected in the list, the template updates WebContext.Current.User.

In updating WebContext.Current.User, the template uses a MockAuthentication type. Mocks of this kind are very useful as they allow you to test how your Silverlight application behaves in response to different user credentials. In each of my (upcoming) samples, you can cycle through the different users and see how the applications change.

The first step in creating a mock is extending the AuthenticationService type found in the System.ServiceModel.DomainServices.Client assembly. At a minimum you’ll need to implement the CreateDefaultUser method and at least one authentication operation (I chose LoadUser).

   public class MockAuthentication : AuthenticationService
  {
      public static IPrincipal MockUser { get; set; }

      private readonly IPrincipal _defaultUser;

      public MockAuthentication(IPrincipal defaultUser)
      {
          this._defaultUser = defaultUser;
      }

      protected override IPrincipal CreateDefaultUser()
      {
          return this._defaultUser;
      }

      protected override IAsyncResult BeginLoadUser(AsyncCallback callback, object state)
      {
          IAsyncResult result = new MockAsyncResult(state);
          Deployment.Current.Dispatcher.BeginInvoke(
              () => callback(new MockAsyncResult(state)));
          return result;
      }

      protected override LoadUserResult EndLoadUser(IAsyncResult asyncResult)
      {
          return new LoadUserResult(MockAuthentication.MockUser);
      }

      // ...

      private class MockAsyncResult : IAsyncResult
      {
          private readonly object _asyncState;

          public MockAsyncResult(object asyncState)
          {
              this._asyncState = asyncState;
          }

          public object AsyncState { get { return this._asyncState; } }
          public WaitHandle AsyncWaitHandle { get { throw new NotImplementedException(); } }
          public bool CompletedSynchronously { get { return false; } }
          public bool IsCompleted { get { return true; } }
      }
  } 

The next step is to add the the mock AuthenticationService to the WebContext. In your test App constructor, just add the following lines.

   this.ApplicationLifetimeObjects.Add(new WebContext()
      {
         Authentication = new MockAuthentication(myDefaultUser)
      });

Finally, in your test code you can select the user you want to test in just another few lines.

   MockAuthentication.MockUser = myTestUser;
  WebContextBase.Current.Authentication.LoadUser();

Calling the LoadUser method will result in an asynchronous update to WebContext.Current.User. It also correctly raises a LoggedIn or LoggedOut event from WebContext.Current.Authentication. This not only allows you to test different application states, but also to test application transitions simulating every time a new user signs in or signs out.

Comments

  • Anonymous
    September 18, 2012
    Hi Kyle, thanks for sharing this. One thing I don't get however. The MockAuthenticationService is intended to be used on the Silverlight client. As far as I know there's no way in Silverlight to instantiate something like a GenericPrincipal or get the currently logged in user other than using an actual AuthenticationService implementation which is what we're trying to avoid here. Where do I get the IPrincipal from that I need to instatiate the MockAuthenticationService and what would I use to set MockUser? Without an actual AuthenticationService I can't get any Principals or do I miss something?

  • Anonymous
    September 20, 2012
    I was so busy looking for a factory for a Principal that I missed the obvious. In case anybody is wondering, the answer to my question above is... your mocking framework of choice. There you have it. Just define types implementing IIdentity and IPrincipal and have Moq, Rhino,... stub the properties for you. Applying the same thought to the MockAuthenticationService you can use you mocking framework to model return values of the MockAuthenticationService's EndYyy methods. Or you sysnchronize the async pattern and mock the sync method.