Question

I've implemented a solution which involves Rhino.Security to manage user/roles/permissions.
Since I want to check if a user is authorized to access a controller action, I've implemented a custom action filter:

public class AuthorizationAttribute : ActionFilterAttribute
{
    CustomPrincipal currentPrincipal = (CustomPrincipal)filterContext.HttpContext.User;
    var actionName = filterContext.ActionDescriptor.ActionName;     
    var controllerName = filterContext.Controller.GetType().Name;
    var operation = string.Format("/{0}/{1}", controllerName, actionName);

    if (!securityService.CheckAuthorizationOnOperation(currentPrincipal.Code, operation))
    {
    filterContext.Controller.TempData["ErrorMessage"] = string.Format("You are not authorized to perform operation: {0}", operation);
    filterContext.Result = new HttpUnauthorizedResult();
    }
}

CheckAuthorizationOnOperation calls Rhino.Security to check if the user is allowed to the operation specified:

AuthorizationService.IsAllowed(user, operation);

Everything works properly but I've noticed that the second-level cache is never hit when the query called by IsAllowed is executed.
I've investigated and I've seen that the framework (Rhino.Security) uses a DetachedCriteria. These are the 2 procedures called:

public Permission[] GetGlobalPermissionsFor(IUser user, string operationName)
{
    string[] operationNames = Strings.GetHierarchicalOperationNames(operationName);
    DetachedCriteria criteria = DetachedCriteria.For<Permission>()
        .Add(Expression.Eq("User", user)
             || Subqueries.PropertyIn("UsersGroup.Id",
            SecurityCriterions.AllGroups(user).SetProjection(Projections.Id())))
        .Add(Expression.IsNull("EntitiesGroup"))
        .Add(Expression.IsNull("EntitySecurityKey"))
        .CreateAlias("Operation", "op")
        .Add(Expression.In("op.Name", operationNames));

    return FindResults(criteria);
}

private Permission[] FindResults(DetachedCriteria criteria)
{
    ICollection<Permission> permissions = criteria.GetExecutableCriteria(session)
    .AddOrder(Order.Desc("Level"))
    .AddOrder(Order.Asc("Allow"))
    .SetCacheable(true)
    .List<Permission>();
    return permissions.ToArray();
}

As you can see FindResults uses SetCacheable.

Everytime I refresh a page my action filter executes the procedures and the query is executed again, ignoring the cache (second-level). Since I use extensively the cache and all the other calls work properly I would like to understand why this one doesn't work as expected.

Doing some research I've noticed that the second-level cache is used only if I call the function twice:

SecurityService.CheckAuthorizationOnOperation(currentPrincipal.Code, "/Users/Edit");
SecurityService.CheckAuthorizationOnOperation(currentPrincipal.Code, "/Users/Edit");

It seems that the cache for this particular situation only works if I am using the same session (nHibernate). Is there anybody who can try to help me to figure out what's happening?

UPDATE: enter image description here

Was it helpful?

Solution 2

There's an issue with this framework. I opened a question on Google Groups, everyone knows about it, but it seems that the framework has been forgotten.

OTHER TIPS

  1. Make sure you are doing the work inside a transaction
  2. Verify that the Permission entity is cached too
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top