Most applications deal with security in a functional way. This means that a business application typically defines different functional roles which are mapped to different users. For example let’s look on a simple Ordering System. In an Ordering System we will have roles like
- ‘Order-Creator‘ – creating the order
- ‘Order-Approver‘ – validating and approving
- ‘Order-Executor‘ – execution
These roles are typical for such an business application and mostly tightly coupled to the corresponding business methods – e.g. createOrder(), approveOrder() and executeOrder(). This works well in a monolithic business application where we can control the security layers as also the business logic. But as more complex the business application becomes, also the enclosed security becomes more complicated. For modern application design in addition we often have to deal with external web services and business logic which need to be adapted easily to changing requirements. So this static security model leads into a hell of hard coded business rules or, what is worse, can no longer guarantee the security.
Using a Workflow Engine
Using a workflow engine offers manifold opportunities to solve such a situation in a model driven way. I will show this on the example of Imixs-Workflow, which is an open source human centric BPM engine. Human-centric business process management means to support human skills and activities by a task orientated approach. The mapping between a function and a business role is done by the workflow model. So the business functions will be decoupled from the business process and can be designed in a more flexible way.
Create a Business Model
First of all we need to create a business model. Most workflow engines support the BPMN standard 2.0 (Business Process Model and Notation). With BPMN we can describe the different phases of our business process life-cycle:
This business model can be created using the Eclipse based modelling Tool Imixs-BPMN.
Definition of Business Roles
Now the important difference when modelling a business process is that we need to abstract the business roles. This is to ensure that we can decouple the business model from the functional programming. In our example this means that we define logical business roles which are mapped to the real world persons involved into the process. So let’s assume that our enterprise has the following departments:
- Sales Department – creating orders
- Management – approving orders
- Finance Department – executing orders
These are the roles our business model has to deal with. With Imixs-BPMN the roles can be mapped directly into the process model:
In this example the roles are mapped to three different person groups which can change later during runtime. The person groups can be managed by the workflow system itself or by an external directory (e.g. LDAP).
The Access Control List (ACL)
Now as we have defined our business roles we can map the roles to different tasks of our process model. Imixs-Workflow defines an ACL setting for each task a process instance can be assigned to:
The ACL of a process instance differentiates the following roles:
- Owner – the responsible person of the process instance
- Read Access – a reader can access the process instance
- Write Access – an author can update the process instance
In our example above the ACL for the Task ‘Approve Order‘ grants a write access the Management department but only a read access to the Sales Department. The Finance Department is not yet allowed to access the task.
So a person which has no read access to a process instance (Finance Department) will be unable to search or access this instance. A person having write access (Management) will be allowed to process the current task. In addition an Owner will be assigned to the process instance so these persons will see the workitem in a personal tasklist.
To complete our example, we can now design the following responsibilities for our process:
- Sales Team -> create an Order
- Management -> approves an Order
- Finance Department -> executes the Order
These roles are now no longer granted on a functional level, but on the level of the business object (the process instance) which is managed by the workflow engine. This means that each process instance can have an individual ACL setting. The example model can be downloaded from here.
Calling the Workflow Engine
Still we have no mapping between our ordering application and the ordering process. So now it’s time to bring the workflow into our business application.
The Imixs-Workflow engine can either be embedded into the code or called via a rest service API. The following example shows how to call the order-process using the embedded engine. The Imixs-JSF Sample application gives a excellent overview how to use this application as an template for custom projects.
Create a new Process Instance
First of all we need to create a new instance of our order-process which can be done in the createOrder() method. Imixs-Workflow provides a generic value object holding business- and process-data. This object can be provided with the order data and information about the process model to create a new order instance:
@EJB private org.imixs.workflow.jee.ejb.WorkflowService workflowService; .... public String createOrder() { // create a new order item ItemCollection order=new ItemCollection(); order.replaceItemValue("order-no","47-43"); order.replaceItemValue("price",new Double(40)); // assign the process model order.replaceItemValue("$processID",1000); // create order order.replaceItemValue("$modelversion","order-model-1.0.0"); order.replaceItemValue("$activityID",10); // forward to management order =getWorkflowService().processWorkItem(order); // get id return order.getUniqueID(); }
In this example we create a order-item with an order-no and a price. Next we assign the model-version and the initial task-id and call the event ‘forward‘ from our process model. The workflow engine will create a new process instance applying the ACL settings defined by the model. Finally the engine returns an order object containing a unique-id to be used to access the order-item later
Update the Process Instance
The workflow engine will automatically control the ACL of our order-item and stores the data together with processing information into a database. We can check the status of the new process instance by requesting the process instance and testing different workflow attributes managed by the workflow engine. Finally we can update the process instance by calling the next ‘forward‘ event:
public void approveOrder(String orderID) { // load order... ItemCollection order = getWorkflowService().getWorkItem(orderID); if (order != null) { // check the new order process instance.... String status = order.getItemValueString("txtworkflowstatus"); // returns the new status int taskID = order.getItemValueInteger("$processid"); // returns the current TaskID List writeAccess = order.getItemValue("$writeaccess"); // returns a list of all users with write access // check if current user has author access? if (order.getItemValueBoolean("$isauthor")) { // we can process the data order.replaceItemValue("$activityID", 10); // forward to accounting order = getWorkflowService().processWorkItem(order); // update ordering system.... } else { // current user is not allowed to read this instance! } } }
This example illustrates how the process data of our order instance can be used to verify the status and ACL for further processing. If the user is not allowed to read the order-item the method will return immediately. If the user is not granted to update the process instance an AccessDeniedException will be thrown by the workflow engine. Finally we forward the process instance to the Finance Department.
Conclusion
With the approach of a workflow engine we can decouple our business logic from hard coded security roles. The important part here is, that we do no longer need to assign a security role with methods into the code. Instead we create a process instance managed by a workflow engine. The security is modeled in a BPMN process model and can be adapted easily to new requirements without the need to change the business functions. Instead that we secure our business methods by hard coded functional roles, we now secure our business objects. This is a powerful concept which extends the behavior of a business application and can bear also complex business logic.