The Content Server Audit Facility

by Blue Fish Development Group

The Documentum Content Server provides support for auditing events of interest which occur
to objects in the Docbase and to application-specific entities. This article explores the
features of the audit facility, how to configure it, and how to work around some of the
problems using it with DFC.

Auditing is a security feature of the Content Server which provides a permanent record of
“events” which have occurred. An event is either an operation performed on the Docbase
(such as a checkin of a document) or an action within an application (such as executing an
advanced search function in a custom application). The Content Server provides API methods
to manage the registration of events to be audited, to create audit entries for events,
and to remove audit entries. Many, but not all of these features can also be controlled
via the DFC interface IDfAuditTrailManager (we’ll see how to get around
those deficiencies later).

When an audit entry is created, a record is written to the Docbase detailing the event
being audited. This collection of audit records, referred to as an Audit Trail, is essential
to providing accountability for actions. It records in detail which operations were executed
by which users against which objects. In addition, this historical information can be
used to assess compliance with business rules, statistically track the access and usage patterns
of users to documents, track the state of critical documents, monitor workflows and lifecycles,
or monitor the activity of specific users.

We’ll be referring to several concepts in this article, so let’s define them first.

System Event:
System-recognized actions performed on specific documents, folders, cabinets, or
other objects. Content Server supports a large number of system-defined events, representing
operations such as checkins, promotions, and demotions. Refer to the Audit section of the Content
Server API Reference Manual for tables listing all System Events. Also, Appendix B (System Events)
of the Content Server API Reference provides an exhaustive list of the System Events.

Application Event:
Actions which are not inherently recognized by the Content Server.
Applications decide which of these non-system actions need to support audit and add code to
specifically handle those actions. For example, an application may choose to provide audit
capability for an advanced search function, capturing useful data in the audit such as the
user executing the search and the search parameters.

Event Target:
The primary entity acted upon by an event. Examples of targets for System Events
include specific instances of an object, types of an object, users, groups, policies, methods,
workflows, activites, etc. Application Events have their targets defined by their application.

Audit Event:
An Audit Event is either a System Event or an Application Event. The term Audit Event is introduced
as a generalization for convenience.

Audit Method:
An Audit Method is used to request an audit of a specific event. The arguments to the Audit
Method specify the event to audit, the target of the event, and the names of the attributes
whose values are to be audited. Audit methods can be used to request audits for System Events
or Application Events. A user must have the extended privilege Config Audit in order to invoke
an Audit Method.

Audit Trail:
An Audit Trail is the history of instances of an Audit Event. Each instance of an Audit Event
results in the creation of one Audit Trail entry which stores information about the event (such as
the time of the event, which objects were involved, who performed the actions, and which values were
affected).

Tamper-Evident Auditing:
The Content Server provides the ability to “sign” each Audit Trail entry, which will cause a
cryptographic hash to be computed for the contents of the entry. The hash itself is then encrypted
using the Application Encryption Key (AEK) for the Content Server and stored back in theaudit_signature attribute of the entry. At any point in the future, a client can validate the entry,
which will recompute the hash and compare it to the hash stored in the attribute. Due to the way
hashes work, if any information in the entry has been changed since the original hash was computed,
then the new hash will not match the original, and the client knows that the entry has been tampered.

Granting Extended User Privileges

Before you can do anything related to auditing, you are going to have to grant a user some
special privileges. There are three “extended” user privileges which the Content Server
uses to manage security authorization for audit requests: Config Audit,Purge Audit, and View Audit. The extended privileges are stored
as an integer in the user_xprivileges attribute of the dm_user
object. The following table defines the privileges and their values. Note that multiple
privileges are summed together instead of being hierarchical, so a Purge
Audit privilege does not imply a Config Audit privilege.

Privilege

Description

Integer Value

Config Audit

User can execute the Audit and Unaudit methods to start and stop auditing.

8

Purge Audit

