Secure-Critical User Control Mechanisms
In many business areas an increased need for safety and control of business processes executed by human actors can be observed. Humans are by nature error-prone and make mistakes. Human activities, ranging from simple scenarios, such as manual approval to complex scenarios involving complicated entry of sensitive data are subject to failure, misunderstandings, typos and incorrect data. But a business can come into trouble not only by unintended errors introduced by human beings; also intentional misuse and internal fraud can produce a lot of damage and is often hard to track.
Common Control Mechanisms
In many business areas an increased need for safety and control of business processes executed by human actors can be observed. Humans are by nature error-prone and make mistakes. Human activities, ranging from simple scenarios, such as manual approval to complex scenarios involving complicated entry of sensitive data are subject to failure, misunderstandings, typos and incorrect data. But a business can come into trouble not only by unintended errors introduced by human beings; also intentional misuse and internal fraud can produce a lot of damage and is often hard to track.
Besides from organizational and structural preventions an application can be hardened in itself against human failures and fraud initiated by internal staff members. The essential basic feature that should be implemented in all sensitive applications is authentication of users by a login process.
Audit and State Archiving
One approach to better control the usage of an application is to keep track on processes and the status of domain objects. This is more than a pure simple logging of events that is done in many applications by integrating common logging frameworks like log4j or the Java logging API. What is meant here is audit-logging or archiving of events. In some countries or businesses even legal requirements exist to keep audit tracks which are to be stored in a prescribed secure and revision-safe mode. This requirement implies that archive records could not be modified, deleted or added. Integration of auditing and archiving functionalities should answer questions like
- what was the type of the event (calling a service, starting a business process, modifying a domain object, deleting an object, etc.)
- who effected the event
- when did the event took place
- how did the status of the system change
- and sometimes, why did a user perform the action
Even though fraud attempts could not be prevented by audit tracking the knowledge that all actions are recorded builds a psychological barrier towards potential malefactors. As all action details and system status are archived it is even possible to restore old states or undo a harmful action.
Authorisation
Another measure to reduce errors and fraud is to introduce an authorization scheme which limits the rights of users to exactly the tasks they are supposed to work on. An authorization scheme is commonly achieved by defining permissions on resources like processes, URLs and domain objects, bundle theses permissions into profiles and groups and assign users to groups and profiles. The Java authentication and authorization service (JAAS) and Spring security are examples for frameworks providing authentication and authorization functionality.
Four-eyes Principle
One step further to increase control in an application is to introduce a dual control mechanism like four-eyes principle. With this control scheme in action a business case will not be executed directly in the productive environment. Instead, the action is stored and postponed. Only if a second user accepts and releases the action, it is performed in the productive system. If the second user rejects the action it will not be executed. Figure 1 shows the workflow of a four-eyes process.
Figure 1: Four-eyes principle
- A user executes a business case. This is often a persistence action on a domain object, but could also be a service call.
- The action is suspended. All necessary data to perform the business case are cached.
- A second user enters a screen to display suspended unreleased business cases.
- Data of suspended unreleased business cases are searched in the cache and displayed. The user can exactly see what the first user wanted to do.
- The second user checks the data and decides to release or reject the action.
- If he releases the action the business case is executed in the productive environment
- Finally, the cached data are removed.
There are a couple of rules to apply like the following:
- the two users must be different
- first user cannot release
- if first user rejects the action, the business case will be discarded
- if second user releases the action the business case will be executed
- if second user rejects the action the business case will be discarded
Six-eyes Principle
An even stricter example for a dual control scheme is the six-eyes principle. In this case a third user must approve a business case before it will be executed in the productive environment. Like in four-eyes principle rules are applied which define which user is allowed to release and reject and what happens on a release.
Two-man Rule
This is another dual control scheme. Like in four-eyes principle two people must agree on a business process to execute it. While in four-eyes principle the initiation and the release action are two system events at different points in time, in two-man rule control scheme it is one system event. There is no differentiation between initiator and releaser of a business case. Two authorized people must be present and agree on a business case. A prominent example of this control scheme is the launch control of nuclear weapons: Two officers must authorize the launch with their personnel keys at the same time.
In the following I will show how control schemes like dual control and state archiving can be integrated into an existing application. I use the open source framework Cibet for this purpose which provides a plugin infrastructure to include controllers into an application.
An example application without control
The example application is of limited functionality and basic web layout but it contains all features to demonstrate complex controlling situations. Sources can be downloaded from the Cibet web page. It is a Tapestry web application with server side logic implemented in plain Java and Java EE using embedded OpenEJB as EJB container. Database access is accomplished using standard JPA API with Hibernate as implementation. The application has been run on a Tomcat application server and in a Jetty servlet container.
The application provides functionality for a purchase department of a perfumery shop. The shop sells perfumes which have a selling price and a type. The purchase department orders perfumes for the shop’s stock from perfume suppliers. The suppliers have a name, an address and perfume offerings with purchase prices. Each supplier has its own set of perfumes to offer. The user of the purchase department can send orders to suppliers in order to purchase perfumes and fill up the stock. An order can have several order items. The major domain objects and their relations are depicted in Figure 2.
Figure2: class diagram
As can be seen the domain objects have some transitive dependencies in order to show that the presented solution can deal with complex object structures.
The application is multi-tenant capable. That means the same application instance can be hosted for multiple perfumery companies which have individual web layout and own separated data. The companies may have different perfumes in their shops and they have their own suppliers. While data and layout are different the overall functionality is the same.
At the beginning the only control mechanism that the application provides is user authentication by a login. After login the application can be navigated by a menu with one menu item for each of the three main domain objects: Perfumes, Suppliers and Orders. The Perfumes page shows only the overall existing perfumes with no further business logic. The Suppliers menu item displays the actual suppliers on the left side and their respective offers on the right side (Figure 3). The following business cases can be executed:
- Create a new Supplier
- Edit a supplier
- Delete a supplier
Figure3: Suppliers web page
The Orders menu item navigates to a page displaying the orders on the left side and the respective order items on the right side (Figure 4). The only business case which can be executed here is to create a new order.
Figure 4: Orders web page
The create and delete supplier business cases are executed in a Java SE service, the update supplier and create new order are executed in a Java EE EJB service. Of cause it is not the usual way of designing server side logic with such heterogeneous technology but I want to show how control mechanisms are applied in both worlds, Java SE and Java EE.
The create, update and delete supplier business functions are simple database operations. The entities are inserted, updated or deleted in the database without any additional logic. The create order business case however is more complex. It inserts an order and its items in the database but additionally creates a file with the order and order item details which is sent to the supplier. It is therefore not sufficient to control only the database action but the whole service call must be set under control.
Making the application control-aware
I want to enhance this application now and make it control-aware by integrating the Cibet control framework. Control awareness means that the application contains a sensor which detects events and is ready to react according to applied control mechanisms. The effective controllers can then be configured later on. The necessary modifications to the application are surprisingly simple. Cibet is a rather non-intrusive framework.
There are just only three things to do to make the application control-aware:
- Tell Cibet the actual user and tenant id and the EntityManager instance that is used
- exchange the container provided EntityManager against an instance of CibetEntityManager
- define CibetInterceptor as interceptor class for EJB calls
Cibet uses a thread-safe context to access application data. The application must supply all data that are necessary for the controllers to this CibetContext object. This is at least the unique user id and the original EntityManager instance to perform persistence actions. In a multi-tenant application also the unique tenant or owner id must be set. These data are normally available after successful login. (Listing 1)
Listing1: setting user, owner and EntityManager into the context after successful login (Index.java)
Object onSuccess() {
String user = getLoginCredentials().getUsername();
CibetContext.setUserId(user);
setLocalEM(InitService.getEmFactory().createEntityManager());
CibetContext.setEntityManager(getLocalEM());
if ("Hugo".equals(user)
|| "Harry".equals(user)
|| "Herman".equals(user)) {
CibetContext.setOwner("Goudlas");
} else if ("Amy".equals(getLoginCredentials().getUsername())
|| "Anne".equals(getLoginCredentials().getUsername())
|| "Arabella".equals(getLoginCredentials().getUsername())) {
CibetContext.setOwner("Rives Yocher");
} else {
loginForm.recordError("Allowed users are: "
+ "Hugo, Harry, Herman [Goudlas] and "
+ "Amy, Anne, Arabella [Rives Yocher]");
return null;
}
}
The example application does not have a real user management; the users and their mappings to companies are hard-coded. The Java SE EntityManager is created from a bootstrap EntityManagerFactory in the InitService class.
Each http request may create a new thread, so CibetContext must be set on each new request. This can be easily achieved in a non-intrusive way by defining the following servlet filter in web.xml (Listing 2)
Listing2: setting user, owner and EntityManager in a servlet filter (CibetFiler.java)
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpSession session = ((HttpServletRequest) request).getSession();
EntityManager em = (EntityManager) session
.getAttribute("sso:javax.persistence.EntityManager");
if (em != null) {
CibetContext.setEntityManager(em);
}
LoginCredentials cred = (LoginCredentials) session.getAttribute(
"sso:com.logitags.perfumery.entities.LoginCredentials");
if (cred != null) {
if (cred.getCompany() != null) {
CibetContext.setOwner(cred.getCompany());
}
CibetContext.setUserId(cred.getUsername());
}
chain.doFilter(request, response);
}
In a Java EE environment the EntityManager is not created from the bootstrap Persistence class but is container managed and injected. Here we must use another technique to set it into CibetContext. One possibility is to use an interceptor (Listing 3).
Listing3: Using an interceptor class to set the EntityManager (SupplierServiceEJB.java)
@Stateless
@Local(SupplierService.class)
@Interceptors( { EJBPersistenceUnitInjector.class })
public class SupplierServiceEJB implements SupplierService, BaseEJBInterface {
@PersistenceContext(unitName = "perfumesDB_EJB")
private EntityManager eman;
public EntityManager getEntityMananger() {
return eman;
}
…
}
The EJB implements interface BaseEJBInterface which declares only one getter method which returns the managed EntityManager instance. In the injector class this EntityManager instance is set into the CibetContext (Listing 4).
Listing4: Setting the EntityManager in an interceptor class (EJBPersistenceUnitInjector.java)
@AroundInvoke
public Object inject(InvocationContext ctx) throws Exception {
BaseEJBInterface ejb = (BaseEJBInterface) ctx.getTarget();
CibetContext.setEntityManager(ejb.getEntityMananger());
return ctx.proceed();
}
The next step is to exchange the standard provided EntityManager instance used in persistence actions against an instance of CibetEntityManager. The EntityManager is initiated at a central place in class InitService. All classes that need an EntityManager call the getEntityManager() method. So only one line of code has to be changed (Listing 5).
Listing5: Setting CibetEntityManager for persistence actions (InitService.java)
public static void init() {
emFactory = Persistence.createEntityManagerFactory("perfumesDB");
}
public static EntityManager getEntityManager() {
// return emFactory.createEntityManager();
return new CibetEntityManager();
}
The exchanged CibetEntityManager can throw some new RuntimeExceptions which must be caught. For example, one rule applied by Cibet is that an object under dual control which has been modified but not yet released cannot be removed or modified a second time. If Cibet detects this situation an UnapprovedEntityException will be thrown (Listing 6). As all exceptions thrown by Cibet are RuntimeExceptions they can also be caught in a central Exception handler.
Listing6: catching UnapprovedEntityException (SupplierServiceImpl.java)
public void delete(long id) {
EntityManager em = InitService.getEntityManager();
em.getTransaction().begin();
Supplier s = em.find(Supplier.class, id);
try {
em.remove(s);
em.getTransaction().commit();
} catch (UnapprovedEntityException e) {
log.error(e.getMessage(), e);
em.getTransaction().rollback();
throw e;
}
}
The last thing to do is to make EJB service calls control-aware. Cibet offers an interceptor class which will do the job. I just add CibetInterceptor to the OrderServiceEJB class and I am done (Listing 7)
Listing7: Using CibetInterceptor to control EJB service calls (OrderServiceEJB.java)
@Stateless
@Local(OrderService.class)
@Interceptors( { EJBPersistenceUnitInjector.class, CibetInterceptor.class })
public class OrderServiceEJB implements OrderService, BaseEJBInterface {
…
}
Configuration
Now the application is susceptible to applied control schemes, but up to now the behavior will be the same as before because we have not yet defined any controllers. We have to configure which controllers we want to apply to which domain objects and business cases. There are two possibilities to do this. The simpler one is to define configuration in an xml file which will be read in by the Cibet framework. You can read in the documentation about this approach. I want to have it a little bit more comfortable, so I use the configuration API and create a form to change configuration online (Figure 5). I don’t want to go too deep into the code; it is mostly just Tapestry form handling stuff. Cibet configuration is set with the ConfigurationManager.configure(…) methods.
Figure5: Defining controllers for business cases
New business cases
In Figure 5 we have defined that the creation of a new supplier should be under four-eyes control and supplier and order states be archived when inserting and updating or creating a new order. Fine, it works: When we insert now a new supplier, it will not be visible in the list of active suppliers afterwards (Figure 3) and the states of supplier and order will be archived. But the application is not quit useful without adding some new business cases. The minimum is a form to release or reject four-eyes business cases and maybe we want to display and analyze the archive. These are new use cases which depend on the applied controllers and requirements of the application. Cibet provides an API to search, release and reject suspended business cases and to search and manage archives. The corresponding web interfaces must be developed individually per application.
In the example application I added an archive list and archive details form (Figure 6, Figure 7). In the details form you can see all the metadata which are stored together with the business case state. In the lower part the details of the created order are displayed.
Figure 6: Archive list form
Figure7: Archive details form
For the dual control schemes I added a form to list unreleased business cases (Figure 8) and a form for the details and to release or reject the action (Figure 9). In the details form the metadata can be seen which are stored together with the business case state and in the lower part the supplier data and his offers. The user can add a remark when he releases or rejects the business case.
Figure8: unreleased business cases form
Figure9: details of unreleased business cases form
Summary
With the Cibet control framework it is very easy to integrate control mechanisms even into an existing application. If the application has a login mechanism and a central EntityManager handling only a few lines of code must be added. The example application has been built with Cibet version 0.5.1. In version 0.7 the Cibet framework has been refactored and is based on common fundamentals of control theory which describes controlling the behavior of dynamical systems in engineering and mathematics. I will show in a later article how principles of control theory are applied to modern software development.
About the author
Dr. Wolfgang Winter is an architect and system analyst at Atos Worldline GmbH, a 100% daughter of Atos Origin S.A. His main focus is server side development on Java EE platform in payment, card and transaction processing. In his spare time he tries to keep his web site about cycling in the South of France up-to-date and publishes open source project Cibet under the label LogiTags.