Hi,
Here, a Documentum DFC standalone sample program in order to create entries in dm_audittrail. DCTM provides several more evolved methods for example to register an audit event (dm_save) for specific custom object and its subtypes and including new values of attributes in order to create automatically entries,
Very good article : https://www.bluefishgroup.com/insights/articles/the-content-server-audit-facility/
public void registerAudit(IDfSession session) throws DfException { // Get an instance of the audit manager using the session IDfAuditTrailManager auditMgr = session.getAuditTrailManager(); // Setup the request parameters String objectType = "vendor_admin"; String eventName = "dm_save"; boolean auditSubTypes = true; // we want to audit subtypes also boolean signAuditEntries = false; // disable tamper-evident Audit Trail int authentication = 0; // we don't require user to authenticate String description = "Save Vendor Admin"; // shows up in each audit entry String[] auditAttrs = { "va_name, "va_tax_id" }; // Use the audit manager to register the audit. // We do not care about controlling applications or workflows, // so we pass null for those arguments. auditMgr.registerEventForType(objectType, eventName, auditSubTypes, null, // controllingApp null, // policyId null, // stateName signAuditEntries, authenticate, description, new DfList(attrs)); }
Here, a simple code in order to create audit entries without registration:
package com.huo.test.ecm.test2; import com.documentum.fc.client.DfClient; import com.documentum.fc.client.DfQuery; import com.documentum.fc.client.IDfAuditTrailManager; import com.documentum.fc.client.IDfClient; import com.documentum.fc.client.IDfCollection; import com.documentum.fc.client.IDfQuery; import com.documentum.fc.client.IDfSession; import com.documentum.fc.client.IDfSessionManager; import com.documentum.fc.client.IDfSysObject; import com.documentum.fc.common.DfId; import com.documentum.fc.common.DfLoginInfo; import com.documentum.fc.common.IDfLoginInfo; /* Documentum DFC Standalone Sample Program Creation of audit trail entries */ public class DMAuditTrailTest { IDfSysObject sysObject = null; IDfSession idfSession = null; IDfSessionManager sessMgr = null; public DMAuditTrailTest(String user, String passwd, String docbase) throws Exception { getDfSession(user, passwd, docbase); } public IDfSession getDfSession(String args1, String args2, String args3) throws Exception { IDfLoginInfo login = new DfLoginInfo(); login.setUser(args1); login.setPassword(args2); IDfClient client = DfClient.getLocalClient(); //new DfClient(); sessMgr = client.newSessionManager(); sessMgr.setIdentity(args3, login); idfSession = sessMgr.getSession(args3); if (idfSession != null) System.out.println("Session created successfully"); return idfSession; } public void releaseSession() throws Exception { sessMgr.release(idfSession); } public void createAuditTrailEntry(String objectId, String eventName) throws Exception { IDfAuditTrailManager mgr = idfSession.getAuditTrailManager(); // createAudit(IDfId objectId, String event, String[] stringArgs, IDfId[] idArgs) mgr.createAudit(new DfId(objectId), eventName, null, null); } public int getNbEntriesOfAuditTrail(String eventName) throws Exception{ IDfCollection resCount = null; int nbEntries = 0; try{ String dql = "select count(r_object_id) as cnt from dm_audittrail where event_name = '"+eventName+"' order by time_stamp desc"; IDfQuery query = new DfQuery(); query.setDQL(dql); resCount = query.execute(idfSession, IDfQuery.DF_EXEC_QUERY); if(resCount!=null){ resCount.next(); nbEntries = resCount.getInt("cnt"); } } finally { if (resCount!=null) { resCount.close(); } }//end-if return nbEntries; } public static void main(String[] args) throws Exception { String user = "huouser"; String passwd = "pwd_4huouser"; String docbase = "MY_DOCBASE_DEV"; boolean isTransactionalSession = false; boolean noErrorWithCurrentDocument = false; DMAuditTrailTest object = new DMAuditTrailTest(user, passwd, docbase); try { if (!object.idfSession.isTransactionActive()) { object.idfSession.beginTrans(); isTransactionalSession = true; } String eventName = "Executing createAuditTrailInput :)"; String objectId = "090xxxxxxxxf1d"; // int nbEntries1 = object.getNbEntriesOfAuditTrail(eventName); System.out.println("Nb of audit trail for the event '"+eventName+"' = "+ nbEntries1 + "(BEFORE adding)"); // object.createAuditTrailEntry(objectId, eventName); // int nbEntries2 = object.getNbEntriesOfAuditTrail(eventName); System.out.println("Nb of audit trail for the event '"+eventName+"' = "+ nbEntries2 + "(AFTER adding) - under condition that the transaction is committed!!!!"); noErrorWithCurrentDocument = true; } finally { if(object!=null){ if (isTransactionalSession) { if (noErrorWithCurrentDocument) { object.idfSession.commitTrans(); } else { object.idfSession.abortTrans(); } } // to release a docbase session object.releaseSession(); } } } }
Below, an example of output for this program:
Session created successfully Nb of audit trail for the event 'Executing createAuditTrailInput :)' = 2(BEFORE adding) Nb of audit trail for the event 'Executing createAuditTrailInput :)' = 3(AFTER adding) - under condition that the transaction is committed!!!!
The important point of code is :
public void createAuditTrailEntry(String objectId, String eventName) throws Exception { IDfAuditTrailManager mgr = idfSession.getAuditTrailManager(); // createAudit(IDfId objectId, String event, String[] stringArgs, IDfId[] idArgs) mgr.createAudit(new DfId(objectId), eventName, null, null); }
Extended User Privileges
To do anything on auditing, the current user must have specific extended user privileges. There are three extended user privileges which the Content Server
uses to manage security authorization for audit requests:
- Config Audit : User can execute the Audit and Unaudit methods to start and stop auditing, its integer value is 8
- Purge Audit : User can remove Audit Trail entries from the Docbase, its integer value is 16
- View Audit : User can view Audit Trail entries, its integer value is 32
We have an user yith the Extended Privileges = Config, View and Purge Audit:
select user_xprivileges from dm_user where user_name = 'gedadm'; = 56 = 8 + 16 + 32
TEST 1 :
Even if the maximum extended user privileges, it is not possible to modify an existing AuditTrail object via DFC/DQL/API, any tentative will get the exception DfException:: THREAD: main; MSG: [DM_AUDITTRAIL_E_CANT_MODIFY]error: “You can not modify any existing AuditTrail object 5f0xxxxxxxxxxxxxbf.”; ERRORCODE: 100; NEXT: nullerror:
public void createAuditTrailEntry(String objectId, String eventName) throws Exception { IDfAuditTrailManager mgr = idfSession.getAuditTrailManager(); // createAudit(IDfId objectId, String event, String[] stringArgs, IDfId[] idArgs) IDfId auditTrailId = mgr.createAudit(new DfId(objectId), eventName, null, null); // => Exception in thread "main" DfException:: THREAD: main; MSG: [DM_AUDITTRAIL_E_CANT_MODIFY]error: "You can not modify any existing AuditTrail object 5f0xxxxxxxxxxxxxbf."; ERRORCODE: 100; NEXT: null try{ IDfAuditTrail auditTrailObj = (IDfAuditTrail) idfSession.getObject(auditTrailId); auditTrailObj.setString("event_description", "event_description for the "+objectId+" object" ); auditTrailObj.save(); }catch(Exception ex){ ex.printStackTrace(); } }
TEST 2 :
Howvever, it is possible to modify any existing AuditTrail object via SQL:
// MAIN 2 : Modification of audit trail { String auditTrailId = "5f0xxxxxx7"; StringBuilder sql = new StringBuilder(); sql.append("UPDATE ").append(object.idfSession.getDocbaseOwnerName()).append(".dm_audittrail_s"); sql.append(" SET "); sql.append(" event_description = '").append("event_description for the "+auditTrailId+" object").append("' "); sql.append(" WHERE R_OBJECT_ID = '").append(auditTrailId).append("'"); IDfApplyExecSQL dfApplyExecSQL = (IDfApplyExecSQL) DfAdminCommand.getCommand(DfAdminCommand.APPLY_EXEC_SQL); dfApplyExecSQL.setQuery(sql.toString()); IDfCollection coll = dfApplyExecSQL.execute(object.idfSession); try { if (coll.next()) { IDfValue dfValue = coll.getValueAt(0); if (!dfValue.asBoolean()) { throw new RuntimeException("Error in modification of existing AuditTrail object via SQL :" + sql); } } else { throw new RuntimeException("Error in modification of existing AuditTrail object via SQL :" + sql); } } finally { if(coll!=null){ coll.close(); } } }
Example of deleting of existing AuditTrail object via pure API:
API> retrieve,c,dm_audittrail where r_object_id ='5f0xxxxxx7' ... 5f0xxxxxx7 API> destroy,c,l ... OK
Example of creation of AuditTrail object via pure API:
create,c,dm_audittrail set,c,l,event_name my_event_huo_name set,c,l,event_source My process set,c,l,user_name My process set,c,l,audited_obj_id 09xxxxxx62 set,c,l,string_1 Value Str 1 set,c,l,string_2 Value Str 2 set,c,l,string_3 Value Str 3 set,c,l,id_1 09xxxxx621 set,c,l,id_2 09xxxxxx622 set,c,l,sid_3 09xxxxxx623 save,c,l
The informations user_id, session_id, owner_name, time_stamp, time_stamp_utc, host_name are filled automatically by Content Server. Yet, the informations acl_name, acl_domain, chronicle_id, object_type, version_label, object_name are extracted from the audited object (audited_obj_id).
Resources : https://www.bluefishgroup.com/insights/articles/the-content-server-audit-facility/
Best regards,
Huseyin