User can remove Audit Trail entries from the Docbase.

16

View Audit

User can view Audit Trail entries.

32

Note:
By default, neither the Docbase owner nor the Superuser have any of these extended permissions. In
addition, only Docbase owners and Superusers may grant/revoke extended user privileges, but they may
not grant or revoke these privileges for themselves.

Granting Audit Privileges Using Documentum Administrator

You can either login to the Documentum Administrator tool as the Docbase owner and grant
the privileges to the Superuser, or login as the Superuser and grant the privileges to the
Docbase owner, or create a new user and grant the privileges to that user. To grant the
privilege in the Documentum Administrator tool, go to the User Management->Users
node in the tree, locate the user in the right hand panel, edit the user’s properties by
clicking on the i, and set the user’s Extended Privileges using the dropdown menu. If
the extended privileges you need are not in the dropdown, then it is easiest to grant the
permissions using DQL (see next section).

Granting Audit Privileges Using DQL

You can grant the privileges in DQL by setting the user_xprivileges attribute
of the dm_user object to an integer value. The value is the sum of the values
corresponding to the extended user privileges defined for the user. For example, to addConfig Audit, Purge Audit, and View Audit
privileges to the user dmadmin:

Registering an Audit

To request that an event be audited, a user must somehow invoke the Audit method. That can be
achieved via Documentum Administrator, a DFC call, or an API call. We’ll show examples of each. For
the example, we will register an audit for all Save events of a custom object vendor_admin,
including any subtypes of vendor_admin. In addition, we’ll want the Audit Trail to include the new
values for the attributes va_name and va_tax_id, which are attributes in thevendor_admin object.
Note that in all cases, the object type and event must be compatible. That is, the object type must
be a valid target of the given event.

Note:
As noted in the Default Auditing section, auditing an event
will result in an Audit Trail entry with the event name dm_audit.

Registering an Audit Via Documentum Administrator

In Documentum Administrator, select the Audit Management node under Administration in the tree. In
the right panel you will see actions to register audits based on the object type, the object
instance, or for all objects in the docbase. Select the action to register based on type. In theStarts With: control, enter “vendor_admin” and click Go. Select the vendor_admin checkbox in the
resulting list and click OK. The next panel has a table at the bottom that shows all the existing
audits registered for the vendor_admin type. You can select any of those and edit or unaudit
them. We want to add a new audit, so click Add Audit in the table header. The next panel allows us to enter
the audit info. Click the Include All Subtypes checkbox, since we want to audit subtypes. Click
the Select Attributes link, locate and select the va_name and va_tax_id attributes, Add them to
the right side of the panel, select the same two attributes from the right side, and click OK. You
should be back to the panel which allows you to enter the audit info. Now click Add in the header
of the event table at the bottom of the panel. Locate and select the “dm_save” event, Add it to
the right side, select it again on the right side and click OK. You should be back to the panel
which allows you to enter the audit info. Make sure it all looks good and click OK. You should
now see the panel which shows all the registered events for the object type and your event should be
in the table. Click OK one final time to get back to the main display.

Registering an Audit Via DFC

In DFC, you will use an instance of IDfAuditTrailManager to register the audit. You can obtain
an instance of IDfAuditTrailManager directly off of any IDfSession by callinggetAuditManager().
Please refer to the javadoc pages for IDfAuditTrailManager for more details on the methods it
supports. The following code snippet demonstrates how to register the example audit:

Registering an Audit Via API

All audit registrations go thru the “audit” API command, which is described in depth in the Content
Server API Reference guide. There are examples there for all the variants you will need to
understand. The syntax for the audit command is:

Note:
This will NOT work for the DM_ALL event (see Content Server API Reference)

In order to audit all instances of an object type, we need to first identify the object
ID of the type’s dm_type object. So, our example requires two steps: one to retrieve the
ID of the type and one to register the audit based on that ID. Note the four empty arguments
in the second step, which are the missing optional values for the controlling app,
the policy ID, the state name, and the authentication.

