Auditing Liferay DXP: Who has done what and when?

AVISO: Este blog está en Inglés. Accede aquí para leerlo en Español.

There are several occasions when a customer has asked us, once an action has taken place on the Portal (more or less dramatic), how to see when that action was carried out and, above all, who carried it out.

To help us in these scenarios, Liferay DXP provides  Audit.


What is Audit?

Audit is a feature available within Liferay DXP through which we can record events carried out on entities in Liferay. These entities can be specific to the product or custom (using Service Builder for its development).

What kind of actions does it allow us to audit?

We will be able to audit any type of action that is carried out on the entities of our Liferay DXP instance, such as actions for adding, updating, deleting, logging ... From these actions we will be able to obtain the user who performed it, the resource on which it was executed, the type of action, IP, execution date, sessionId, among others.

Where in Liferay DXP is used?

One of the many uses of Audit is in Liferay DXP 7.2 out-of-the-box to audit User and UserGroup entities.

In a Liferay DXP 7.2 installation, accessing Control Panel> Configuration> Audit, you will be able to see the audited actions.
An advanced search form to filter our results is available:

An advanced search form to filter our results is available:

How does it work?

The hook point between Audit and the entities that we want to be audited is done through the implementation of a ModelListener interface. In our class, the onBefore<Action> and onAfter<Action> methods need to be implemented. These methods are called before or after the persistence layer call. It’s in the implementation of these methods where we will make use of the Audit API, where we will build a message and route it. To route these messages, by default, we have a router called DefaultAuditRouter that implements the AuditRouter interface, which performs the dumping of log files of the events audited or persisted in the database. Both the dumping to log files, as the output by console or persistence in the database is configurable from the Control Panel in the Audit section. Like everything in the Liferay World, this is completely adaptable and extensible, so we can create our own processors and router in order to adapt it to the most demanding needs.

What examples can we see that may make sense to audit?

A very common case is the audited deletion of pages on a website. For example, we could use Audit to record when and who has deleted a Homepage (or main page) from a website, notifying us of the action by email and saving that evidence record in a database. In addition, we will dump it into a log file that we can index using ElasticSearch and manage from Kibana. For this case, I have developed the following OSGi module that will audit the adding, updating and deletion of a website pages.

When a page is added, the following fields are registered: all the properties of the event (when it was added, who added it), those indicated in the construction of the message and a series of fields that I have decided relevant to audit:groupName, groupId, name , friendlyURL and layoutId.

When a page is updated, the following fields are registered: all the properties of the event (it registers when the action was performed and who performed it), those indicated in the construction of the message, but this time I have decided to only register this update when one of the following properties have been modified: name and friendlyURL. Therefore, if a page is modified, for example by adding an SEO property, this action will not be registered as an update in Audit.

When a page is deleted, the deletion of the page and the entity properties that I have decided to audit are recorded. Also, if the page is the Website Home page, a notification email will be sent.

Another case could be to audit the deletion of Web Contents. These have embedded a complete versioning system. Also, the recycle bin framework is available in this entity to reverse deletion actions. But if we want to have that exhaustive record of who definitively deleted those web contents and when, there would be a possible way of doing it. For this case, I have developed the following OSGi component that will audit the action of moving web contents to the recycle bin, in addition to deleting them.

Like Web Contents, Documents created in Documents and Media have version control and the recycle bin feature, but it might be interesting to audit deletion actions on a specific type of document. For this entity, I have developed the following OSGi module where in the case of sending an item to the recycle bin or permanently deleting a document of type myCustomDLEntryType, such action is registered using Audit.

Where do I configure Audit?

In Control Panel > Configuration > System Settings > Audit we can configure everything related to Audit: activate / deactivate it, configuration related to the LoggingProcessor and the formatter used (CSV or JSON), decide which columns we want to dump, print it on the console, persist the events in database, etc.

In my case, I have configured Audit, with database persistence as well as log dump with CSV format and without console output:

But also I have configured Log4j to dump the INFO traces to the log [LIFERAY_HOME]/logs/audit.yyyy-MM-dd.log with the class

For this I have created the following XML: [LIFERAY_HOME]/tomcat-[version]/webapps/ROOT/WEB-INF/classes/META-INF/portal-log4j-ext.xml

Next, I have configured the ELK stack (ElasticSearch, Logstash and Kibana) in order to index and consult the logs dumped at [LIFERAY_HOME] /logs/audit.*. In this way I can audit the system from outside Liferay DXP and create a history of monitoring, graphics, etc.

It's interesting, but... everything is better with control

In the case of having persistence in the database enabled, the events audited can end up generating an AuditEvent table in Liferay of unmanageable size, so it is recommended to establish some control over it. What records to keep will be a decision to evaluate for each specific case, depending on the volume that can be reached and how important it is to store those records in the database.

As a solution to keeping the table of events audited under control, a scheduler entry could be used to periodically clear the table according to the creation date of those events. For this specific case, I have developed the following scheduler that runs every 3 months and will delete the records with a creation date prior to 3 months, always leaving a history of the last 3 months in order to consult a recent history.

In the case of maintaining the log dump, it is recommended to maintain an adequate log rotation system with which to control disk space. Also, if you choose the option of indexing them in ElasticSearch, it is recommended to keep a history of these indexes under control. For this, we can rely on the use of the ElasticSearch-Curator utility in order to delete the indexes of a certain pattern and execute that deletion using a crontab appropriate to the history that we want to keep.


Everything has a price: performance

The Audit system is nothing more than persistence to the database and access + writing to log files, with the consumption of resources that these actions generally entail.

Although log dumping and database persistence of audited events can be performed at the same time, it is usually recommended to do one of the two mechanisms, in order to consume less resources. In addition, it is recommended to run performance tests in order to verify that the System does not suffer from an excessive performance degradation due to uncontrolled auditing.

Like the processors called by the router that includes Liferay DXP 7.2 by default, LoggingAuditMessageProcessor and PersistentAuditMessageProcessor, are configurable from the Control Panel, both for their activation / deactivation and to configure their properties, it is recommended to apply activation / deactivation mechanisms to our MessageProcessors or even the actions that can be triggered from the Listener in order to be able to activate / deactivate the audit procedures if necessary.

In the case of the development made to audit the pages, I have implemented an activation / deactivation mechanism in order to completely disable the auditee that the Listener performs, even deactivating the sending by mail and the log / persistence dump based on data (regardless of whether the option is enabled for each of them in Control Panel)

To Conclude:

Liferay DXP gives us out-of-the-box the powerful functionality to record all actions on entities, both product and custom.

The way to audit our entities, in addition to the processing of audit messages, will depend completely on each case, but taking into account these bases, virtually any solution will be possible.