views:

2799

answers:

3

Hi all,

I'm implementing a secure WCF service. Authentication is done using username / password or Windows credentials. The service is hosted in a Windows Service process. Now, I'm trying to find out the best way to implement authorization for each service operation.

For example, consider the following method:

public EntityInfo GetEntityInfo(string entityId);

As you may know, in WCF, there is an OperationContext object from which you can retrieve the security credentials passed in by the caller/client. Now,authentication would have already finished by the time the first line in the method is called. However, how do we implement authorization if the decision depends on the input data itself? For example, in the above case, say 'admin' users(whose permissions etc are stored in a database), are allowed to get entity info, and other users should not be allowed... where do we put the authorization checks?

Say we put it in the first line of the method like so:

CheckAccessPermission(PermissionType.GetEntity, user, entityId) //user is pulled from the current OperationContext

Now, there are a couple of questions:

  1. Do we validate the entityId (for example check null / empty value etc) BEFORE the authorization check or INSIDE the authorization check? In other words, if authorization checks should be included in every method, is that a good pattern? Which should happen first - argument validation or authorization?

  2. How do we unit test a WCF service when authorization checks are all over the place like this, and we don't have an OperationContext in the unit test!? (Assuming I'm tryin to test this service class implementation directly without any of the WCF setup).

Any ideas guys?

+4  A: 

For question 1, it's best to perform authorization first. That way, you don't leak validation error messages back to unauthorized users.

BTW, instead of using a home-grown authentication method (which I assume is what your CheckAccessPermission is), you might be able to hook up to WCF's out-of-the-box support for ASP.NET role providers. Once this is done, you perform authorization via OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsInRole(). The PrimaryIdentity is an IPrincipal.

Paul Lalonde
Thanks Paul. The problem with doing authorization first, is this:how do we authorize a user if we need to check the permissions based on the input arguments? Don't we need to validate those arguments first, before we use it for authorization?
Krishna
Authorization should only depend on the identity of the user. If it depends on input arguments, then the caller can send whatever values it needs to get the authorization it wants, so your authorization check becomes meaningless.
Paul Lalonde
No. Say I want to access an object with id 'abc1'. I'm 'user1'. Authorization decides whether 'user 1' can access object 'abc1'. so the first thing to do will be to validate the parameter that contains the object id string!
Krishna
+3  A: 

For question 1, absolutely do authorization first. No code (within your control) should execute before authorization to maintain the tightest security. Paul's example above is excellent.

For question 2, you could handle this by subclassing your concrete service implementation. Make the true business logic implementation an abstract class with an abstract "CheckPermissions" method as you mention above. Then create 2 subclasses, one for WCF use, and one (very isolated in a non deployed DLL) which returns true (or whatever you'd like it to do in your unit testing).

Example (not, these shouldn't be in the same file or even DLL though!):

public abstract class MyServiceImpl
{
    public void MyMethod(string entityId)
    {
        CheckPermissions(entityId);
        //move along...
    }
    protected abstract bool CheckPermissions(string entityId);
}

public class MyServiceUnitTest
{
    private bool CheckPermissions(string entityId)
    {
        return true;
    }
}

public class MyServiceMyAuth
{
    private bool CheckPermissions(string entityId)
    {
        //do some custom authentication
        return true;
    }
}

Then your WCF deployment uses the class "MyServiceMyAuth", and you do your unit testing against the other.

TheSoftwareJedi
+4  A: 

About question #2, I would do this using Dependency Injection and set up your service implementation something like this:

class MyService : IMyService
{
    public MyService() : this(new UserAuthorization()) { }
    public MyService(IAuthorization auth) { _auth = auth; }

    private IAuthorization _auth;

    public EntityInfo GetEntityInfo(string entityId)
    {
            _auth.CheckAccessPermission(PermissionType.GetEntity, 
                    user, entityId);

            //Get the entity info
    }
}

Note that IAuthorization is an interface that you would define.

Because you are going to be testing the service type directly (that is, without running it inside the WCF hosting framework) you simply set up your service to use a dummy IAuthorization type that allows all calls. However, an even BETTER test is to mock the IAuthorization and test that it is called when and with the parameters that you expect. This allows you to test that your calls to the authorization methods are valid, along with the method itself.

Separating the authorization into it's own type also allows you to more easily test that it is correct in isolation. In my (albeit limited) experience, using DI "patterns" give you vastly better separation of concerns and testability in your types as well as leading to a cleaner interface (this is obviously open to debate).

My preferred mocking framework is RhinoMocks which is free and has very nice fluent interface but there are lots of others out there. If you'd like to know more about DI here are some good primers and .Net frameworks:

akmad