The Audit Registry

Every time an Audit method is successfully invoked, a new record is recorded in thedmi_registry object. The record stores the details of the audit request,
which are especially useful for managing the audit of Application Events
(see Auditing Application Events).

The Content Server automatically performs audits for several System Events, without any user
having to register an audit. All of the resulting Audit Trail entries are stored indm_audittrail objects. Only the User Login Failure auditing can be disabled.

The following shows the methods/actions which are audited by default and the values stored in theevent_name attribute of their dm_audittrail entries:

After you register the audit for a System Event, then Content Server takes care of creating
the Audit Trail entries when the registered events occur. There is no other work which you
need to do to make that happen.

It the responsibility of the application to know when an Application Event has occurred
and to manage the creation of Audit Trail entries. The recommended approach is that after
an Application Event has occurred, the application should check thedmi_registry to see if auditing is enabled for the Application Event. If it
is, then the application should create Audit Trail entry for the event using API
calls. Using this technique, clients can enable/disable auditing of the Application Event
by creating/destroying the dmi_registry object instead of changing runtime
configuration and/or recompiling the application.

DFC Application Event Bug

If you are auditing Application Events, there appears to be a bug in the DFC IDfAuditTrailManager
class which will prevent you from registering, unregistering, or querying audits on your custom events.
Why is this? For custom app events, there are no dm_type
objects which act as the target. So, you need to pass null for the objectName
parameter to the registration/query methods in IDfAuditTrailManager. Unfortunately, that causes
the methods to blow up with a DfException.

The workaraound is to register your custom events using the API and to query them using a utility
method. Here is how you register a custom event named “my_custom_event” using the API:

API> audit,s0,0,my_custom_event

Here is how you register a custom event named “my_custom_event” in DFC using an IDfSession
to invoke an API call:

This will result in a dmi_registry object being created whoseregistered_id is ‘0000000000000000’ and whose event is
‘my_custom_event’. The registered_id value of ‘0000000000000000’ is special
and will help us to locate the registry object using a DQL select.

Note:
When doing this, you cannot specify any parameters after the event name. That implies you cannot
specify ‘T’ for the sign_audit parameter, which means that Application Events
can not be setup for signing when they are created. If you want to have the Content Server
sign your Application Events, then you should Set and Save the boolean sign_audit
attribute of the dmi_registry record for the audited event.

Now that you have registered the audit event, you need to be able to programmatically check
for its registration when it comes time to create an audit entry for the custom event. To
do that, we write a special method which checks for the existence of a custom audit registration
in the dmi_registry with a matching event name. Here is a simple
version:

Creating Application Event Audit Entries

We can now determine that an Application Event is being audited. The final step is to actually
create the Audit Trail entry for the event. I could not locate any DFC class to help in this
endeavor, so it looks like we are going to have to fall back on an API call invoked through DFC.
The API call available to us is Createaudit (see the Content Server API Reference for
full details). The syntax for the call is:

Notice that the audited_obj_id parameter is required. So, every
audit event has to have a valid object instance which is the target. Also, notice
that the call allows for up to five strings and five IDs to be recorded in the
entry. Applications are free to use these attributes to store whatever info is necessary.
Here is an example of an API call to create an Audit Trail entry for an event named
“advanced_search” which was run by “lsmith” (stored in string_1) and
which returned 731 records (stored in string_2):

In order to stop the audit of an event, a user must somehow invoke an Unaudit method.
That can be achieved via Documentum Administrator, a DFC call, or an API call. Invoking theUnaudit method will cause the dmi_registry object corresponding to the event
to be deleted. If the event is a System Event, the removal of thedmi_registry object will cause the Content Server to stop auditing the event.
If the event is an Application Event and you wrote your application to query thedmi_registry to determine if auditing was enabled for the event, then this
will effectively stop your application from auditing the event.

