Securing Your Agatha Service Layer
Posted by Davy Brion on January 27th, 2010
The question of how to implement security for an Agatha Service Layer is one that comes up frequently. First of all, you need to remember that if you’re using Agatha with WCF you can use any of the WCF features that you’d normally use to secure your WCF service. There’s already plenty of information available online or in books on implementing security for WCF services so i’m not going to spend time on covering those options. What i am going to cover is the approach that we typically use for our Agatha service layers.
I don’t like to tie myself to WCF-specific features, so i always plug in custom authentication into either a custom Request Processor, or a base Request Handler class that all other Request Handlers must inherit from. But first, how do we get the authentication-related data from the client to the service?
In each project i use Agatha in, i always have a MyProjectRequest and MyProjectResponse base class:
public class MyProjectRequest : Request
{
public string UserName { get; set; }
public byte[] PasswordHash { get; set; }
}
public class MyProjectResponse : Response {}
Each request in the project inherits from this base request, and each response inherits from the base response. The base response class is often empty, though this does make it very easy if you ever need to send something back with every response.
Now obviously, if every single request that is sent to your service layer needs values for the UserName and PasswordHash properties you want this to be done in only one place. I do this by using a custom request dispatcher:
public class MyProjectAsyncRequestDispatcher : AsyncRequestDispatcher
{
private readonly IUserContext userContext;
public MyProjectAsyncRequestDispatcher(IAsyncRequestProcessor requestProcessor, IUserContext userContext) : base(requestProcessor)
{
this.userContext = userContext;
}
protected override void BeforeSendingRequests(IEnumerable<Request> requestsToProcess)
{
base.BeforeSendingRequests(requestsToProcess);
foreach (var myProjectRequest in requestsToProcess.OfType<MyProjectRequest>())
{
myProjectRequest.UserName = userContext.UserName;
myProjectRequest.PasswordHash = userContext.PasswordHash;
}
}
}
The IUserContext dependency is just a component that is registered in my IOC container and will be injected automatically whenever you get an instance of IAsyncRequestDispatcher. Now, in this example you can see that i add the authentication data to every request in a batch, even though the batch will be sent in one roundtrip. If you want, you can add the authentication data only to the first request and then only use the first request to do the authentication within your service layer. I prefer to add the authentication data to each request and then authenticate every single request (even subsequent requests in a batch) within the service layer. I’ll get back to this point later on.
Now, the only thing we need to do to make sure that your requests will always have the authentication data contained within them is to instruct Agatha to always use instances of your MyProjectAsyncRequestDispatcher class whenever an IAsyncRequestDispatcher is needed. This is easily done during Agatha’s client-side configuration:
new ClientConfiguration(typeof(MyProjectRequest).Assembly, new Agatha.Castle.Container(myContainerWrapper))
{
AsyncRequestDispatcherImplementation = typeof(MyProjectAsyncRequestDispatcher)
}
.Initialize();
Keep in mind that you still have to register your IUserContext with the container on your own though.
With that in place, we are sure that each request that comes from our clients always contains the proper authentication data. Now we need to make sure that we actually authenticate these requests within the service layer. You basically have 2 options: either implement your own Request Processor which adds authentication checks, or create a base Request Handler that your other Request Handlers inherit from.
We’ll first cover the option of using a custom Request Processor. You could create one like this:
public class MyProjectRequestProcessor : RequestProcessor
{
private readonly IAuthenticator authenticator;
public MyProjectRequestProcessor(IAuthenticator authenticator, ServiceLayerConfiguration serviceLayerConfiguration, ICacheManager cacheManager)
: base(serviceLayerConfiguration, cacheManager)
{
this.authenticator = authenticator;
}
protected override void BeforeHandle(Request request)
{
var myProjectRequest = request as MyProjectRequest;
if (myProjectRequest != null)
{
if (!authenticator.AreValidCredentials(myProjectRequest.UserName, myProjectRequest.PasswordHash))
{
throw new MySecurityException();
}
}
}
}
The BeforeHandle virtual method is called right before the request is passed to its Request Handler to be handled. Note that this Request Processor would authenticate every request. If you want a Request Processor that only authenticates the first request, you could do so like this:
public class MyProjectRequestProcessor : RequestProcessor
{
private readonly IAuthenticator authenticator;
public MyProjectRequestProcessor(IAuthenticator authenticator, ServiceLayerConfiguration serviceLayerConfiguration, ICacheManager cacheManager)
: base(serviceLayerConfiguration, cacheManager)
{
this.authenticator = authenticator;
}
protected override void BeforeProcessing(IEnumerable<Request> requests)
{
var myProjectRequest = (MyProjectRequest)requests.ElementAt(0);
if (!authenticator.AreValidCredentials(myProjectRequest.UserName, myProjectRequest.PasswordHash))
{
throw new MySecurityException();
}
}
}
The BeforeProcessing virtual method is called before any of the requests are handled, so you could authenticate only the first request in a batch and then proceed with regular processing if the first one is authenticated. Now, the big problem that i have with this approach is that you aren’t really in control of what is sent to your service layer. Yes, you can guarantee that each request coming from your clients contains the proper authentication data. What you simply can’t guarantee however is what other people or custom clients can send to your service layer. If they send you a batch of 2 requests, the first containing valid credentials of a normal user for a benign request, it will pass the authentication just fine. If the second request in that batch contains invalid credentials (to trick your authorization into believing it’s from a user with higher privileges for instance) for a request that could cause some damage (deleting important information or triggering certain tasks or whatever), then you can’t really do anything to prevent that. Unless of course, you reject this approach and authenticate every single request.
As for the MySecurityException type, that’s up to you as well. When you configure your Agatha service layer, you can set the SecurityExceptionType property to the type of exception that should be considered as a security exception. When the Request Processor catches an exception of that type, it will set the ExceptionType property of the response to ExceptionType.Security so you can check for that specific situation in your client.
To configure Agatha to use your custom Request Processor, your configuration code would look like this:
new ServiceLayerConfiguration(Assembly.GetExecutingAssembly(), typeof(MyProjectRequest).Assembly,
new Agatha.Castle.Container(containerWrapper))
{
RequestProcessorImplementation = typeof(MyProjectRequestProcessor),
SecurityExceptionType = typeof(MySecurityException)
}
.Initialize();
Another alternative is to create a base Request Handler for your project and to have each Request Handler inherit from it. Something like this, for instance:
public abstract class MyProjectRequestHandler<TRequest, TResponse> : RequestHandler<TRequest, TResponse>
where TRequest : MyProjectRequest
{
public IAuthenticator Authenticator { get; set; }
public override void BeforeHandle(TRequest request)
{
base.BeforeHandle(request);
if (!Authenticator.AreValidCredentials(request.UserName, request.PasswordHash))
{
throw new MySecurityException();
}
Authorize(request);
}
protected virtual void Authorize(TRequest request) {}
}
In case you’re wondering why i’m using Setter-injection here instead of Constructor-injection, read this.
I typically prefer the custom Request Handler approach for authentication. In most applications that we write, authentication is not enough and we need custom authorization checks for many requests. So i’m going to need a base Request Handler which introduces the virtual Authorize method anyway. So i might as well do my authentication check right before it.
With the custom Request Handler approach, you probably still want to configure Agatha to use your custom security exception type:
new ServiceLayerConfiguration(Assembly.GetExecutingAssembly(), typeof(MyProjectRequest).Assembly,
new Agatha.Castle.Container(containerWrapper))
{
SecurityExceptionType = typeof(MySecurityException)
}
.Initialize();
And then you just need to let your own Request Handlers inherit from your MyProjectRequestHandler. Authentication will be performed for each request by default, and you can easily add specific authorization logic for every request.
And those are pretty much the options you have to secure your Agatha Service Layer. Oh, and be sure to only expose your Service Layer through SSL
January 28th, 2010 at 9:35 am
[...] Securing Your Agatha Service Layer – Davy Brion talks about implementing security within his Agatha Service Layer project, which can be achieved by the usual WCF security methods, or as Davy explores in this piece by implementing custom authentication into the request processing. [...]
January 29th, 2010 at 12:36 am
I read your post that discusses setting injection. I won’t go down the path of others and argue that point as it is done against that post already. However, if this is the pattern you go forward with for optional parameters, then you need to check whether Authenticator is null before referencing it to avoid potential NullReferenceExceptions. The code here describes that Authenticator is a required value. In this case it should be injected via the constructor with a guard clause.
Another point of note is that it might be a good idea to also pass the AssemblyQualifiedName of the type that created the hash of the password. This implementation creates an unspoken contract between the client and server about how to calculate the hash. The hash type used is an assumption at best. If the API allows the client to specify how the hash type then there is no assumption in play.
Bryan Sullivan wrote an article in the August 2009 MSDN mag about Cyrptographic Agility (here) which addresses this issue very well.
January 29th, 2010 at 12:37 am
Busted link – try http://msdn.microsoft.com/en-us/magazine/ee321570.aspx
January 29th, 2010 at 9:00 am
@Rory
what i was trying to make clear in the setter injection post was that i sometimes use it for _required_ dependencies to avoid having to put it in the constructor of each derived class. I’m not really gonna keep arguing about the validity of that, because i explained my reasons in the other post (and its comments). I’m not sure if you read it thoroughly though since you seem to think i’m talking about optional dependencies.
thanks for the link btw