views:

207

answers:

3

We are using ASP.NET with a lot of AJAX "Page Method" calls. The WebServices defined in the Page invokes methods from our BusinessLayer. To prevent hackers to call the Page Methods, we want to implement some security in the BusinessLayer.

We are struggling with two different issues.

First one:

public List<Employees> GetAllEmployees()
{
    // do stuff
}

This Method should be called by Authorized Users with the Role "HR".

Second one:

public Order GetMyOrder(int orderId)
{
    // do sutff
}

This Method should only be called by the owner of the Order.

I know it's easy to implement the security for each method like:

public List<Employees> GetAllEmployees()
{
    // check if the user is in Role HR
}

or

public Order GetMyOrder(int orderId)
{
    // check if the order.Owner = user
}

What I'm looking for is some pattern/best practice to implement this kind of security in a generic way (without coding the the if then else every time) I hope you get what i mean :-)

A: 

If you are using SOA, you can create a Security Service, and each action (method) will send it's context (UserId, OrderId etc.). Security Service knows about business security rules.

Scheme may be something like this

UI -> Security -> BLL -> DAL
griZZZly8
@griZZZly8 any samples/literature ?
gsharp
I agree to put the security at application level and not at "Framework" level like the other answers. What if roles are dynamic?
Mike Gleason jr Couturier
+2  A: 

One "best practice" is to implement Security an aspect. This keeps the security rules separate from the primary business logic, avoiding hard-coding and making it easy to change the security rules in different environments.

The article below lists 7 ways of implementing aspects and keeping the code separate. One approach that is simple and doesn't change your business logic interface is to use a proxy. This exposes the same interface as you have currently, yet allows an alternative implementation, which can decorate the existing implementation. The security requirements can be injected into this interface, using either hard-coding or custom attributes. The proxy intercepts method calls to your business layer and invokes the appropriate security checks. Implementing interception via proxies is described in detail here - Decouple Components by Injecting Custom Services into your Object's Invocation Chain. Other AOP approaches are given in Understanding AOP in .NET.

Here's a forum post discussing security as an aspect, with implementation using advice and security attributes. The end result is

public static class Roles 
{
    public const string ROLE_ADMIN = "Admin";
    public const string ROLE_CONTENT_MANAGER = "Content Manager";
}

// business method    
[Security(Roles.ROLE_HR)]
public List<Employee> GetAllEmployees();

You can put the attribute directly on your business method, tight coupling, or create a service proxy with these attributes, so the security details are kept separate.

mdma
The solution is too tied to the framework in my opinion (by decorating methods). I would implement the security features being a part of the system as it is not as outside of the business logic as it may seem. I like the proxy suggestion though.. my 2 cents.
Mike Gleason jr Couturier
@Mike - the attributes are your own, so I don't see how this is tied to any framework. They are an implementation detail - declaritive security rather than writing code. You are still free to write code, but putting the code on the business objects themselves what what the OP says he wants to avoid. When the attributes are put on the business objects, they are still "separate" from the code - i.e. easily identifiable. This is not so much the case if you make the security checks as code and put that in with the business logic.
mdma
Hi, well I see it like it's hardcoding. That's why I said "framework" sorry. What if the roles are dynamic? I would create security objects just like "User" objects for example as they are a part of the system just like anything else.
Mike Gleason jr Couturier
+2  A: 

user mdma described a bit about Aspect Oriented Programming. For this you will need to use an external library (such as the great PostSharp), because .NET doesn’t have much AOP functionality. However, .NET already has a AOP mechanism for role based security, that can solve part of your problem. Look at the following example of standard .NET code:

[PrincipalPermission(SecurityAction.Demand, Role="HR")]
public List<Employees> GetAllEmployees()
{
    // do stuff
}

The PrincipalPermissionAttribute is part of the System.Security.Permissions namespace and is part of .NET (since .NET 1.0). I’ve been using it for years already to implement role based security in my web applications. Nice thing about this attribute is that the .NET JIT compiler does all the weaving for you on the background and you can even define it on a class level. In that case all members of that type will inherit that attribute and its security settings.

Of course it has its limitations. Your second code sample can't be implemented using the .NET role based security attribute. I think you can’t really come around some custom security checks in this method, or calling some internal security library.

public Order GetMyOrder(int orderId)
{
    Order o = GetOrderInternal(orderId);
    BusinessSecurity.ValidateOrderForCurrentUser(o);
}

Of course you can use an AOP framework, but you would still have to write an framework specific attribute that will again call your own security layer. This would only get useful when such an attribute would replace multiple method calls, for instance when having to put code inside try,catch,finally statements. When you would be doing a simple method call, there wouldn’t be much difference between a single method call or a single attribute IMO.

When you are returning a collection of objects and want to filter out all objects for which the current user doesn't have the proper rights, LINQ expression trees can come in handy:

public Order[] GetAllOrders()
{
    IQueryable orders = GetAllOrdersInternal();
    orders = BusinessSecurity.ApplySecurityOnOrders(orders);
    return orders.ToArray();
}

static class BusinessSecurity
{
    public static IQueryable<Order> ApplySecurityOnOrders(
       IQueryable<Order> orders)
    {
        var user = Membership.GetCurrentUser();

        if (user.IsInRole("Administrator"))
        {
            return orders;
        }

        return 
            from order in orders
            where order.Customer.User.Name == user.Name
            select order; 
    }
}

When your O/RM supports LINQ through expression trees (such as NHibernate, LINQ to SQL and Entity Framework) you can write such a security method once and apply it everywhere. Of course the nice thing about this is, that the query to your database will always be optimal. In other words, no more records will be retrieved than needed.

Good luck.

Steven