Note:
As noted in the Default Auditing section, unauditing an event
will result in an Audit Trail entry with the event name dm_unaudit.

Stopping Auditing Via Documentum Administrator

In Documentum Administrator, select the Audit Management node under Administration in the tree. In
the right panel you will see actions to manage audits based on the object type, the object
instance, or for all objects in the docbase. Select the appropriate action based on what type of event you need
to disable audit for and enter the criteria necessary to locate the existing audits. The resulting panel
will have a table at the bottom that shows all the existing audits registered. Select the event you want
to disable and click Unaudit. Click OK one final time to get back to the main display.

Stopping Auditing Via DFC

In DFC, you will use an instance of IDfAuditTrailManager to disable the audit. You can obtain
an instance of IDfAuditTrailManager directly off of any IDfSession by callinggetAuditManager().
Please refer to the javadoc pages for IDfAuditTrailManager for more details on the methods it
supports. The following code snippet demonstrates how to disable an audit:

DFC Application Event Bug

If you are auditing Application Events, there appears to be a bug in the DFC IDfAuditTrailManager
class which will prevent you from registering, unregistering, or querying audits on your custom events.
Why is this? For custom app events, there are no dm_type
objects which act as the target. So, you need to pass null for the objectName
parameter to the registration/query methods in IDfAuditTrailManager. Unfortunately, that causes
the methods to blow up with a DfException.

The workaraound is to unregister your custom events using the API.
Here is how you unregister a custom event named “my_custom_event” using the API:

API> unaudit,s0,0,my_custom_event

Stopping Auditing Via API

Use the “Unaudit” API command to stop auditing. Refer to the Content Server API Reference
for more details on this command. The syntax is:

Over time, Audit Trail entries can take up a lot of space in your Docbase. You will need to
periodically archive the entries by copying them or moving them out of the Audit Trail.
After you have copied the entries to a safe place, you can remove them using a DQL call,
an API call, or by using the Audit Management Tool. Regardless of which technique you
use, the user performing the operation needs to have the extended privilege Purge Audit.
Please refer to the section Granting Extended User Privileges
for details on how to grant the privilege.

Note:
As noted in the Default Auditing section, any removal of an
audit entry will result in an Audit Trail entry the event name dm_purgeaudit.
In fact, there will be one entry created per transaction; when purging lots of entries, this
can result in numerous dm_purgeaudit entries.

Purging Audit Trail Entries Via DQL

The DQL command to purge entries is purge_audit. The command is quite complex, so
we’ll only show a simple example here. For complete details, refer to PURGE_AUDIT in theContent Server DQL Reference Manual.

This example deletes all Audit Trail entries generated from January 1, 2003 to January 1, 2004,
including unarchived entries. The number of entries deleted in each transaction is set to 500:

Purging Audit Trail Entries Via API

The API command to purge entries is the administrative apply command, passingPURGE_AUDIT for the admin command name. So, this turns into a DQL PURGE_AUDIT.
That command is quite complex, so we’ll only show a simple example here. For complete details, refer toPURGE_AUDIT in the Content Server DQL Reference Manual.

This example deletes all Audit Trail entries generated from January 1, 2003 to January 1, 2004,
including unarchived entries. The number of entries deleted in each transaction is set to 500:

Audit Management Tool

The Audit Management Tool runs a dm_AuditMgt job, which in turn uses thePURGE_AUDIT administration method to remove the Audit Trail entries from the Docbase.
This tool has many options controlling its behaviour. Please refer to the Audit Management
section of Tools and Tracing in the Documentum Content Server Admin Guide for full
details on the tool and its execution.

Audit Trail entries are persistent Docbase objects of one of the following types (depending on the
Audit event): dm_audittrail, dm_audittrail_acl, or dm_audittrail_group.
Both dm_audittrail_acl and dm_audittrail_group extend dm_audittrail.

Audit Trails

