Security in On-line shop? That’s easy!

XAF Team Blog
24 May 2013

There are many reasons why Security is a necessity when developing even the simplest online shop backend. Instead of listing them all I will concentrate on how to empower the application prototype we created for our DXSK8 e-shop with a flexible Security System.

You may recall that in the previous post we applied a XAF layer(rich application) over an EF model located in an external lib (DSK8.Service). Now we will extend the same EF model to support XAF’s Security System.

1) Designing an Entity Framework Model for Security System objects.

XAF’s Security system uses Users, Roles and Permissions to configure both data access and UI generation for both platforms! This is done with the help of several system interfaces such as :
User: ISecurityUser, IAuthenticationStandardUser, IOperationPermissionProvider
Role:, IOperationPermissionProvider.

Our EF model from the DXSK8.Service project already contains an Employee entity, which is just perfect for taking on the role of XAF’s system user. We begin by adding all public properties of the user depended interfaces to our Employee entity. XAF interfaces are well designed and there are only three as you see below. The UserName in the black frame already existed in our Login entity, it’s not in the Employee entity with the rest of the new fields. XAF has no problems understand it as is!

image

The next step is to design the Roles and Permissions objects. While XAF supports member level and criteria based systems as well, I will utilize the Type Permission system in this case. I only need the Roles and TypePermissionObject entities listed below.

image

Be sure to follow the database migration steps detailed by EF. For the purposes of this blog I followed a standard technic described in Code First Migrations. 

Note that we must use partial classes to implement the consumed interfaces this implementation simple and can be reusable, for example let’s see how easy it is to implement the Employee interfaces. For Role, TypePermissionObject implementation please check sample at the end of the post (See also How to: Implement Custom Security Objects (Users, Roles, Operation Permissions))).

[ImageName("BO_User"), DefaultProperty("UserName")]

public partial class Employee : ISecurityUserIAuthenticationStandardUser,

                                IOperationPermissionProvider {

 

    #region IOperationPermissionProvider

    IEnumerable<IOperationPermissionProvider> IOperationPermissionProvider.GetChildren() {

        if (!Roles.IsLoaded) {

            Roles.Load();

        }

        return new EnumerableConverter<IOperationPermissionProvider, Role>(Roles);

    }

 

    IEnumerable<IOperationPermission> IOperationPermissionProvider.GetPermissions() {

        return new IOperationPermission[0];

    }

    #endregion

    #region ISecurityUser

    Boolean ISecurityUser.IsActive {

        get { return IsActive.HasValue && IsActive.Value; }

    }

 

    String ISecurityUser.UserName {

        get { return UserName; }

    }

    #endregion

 

    #region IAuthenticationStandardUser

    Boolean IAuthenticationStandardUser.ComparePassword(String password) {

        var passwordCryptographer = new PasswordCryptographer();

        return passwordCryptographer.AreEqual(StoredPassword, password);

    }

 

    public void SetPassword(String password) {

        var passwordCryptographer = new PasswordCryptographer();

        StoredPassword = passwordCryptographer.GenerateSaltedPassword(password);

    }

 

    Boolean IAuthenticationStandardUser.ChangePasswordOnFirstLogon {

        get { return ChangePasswordOnFirstLogon.HasValue && ChangePasswordOnFirstLogon.Value; }

        set { ChangePasswordOnFirstLogon = value; }

    }

 

    String IAuthenticationStandardUser.UserName {

        get { return UserName; }

    }

    #endregion

 

}

2)  Installing a XAF Security System

Although XAF has strong design time support I will go through this step using one line of code in both Program.cs and Global.asax.cs just before application.Setup() call.

application.Security = new SecurityStrategyComplex(typeof(DXSK8.Service.Employee), typeof(DXSK8.Service.Role), new AuthenticationStandard());

application.Setup();

The snippet above will assist you with applying a security strategy using the Entity Framework entities located in the external DXSk8.Service lib . For this type of security strategy XAF spares our time as usual and will automatically display a customizable credentials window for both win and web platforms as shown,

 

image

image

 

In addition XAF detects the custom Security EF Entities we designed in step 1 and automatically populates the navigation menu.

 

Win
image
Web
image
   

 

3) Supplying initial data

It is absolutely imperative that someone working on your project is assigned the security password. In addition, a user with admin privileges must also be assigned. Use the XafApplication’s CustomCheckCompatibility event inside our platform agnostic module to assign these admin priviledges.

 

public override void Setup(XafApplication application) {

    base.Setup(application);

    application.CustomCheckCompatibility+=ApplicationOnCustomCheckCompatibility;

    application.CreateCustomObjectSpaceProvider += ApplicationOnCreateCustomObjectSpaceProvider;

}

 

void ApplicationOnCustomCheckCompatibility(object sender, CustomCheckCompatibilityEventArgs e) {

    var objectSpace = e.ObjectSpaceProvider.CreateUpdatingObjectSpace(true);

    var updater = new Updater(objectSpace, Version.Parse("1.0.0.0"));

    updater.UpdateDatabaseAfterUpdateSchema();

}

and the UpdateDatabaseAfterUpdateSchema where we created:
a) A Content Manager role with CRUD on Product but ReadOnly on Orders/Employees

b) A Sales Manager role wirh CRUD on Order but ReadOnly on Product/Employees

public override void UpdateDatabaseAfterUpdateSchema() {

    base.UpdateDatabaseAfterUpdateSchema();

    if (ObjectSpace.FindObject<Employee>(CriteriaOperator.Parse("UserName=?","Admin")) == null) {

        var roleAndUser = CreateRoleAndUser("Admin");

        roleAndUser.IsAdministrative = true;

        CreateRole("Content Manager", new[]{

            CRUDPermission(typeof(Product)),

            ReadOnlyPermission(typeof(Order)),

            ReadOnlyPermission(typeof(Employee))

        });

 

        CreateRole("Sales Manager", new[]{

            CRUDPermission(typeof(Order)),

            ReadOnlyPermission(typeof(Product)),

            ReadOnlyPermission(typeof(Employee))

        });

 

        var employees = ObjectSpace.GetObjects<Employee>();

        foreach (var employee in employees) {

            employee.IsActive = true;

            employee.ChangePasswordOnFirstLogon = true;

        }

 

        ObjectSpace.CommitChanges();

    }

}

Use this post’s sample to explore the implementation of the remaining methods, which happens to be rather simple.

 

The remainder of the project needs a business user to simply associate Employees with Roles using XAF’s well thought-out UI. For example, the next two screenshots illustrate how to assign a Content Manager Role to a list of users.

 

image

image

Conclusion

There are many difficulties and complexities when it comes to addressing business problems with technology. And that’s exactly why tools like XAF, which bridge business and technology are such a life saver. You just witness just how simple it was to integrate a complex and sensitive feature like security while working with EF as datalayer. Thanks to the flexible and well-designed XAF, your product can now be marketed more easily since it features a complete security system.

I close this time with a phrase I often hear from our customers :

XAF really works!

Download a sample from here and attach the mdf file found in the DXSK8.Service/App_Data folder to your SQL instance. Be sure to visit How to: Get Started with the Entity Framework Model First in XAF for coverage of the basics.

.

1 comment(s)
Willem de Vries
Willem de Vries

Please update this great post with XPO instead of EF!

9 July, 2013

Please login or register to post comments.