Decently protecting entity fields which may be only updated by server side processing.

Introduction

We have often fields in an entity definition which should only be updated byserver side processing. Think for example at audit fields. Sometimes developers make the mistake by thinking that if they don’t put these security critical fields on screen, the user can’t make updates to these fields.  Completely wrong of course.

How?

Image we have a field called “ChangedBy”, which is filled in by the Update method in the server side save pipeline:

partial void Customers_Updating(Customer entity)
        {
                entity.ChangedBy = this.Application.User.Name;
        }

We want to combine this with making the field read-only, because we want to avoid the client side changes can be made to the “ChangedBy” field:

 public partial class Customer
    {
        partial void ChangedBy_IsReadOnly(ref bool result)
        {
                result = true;        
        }
    }

Obviously, the above won’t work, because now we are too strict: even the server won’t be able to fill in the ChangedBy field.

We can fix this by making use of a brilliant but often misunderstood feature in LightSwitch: Permission Elevation.

 

We first create an additional permission called “CanDoServerSideAudit”.

Make directly make use of this permission in the ChangedBy_IsReadOnly method. If the user has this permission, she can make updated to this field.

 public partial class Customer
    {
        partial void ChangedBy_IsReadOnly(ref bool result)
        {
            if (this.Application.User.HasPermission(Permissions.CanDoServerSideAudit))
            {
                result = false;
            }
            else
            {
                result = true;
            }
        }
    }

 

Note that we will never assign this permission to any user. The permission only exists for the sake of the permission elevation mechanism which we can only activate during server side processing:

partial void Customers_Updating(Customer entity)
        {
            using (this.Application.User.AddPermissions(Permissions.CanDoServerSideAudit))
            {
                entity.ChangedBy = this.Application.User.Name;
            }
        }

As you can see, we elevate temporally the CanDoServerSideAudit permission during the update of our entity. By doing so, the field will be, also temporally, writable. And that’s what we want.

Update 2013-04-08: Unfortunately this is not enough ! See the comment lower on this page of Jewel Lambert: the server side read-only check will not be executed when when the field is not access from the server. That means we need to do additionally following check:

partial void Customers_Updating(Customer entity)
        {

            if (((entity.Details.Properties["ChangedBy"]) as IEntityStorageProperty).IsChanged)
            {
                throw new Exception("The changedBy field should not be changed...");
            }
            using (this.Application.User.AddPermissions(Permissions.CanDoServerSideAudit))
            {
                entity.ChangedBy = this.Application.User.Name; 
            }

Note we have now a Magic String “ChangedBy”. I’ll devote a series of 2 posts on how to avoid magic strings very soon.

Conclusion

If you believe that security matters, the above can be important !

Many thanks to Jewel for the very important addition to the above approach !