Audit Trail dm_audittrail objects are created for all Application Events and for all System Events
which do not pertain to an ACL or a group. Excepting the string_x and id_x attributes, all of the
attributes in this object have a common purpose and are used by all the System Events. When the
event involves a SysObj, there are several attributes which identify the SysObj such as the object
ID, the chronicle ID, the vstamp, the Content Server host, and the Docbase. Of particular interest
is the attribute_list attribute, which is a comma-separated list of the audited attributes and their
values AFTER the event (for versioned objects, the value is the value of the attribute in the new
version). Please refer to Audit Trail section of the Documentum Content Server Object Reference for
details on the attributes in this object.

This object also contains five ID attributes and five String attributes which store special values
for certain System Events. These are referred to as the id_x and string_x attributes. The contents
of these attributes and their values for the various System Events are spelled out in detail inAuditing section of the Content Administrator’s Administration Guide. Applications can also map
special values onto these attributes when they are constructing Application Events (in which case,
it is up to the application to understand how to interpret the values when the Audit Trails are read
later).

All of the attributes in this object are available for use in Application Events.

Note:
There is an additional object of interest, dmi_audittrail_attrs, which is used as an overflow
store when the list of audited attributes for a System Event is too large to fit in theattribute_list attribute of a dm_audittrail object. In that case, the audited attributes are
stored in a dmi_audittrail_attrs object and the object ID of the dmi_audittrail_attrs object
is stored in the attribute_list_id attribute of the dm_audittrail object. If you are processing
Audit Trails programmatically, you will need to check for this overflow condition and handle it
accordingly. Optionally, you can query the the computed attribute, _attribute_list_values,
which will return all the attributes, including any stored in the dmi_audittrail_attrs object.

ACL Audit Trails

Audit Trail dm_audittrail_acl objects are created when a dm_save, dm_saveasnew, or dm_destroy
registered event occurs on an ACL. The audited ACL is identified by the inherited audited_obj_id
attribute. Please refer to Audit Trail ACL section of the Documentum Content Server Object Reference
for details on the attributes in this object.

Group Audit Trails

Audit Trail dm_audittrail_group objects are created when a dm_save, saveasnew, or dm_destroy
registered event occurs on a group. The audited group is identified in the inherited audited_obj_id
attribute. Please refer to Audit Trail Group section of the Documentum Content Server Object
Reference for details on the attributes in this object.

In order to read an Audit Trail entry, a user must possess the extended privilege View Audit.
Please refer to the section Granting Extended User Privileges
for details on how to grant the privilege.

Distributed Audit Trails

If your Content Server is running in a distributed environment, there are two situations
you need to be aware of in order to locate your Audit Trail. These are good to know even if
you are accessing your audits only through Documentum Administrator.

Audit Trail entries are stored in the source Docbase. If a user accessing
a remote Docbase causes an event to be audited for a document, the Audit Trail entry
will be written to the document’s source Docbase. So, you will want to access the
source Docbase to retrieve the Audit Trail.

Virtual documents that have component documents stored in multiple Docbases are even more interesting.
For these, the Assemble Audit Trail is written to the Docbase to which you are connected
when the Assemble method is executed, but the Checkin Audit Trail for individual components is
written to the corresponding source Docbase. So, the complete Audit Trail for the document is
spread across multiple Docbases. To access the full Audit Trail for one compound
document, you need to check multiple Audit Trails. Use the time_stamp_utc
attribute of the dm_audittrail object to merge the Audit Trails after you
have queried each Docbase.

Audit Viewing Security

What you can view is determined by your privileges and the value in an Audit
Trail entry’s i_audited_obj_class attribute. The following excerpt from theContent Server Administrator Guide details the security
rules applied to the Audit Trail entries displayed in Documentum Administrator:

Users with Superuser or View Audit privileges can view any Audit Trail entry.

Users without Superuser or View Audit privileges can view Audit Trail entries for
SysObject-related system events (i_audited_obj_class is set to 0) if they have at least
Browse privileges for the audited object.

