Making a Lightswitch intrinsic ria service row level security aware (part 2 of 2)

Introduction

In my previous article we provided the base for row level security aware Ria Services. We did this my sharing the LightSwitch Rowel level filter code with the Ria Service.

In this article, we will make sure that we have also inside the Ria Domain service classes the full set of permissions and the LightSwitch user object at our disposal. By doing so, we really have everything available inside a Ria Service for fine tuning row level security but without having to write duplicate code. We like being .D.R.Y.

An accompanying sample for this article can be found here :http://code.msdn.microsoft.com/vstudio/Setting-up-a-Ria-Service-6f7950b0

If you like my articles, consider following me on twitter: Twitter

What was missing so far ?

Recall from the previous article, our Filter class looked like this so far:

public static  Expression<Func<Customer, bool>> CustomerFilter()
{
return e => e.LastName.EndsWith(“1″);
}

Nice, but we didn’t have access to the Permissions of the current user, and that’s really key for genuine row level security.

What we want is the following:

internal static Expression<Func<Customer, bool>> CustomerFilter()
{
Expression<Func<Customer, bool>> filter = e => true;  //important to initiate as “true” filter
if (!Context.Application.User.HasPermission(Permissions.CanManageAllCustomers))
{
filter = e => e.LastName.EndsWith(“1″);
}
return filter;
}

As you can see, we check the permission of the currently connected user.

You’ll start loving the ServerApplicationContext

using System;
using System.Linq.Expressions;
using LightSwitchApplication.Implementation;
using Microsoft.LightSwitch.ServerGenerated.Implementation;
using Microsoft.LightSwitch.Server;
using Microsoft.LightSwitch;
namespace LightSwitchApplication
{
internal static class RowLevelSecurityFilters
{
private static IServerApplicationContext Context;
static RowLevelSecurityFilters()
{
Context = ServerApplicationContextFactory.Current;
if (Context == null)
{
Context = ServerApplicationContextFactory.CreateContext();
}
}

        internal static Expression<Func<Customer, bool>> CustomerFilter()
{
Expression<Func<Customer, bool>> filter = e => true;  //important to initiate as “true” filter
if (!Context.Application.User.HasPermission(Permissions.CanManageAllCustomers))
{
filter = e => e.LastName.EndsWith(“1″);
}
return filter;
}


        internal static Expression<Func<Order, bool>> OrderFilter()
{
Expression<Func<Order, bool>> filter = e => true; //important to initiate as “true” filter
if (!Context.Application.User.HasPermission(Permissions.CanManageAllCustomers))
{
filter = e => e.Customer.LastName.EndsWith(“1″);
}
return filter;
}
}
}

Note that we are NOT using the strongly typed ServerApplicationContext but we use the weakly typed instead via the ServerApplicationContextFactory. The reason for this is that we do not want to create a binary reference from the Ria Project to the LightSwitch Server project, the strongly typed ServerApplicationContext would need this.

For being able to consume the weakly typed ServerApplicationContext we need following binary references in our Ria Project:

refsForServerContext

How do we get access to the strongly typed Permissions in the Ria Project?

Remember we included a helper project in our solution which carries the file linked auto generated code from the LightSwitch server project. At least, it just contains the ApplicationDataObjectContext class.

We need now to do the same for the Permissions.cs class from the GeneratedArtifacts folder in the LightSwitch Server project:

 

permissions

 

Consuming the filter in the LightSwitch Filter pipeline

Stays exactly the same as before:

using System;
using System.Linq.Expressions;
using Microsoft.LightSwitch;

namespace LightSwitchApplication
{
public partial class ApplicationDataService
{


        partial void Customers_Filter(ref Expression<Func<Customer, bool>> filter)
{
filter = RowLevelSecurityFilters.CustomerFilter();
}
}
}

Consuming the filter in the Ria Domain Service

Stays also exactly the same

namespace RiaService.Services
{
using LightSwitchApplication;
using LightSwitchApplication.Implementation;
using RiaService.DTO;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.ServiceModel.DomainServices.Server;

    public class ExampleCustomerDomainService : LightSwitchDomainServiceBase
{
[Query(IsDefault = true)]
public IQueryable<ExampleCustomerDTO> GetCustomersDTO()
{
var filter = RowLevelSecurityFilters.CustomerFilter();


            return from c in this.Context.Customers.Where(filter)
select new ExampleCustomerDTO
{
Id = c.Id,
CustomerName = c.LastName,
};
}
}
}

Conclusion

In my view, can can do now everything, security wise,  in a Ria Service as you can do inside the LightSwitch server pipeline.

Enjoy.