Thursday, November 8, 2012

Let’s create metadata based permission policies

XAF has a great security system which can be used to protect our data either at client or server side. There is also great support for modifying the Security behavior at runtime using a permission matrix. However we need to provide initial before distributing our application. In this post we are going to discuss a way connecting methods that describe permission policies with our domain objects using metadata (Attributes).

For supplying initial data XAF provides a well documented approach through ModuleUpdaters. We can use them and write methods that create initial permissions. There are also many extension methods that can help us write faster code,

image

Full permission policy

This policy can be applied to any role and give full permission for the related objects. To connect a domain object with a method we need to do the following:

  1. Define a FullPermissionAttribute as,

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]

    public class FullPermissionAttribute : Attribute {

    }

     

  2. Decorate all related objects

    [FullPermission]

    public class MovieArtist : VideoRentalBaseObject {

    [FullPermission]

    public class Artist : VideoPerson {

  3. With the use of XAF’s sub types info metadata API write an abstract algorithm that will enumerate all domain objects and assign full permission to them for a certain role

    public static void CreateFullPermissionAttributes(this SecuritySystemRole systemRole,  bool defaultAllowValues = true) {

        var persistentTypes = XafTypesInfo.Instance.PersistentTypes.Where(info => info.FindAttribute<FullPermissionAttribute>() != null);

        foreach (var typeInfo in persistentTypes) {

            systemRole.CreateTypePermission(typeInfo.Type,  defaultAllowValues);

        }

    }

    public static SecuritySystemTypePermissionObject CreateTypePermission(this SecuritySystemRole systemRole, Type targetType, bool defaultAllowValues = true) {

        var permission = systemRole.CreateTypePermission(targetType);

        permission.TargetType = targetType;

        permission.AllowDelete = defaultAllowValues;

        permission.AllowNavigate = defaultAllowValues;

        permission.AllowRead = defaultAllowValues;

        permission.AllowWrite = defaultAllowValues;

        permission.AllowCreate = defaultAllowValues;

        return permission;

    }

  4. Invoke the CreateFullPermissionAttributes form the roles you want to apply inside the ModuleUpdater’s

    public override void UpdateDatabaseAfterUpdateSchema() {

        base.UpdateDatabaseAfterUpdateSchema();

        var employersRole = ObjectSpace.GetRole<SecuritySystemRole>("Employers");

        employersRole.CreateFullPermissionAttributes();

Permission Behavior policy

A common policy for an application is a “settings” policy. Which really means that for certain roles like the employee role there should be limited access to objects that store “settings” data. To implement this we can follow the follow steps

  1. Define an attribute to decorate our objects as in previous step. This time we do not know the policy name (settings) so we design this as an Enum parameter in the ctor.

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]

    public class PermissionBehaviorAttribute : Attribute {

        readonly string _name;

     

        public PermissionBehaviorAttribute(object @enum) {

            if (!@enum.GetType().IsEnum)

                throw new NotImplementedException();

            _name = Enum.GetName(@enum.GetType(), @enum);

        }

     

        public PermissionBehaviorAttribute(string name) {

            _name = name;

        }

     

        public string Name {

            get { return _name; }

        }

    }

     

  2. Design an enumeration to hold all possible security policies

    public enum PermissionBehavior {

        Admin,

        Settings,

        ReadOnlyAccess

    }

     

  3. Decorate related objects

    [PermissionBehavior(PermissionBehavior.ReadOnlyAccess)]

    public class Language : VideoRentalBaseObject {

  4. Create a method to describe the ReadOnlyAccess permission policy inside ModuleUpdater.

    public class Updater : ModuleUpdater {

        void ReadOnlyAccesPermissionBehaviour(SecuritySystemRole securitySystemRole, ITypeInfo typeInfo) {

            securitySystemRole.SetTypePermissions(typeInfo.Type, SecurityOperations.ReadOnlyAccess, SecuritySystemModifier.Allow);

        }

  5. With the use of XAF’s sub types info API write an abstract algorithm that will enumerate all domain objects and invoke a delegate with same parameters as the method in step 4

    public static void CreatePermissionBehaviour(this SecuritySystemRole systemRole, Enum behaviourEnum, Action<SecuritySystemRole, ITypeInfo> action) {

        var typeInfos = XafTypesInfo.Instance.PersistentTypes.Where(info => {

            var permissionBehaviorAttribute = info.FindAttribute<PermissionBehaviorAttribute>();

            return permissionBehaviorAttribute != null && permissionBehaviorAttribute.Name.Equals(Enum.GetName(behaviourEnum.GetType(), behaviourEnum));

        });

        foreach (var typeInfo in typeInfos) {

            action.Invoke(systemRole, typeInfo);

        }

    }

     

  6. Invoke the CreatePermissionBehaviour inside the ModulerUpdater feeding it with the ReadOnlyAccesPermissionBehaviour method of step 4

    employersRole.CreatePermissionBehaviour(PermissionBehavior.ReadOnlyAccess, ReadOnlyAccesPermissionBehaviour);

In this post we created reusable algorithms from any XAF projects to help us speeding up the configuration of the initial permissions. When of course talking about code reusability we talk about money saving!

P.S. In a real world application the above coding will be converted to a permission matrix UI representation like,
image

We would appreciate your feedback on this post. Has it been useful to you? Feel free to contact us with any further questions

Next post will be about what else? its model time!

Happy XAFing as always.

Subscribe to XAF feed
Subscribe to community feed

DiggIt!

0 comments:

Post a Comment