Users without Superuser or View Audit privileges cannot view Audit Trail entries for
ACL, group, and user-related events (i_audited_obj_class is set to 1, 2, or 3)

Users who are the owner of an audited object can always view Audit Trail entries
for the object.

All users, regardless of privilege level, can view Audit Trail entries for application events.
If you do not have Superuser or View Audit privileges, the following attributes of the
Audit Trail entries are excluded from view for both system and application events:

acl_name

acl_domain

attribute_list

attribute_list_id

chronicle_id

object_nameo

object_type

owner_name

session_id

version_label

Viewing Trails Using Documentum Administrator

In general, the easiest way to view an Audit Trail is to use the Documentum Administrator
tool. Log in as a user with View Audit privilege. Select the Audit
Management node under Administration in the tree. In the right panel clickSearch Audit. Fill out the details necessary to view the events you need to view
and click OK. The tool will then display all the entries which meet your search
criteria. You can see all the attributes of any entry by clicking the i link on its
row in the table.

Note:
I had trouble viewing Application Events using Documentum Administrator 5.2.2.148. I was unable to locate my
custom event names using the Selected Events link, which is not suprising since they are custom events.
However, when I typed my custom event name into the text box under Selected Events and performed the
search, the tool never returned any records. Most likely, this is a “User Error” issue.

Accessing Trails Via Queries

You can programmatically query Audit Trail entries by executing either a DQL SELECT
or an API Fetch command against any of the three Audit Trail objects. All of theaudit viewing security restrictions listed
above also apply to these techniques.
In addition, if you are accessing objects of type dmi_audittrail_attrs,
then you must have Superuser or View Audit privileges.
However, there is a neat trick you can use if you do not have those privileges:
query the computed attribute, _attribute_list_values, and you will
get the audited attribute values for an event which you have permission to see,
including those stored in the dmi_audittrail_attrs object.

Verifying Signed Audit Trail Entries

When you register an audit on an event, you can elect to have the Content Server sign the
contents of all Audit Trail entries created for that event. This involves computing a hash
for the contents, encrypting the hash with the Application Encryption Key (AEK) for the Content
Server, and storing the encrypted hash in the audit_signature attribute of
the dm_audittrail entry. At any point in the future, a user may request that
the signed event be verified, in order to ensure that it has not been tampered with since
it was created. In order to verify the entry, the Content Server recomputes the encrypted
hash of the entry and compares it to the one stored in the record. If the hashes are not the
same, then the values in the Audit Trail entry have been modified since it was created.

Verifying Signed Audit Via API

The API call available to us is Verifyaudit (see the Content Server API Reference for
full details). There are no special privileges required to make the call. The syntax for the call is:

dmAPIExec("verifyaudit,session,object_id")

where the object_id is the Object ID of the dm_audittrail,dm_audittrail_acl, or dm_audittrail_group object being verified.
The following example will verify the audit entry whose ID is ‘5f638bd780000125′:

API> verifyaudit,s0,5f638bd780000125

Verifying Signed Audit Via DFC

There is no equivalent method in IdfAuditTrailManager to perform a verify,
so we have to invoke the API call from an IDfSession.
The following example will verify the audit entry whose ID is ‘5f638bd780000125′:

Note:
Because the audit entries are signed with the AEK of the Content Server, problems can
arise if the Docbase has multiple servers. In that case, you should ensure that the AEKs
in all the Content Servers are the same. If that cannot be done, then the application
requesting the verify must request the verify operation off of the Content Server which
created the audit entry (the server which creates the entry is stored in thehost_name attribute of the dm_audittrail entry).

That ends our tour of the audit capabilities of the Content Server. Clearly, the facility
is quite powerful, especially when it comes to auditing your application-specific events.
The Documentum documentation is quite excellent for this feature set. I would recommend
starting with the Content Server Administration Guide if you are interested in
more details.