4 Java-Based Audit Trail Collection Plug-ins
Oracle Audit Vault and Database Firewall provides a set of Java-based audit trial collection plug-in, which enable you to create custom plug-ins.
4.1 About Java-Based Collection Plug-ins
For situations where a template-based collection plug-in cannot easily handle audit data, you can use Java-based collection plug-ins
Creating a custom collection plug-in using the Java APIs gives you much flexibility in how you design your collection plug-in.
In general, use the Java type of collection plug-in if you need it to:
-
Read trails not written in database tables or XML files.
-
Read complex trails written to tables or XML files.
4.2 JDK Requirement for Using the Java-Based Collection Plug-in
To use a Java-based collection plug-in with Oracle Audit Vault and Database Firewall, you must have the JDK to compile and test your code.
Because the collection plug-in runs under the same JVM after it is shipped, Oracle
recommends that you use the same JDK as the JDK that you use to start the agent. Compile
your classes with the JDK by setting the -target
option of the
javac
compiler to the same JDK version. Refer to the JDK
documentation for details.
4.3 About the Flow of Control Inside the Java-Based Collection Plug-in
Learn how Oracle Audit Vault accesses an audit trail, maps the trail to Oracle Audit Vault events, starts the correct Java-based collection plug-in, and creates audit records.
When a collection plug-in accesses an audit trail, it extracts an audit record and its related fields from the audit trail. Next, it maps the audit record to an Oracle Audit Vault event, and all the fields to Oracle Audit Vault fields. The collection plug-in then passes the Oracle Audit Vault event and fields to the Collection Framework, which sends the information to the Oracle Audit Vault Server.
The sequence of control processes for the audit trail collection is as follows.
Control Process Sequence for Audit Trail Collection
-
The Oracle Audit Vault Server commands the Agent Framework to create a thread to collect from a specific audit trail.
-
The new thread, just created by the agent, collects a specific audit trail.
At this point, control is handed to the Collection Framework.
-
Within the thread, the Collection Framework connects to the Oracle Audit Vault Server, and queries for configuration information for the audit trail being collected.
In addition, it requests information for the last checkpoint set for that trail.
-
With the information it now has, the Collection Framework uses the plug-in manifest file to determine the correct Java class to start within the correct collection plug-in. It passes the configuration information to this class, and asks it to initialize itself.
-
After the collection plug-in has initialized itself, the Collection Framework loops repeatedly. Within each loop, the Collection Framework does the following:
-
Asks the collection plug-in for any additional audit records in the audit trail.
The collection plug-in transforms (by mapping) any further audit records into the form of audit records that Audit Vault expects, and hands them to the Collection Framework through the Collection API.
-
-
The collection plug-in can periodically send Checkpoint and metric information to the Collection Framework. The collection plug-in can do so in the same flow when it has the control, for example when the Collection Framework calls
hasNext()
. -
If the Oracle Audit Vault Server sends commands to the Collection Framework, the Collection Framework passes them to the collection plug-in to act on.
If the Collection Framework receives a
STOP
command from the Audit Vault Server, it notifies the collection plug-in to stop sending record. Then it exits the collection thread and shuts itself down.If the Collection Framework receives a
RECONFIGURE
command from the Audit Vault Server, it notifies the collection plug-in to set an attribute usingsetAttribute()
.
Related Topics
4.4 Useful Classes and Interfaces in the Collection Framework
Learn about Oracle Audit Vault Java-based collection plug-in classes and interfaces that can be particularly useful for your own collections
The image below shows the relationships between the classes and interfaces from the AuditService, CollectorContext, and Class AVLogger.
Figure 4-1 Classes and Interfaces from AuditService, CollectorContext, and Class AVLogger

Description of "Figure 4-1 Classes and Interfaces from AuditService, CollectorContext, and Class AVLogger"
The following diagram shows the various classes and interfaces in the Collection Framework that you need to know about to write a Java-based collection plug-in.
Figure 4-2 Classes and Interfaces from Collection Framework Used in Collection Plug-in

Description of "Figure 4-2 Classes and Interfaces from Collection Framework Used in Collection Plug-in"
4.5 How to Create a Java-Based Collection Plug-in
Review the tasks required to create and use Java-based collection plug-ins for Oracle AVDF.
4.5.1 About Creating a Java-Based Collection Plug-in
The Oracle Audit Vault documentation provides examples of a Java-based collection
plug-in implementation, including a hypothetical source that writes events to a table named
AUD
.
Implementing Oracle Audit Vault and Database Firewall involves writing Java classes
that implement the AuditEventCollectorFactory
interface, and that
extend the AuditEventCollector
class, which are part of the Audit Vault
Collection Framework. The same Java class can both extend the
AuditEventCollector
class. and implement the
AuditEventCollectorFactory
interface. Alternately, you can choose
to write two separate classes.The sample consists of two classes,
SampleEventCollectorFactory
which implements the
AuditEventCollectorFactory
interface and
SampleEventCollector
which extends from the
AuditEventCollector
class.
4.5.2 Using the AuditEventCollectorFactory to Get the AuditEventCollector Object
During runtime the collection plug-in can require multiple implementations of AuditEventCollector. The AuditEventCollectorFactory object enables this capability for Oracle Audit Vault and Database Firewall.
The Collection Framework does not create an instance of the AuditEventCollector
object directly. Instead, it creates an instance of the AuditEventCollectorFactory
class and using the factory object, gets the AuditEventCollector
object. This is because the collection plug-in may require multiple implementations of AuditEventCollector
. The collection plug-in decides at run time which implementation to use. Therefore, every collection plug-in should have an implementation of AuditEventCollectorFactory
.
In the following example, the createAuditEventCollector()
always
creates and returns an instance of the SampleAuditEventCollector
class.
Example 4-1 Creating a SampleAuditEventCollector Class
public class SampleEventCollectorFactory implements AuditEventCollectorFactory {
public AuditEventCollector createAuditCollection(
CollectorContext collectorContext) throws AuditEventCollectorException {
return new SampleEventCollector();
}
}
4.5.3 Using the CollectorContext Class When Creating a Java-Based Collection Plug-in
Learn how to use source attributes, which provide the Oracle AVDF collection plug-in with information about the source that is needed to collect the audit trail effectively.
The Collection Framework passes an instance of the CollectorContext
class to the collection plug-in through the initializeCollector
method. This instance can be queried by the collection plug-in to obtain information needed to collect the audit trails generated by the source.
4.5.3.1 Basic Source Attributes
To obtain audit trail collection successfully, there are basic source attributes that provide the collection plug-in with information about the source for Oracle Audit Vault and Database Firewall.
Basic source attributes for Oracle Audit Vault and Database Firewall include the user
name, password, and connection string. These attributes are returned by these methods
respectively: getSecuredTargetUser
,
getSecuredTargetPassword
, and
getSecuredTargetLocation
. You can retrieve pther source attributes
by using getAttributes
.
When the Oracle Audit Vault administrator registers the source, you can require the Oracle Audit Vault administrator to provide the required information, in the form of source attributes. Oracle Audit Vault stores these attributes in the Oracle Audit Vault Server repository, and provides them to the collector code on startup.
Some collection plug-ins do not need to connect to the source and in these cases, the Collection Framework may return null for these methods.
Related Topics
4.5.3.2 Basic Trail Attributes
The checkpoint and trail name attributes are the basic attributes that Oracle Audit Vault and Database Firewall obtains.
Checkpoint attributes are returned by the getCheckpoint
method, and
trail name attributes are returned by the getTrailLocation
method. The
collection plug-in should use these attributes as follows:
-
The checkpoint returned is the last checkpoint the collection plug-in has set for this trail when it ran the last time. The collection plug-in should start sending only those records which have an event time greater than or equal to the checkpoint. If the collection plug-in is starting for the first time, the collection plug-in receives this value as null. In this case, the collection plug-in must send the records from the beginning.
-
Trail name indicates the target containing the audit events, typically, a table or directory name.
You can retrieve other trail attributes by using getAttributes
.
Related Topics
4.5.3.3 Utility Instances
Learn how to use the AVLogger and AuditService attributes with the Oracle Audit Vault collector.
AVLogger
and AuditService
are returned by the getLogger
and getAuditService
methods, respectively. The collector should use these attributes as follows:
-
The
AVLogger
instance logs various messages. -
The
AuditService
instance sends checkpoints and metrics to the Audit Vault Server.
These methods never return null.
Related Topics
4.5.3.4 Additional Source or Trail Attributes
You can retreive other attributes that you find the Oracle Audit Vault and Database
Firewall collector needs by passing the attribute name to the getAttribute
method.
For example, suppose that a source required SourceVersion
to
collect audit data. In that scenario, to obtain the value of
SourceVersion
. the collector for the source calls
collectorContext.getAttribute('SourceVersion')
.
If the attribute is present, then the getAttribute
method returns
the attribute value as a String. Otherwise, the method returns null.
If the collector receives a null or an invalid value for any mandatory attribute,
then it must throw an AuditEventCollectorException
exception from the
initializeCollector
method. After throwing an exception, the
Collection Framework shuts down.
Related Topics
4.5.4 Initializing the Java-Based Collection Plug-in
Use these examples to understand how to initialize a Java-based collection plug-in, and how to start audit events collection with Oracle Audit Vault and Database Firewall.
The first thing the Collection Framework does after the collection thread starts is to initialize the collector.
The Collection Framework calls the initializeCollector()
method of the AuditEventCollector
class. The collector sets up the
environment appropriately to enable it to start collecting audit events. For example,
for a database table collection plug-in, this method connects to the database. For an
XML file collection plug-in, this method parses the file mask and may open a particular
file to start with. The collection plug-in may also want to retrieve various attributes
from the collector context at this point. If there is an error in setting up the
environment, this method throws AuditEventCollectorException
with an
appropriate error message.
Example 4-2 Initializing a Java-Based Collection Plug-in
The following is a example of how to initialize a Java-based collection plug-in:
private AVLogger m_logger;
private CollectorContext m_collectorContext;
private long m_timeZoneOffset;
private AuditService m_auditService;
private Timestamp m_previousCheckpoint;
public void initializeCollector(CollectorContext collectorContext)
throws AuditEventCollectorException {
m_collectorContext = collectorContext;
m_auditService = m_collectorContext.getAuditService();
m_previousCheckpoint = m_collectorContext.getCheckpoint();
m_logger = m_collectorContext.getLogger();
// Get other attributes of the Source.
String offset = m_collectorContext.getAttribute("TimeZoneOffset");
if (offset != null) { m_timeZoneOffset = getTimeZoneOffsetInMs(offset);
}
connectToSource();
}
Example 4-3 Using the ConnectionManager Utility to Connect and Retrieve Audit Records From a Database
If a collector must connect to a database to retrieve audit records, then it must use
the ConnectionManager
utility API provided with Oracle Audit Vault. The
following example shows how to use the ConnectionManager utilityL
private ConnectionManager m_connectionManager;
private void connectToSource() throws AuditEventCollectorException {
m_logger.logDebugMethodEntered();
// Get connection information from collector context.
String user = m_collectorContext.getSecuredTargetUser();
String password = new String(m_collectorContext.getSecuredTargetPassword());
String connectionString = m_collectorContext.getSecuredTargetLocation();
// Create a ConnectionManager object.
try {
m_connectionManager = new ConnectionManagerImpl(connectionString,
user, password.toCharArray());
m_connection = m_connectionManager.getConnection();
} catch (AuditException ex) {
throw new AuditEventCollectorException(
ErrorCodes.FAILED_CONNECT_TO_SOURCE,
new Object[] { connectionString }, ex);
}
m_logger.logDebugMethodExited();
}
4.5.5 Connecting, Fetching Events, and Setting Checkpoints
Use these examples to understand how to connect a Java-based collection plug-in, how to fetch events, and how to set checkpoints with Oracle Audit Vault and Database Firewall.
After initialization, the Collection Framework repeatedly calls the hasNext()
method of the collector, which internally calls the fetchEvents()
method. In this method, the collector fetches audit records from the audit trail in the form of a ResultSet
.
The range that is fetched starts from the point that was just finished to nearly the current time. The next fetch is performed when the current ResultSet
is exhausted
The collection plug-in sets the checkpoint whenever one
ResultSet
finishes processing, but before the next one starts. The
timing of this is important. When a collection plug-in sets the checkpoint with
Timestamp
t
, the collection plug-in must ensure that all
records with an event time less than t
are already
sent to Collection Framework. However, because ResultSet
does not give
records in any particular order, setting the checkpoint before the end of a
ResultSet
can be incorrect. Additionally, the collection plug-in
does not use the current time as the upper bound of the range, but rather uses the
current time minus the delta time. Using this time method allows for possible delays
between generating the event, and inserting the event into the table. When the
collection plug-in runs the query, all events up to the upper bound are fetched in the
ResultSet
to honor the checkpoint contract. The 5-second delay time
(the delta) ensures that all of the records, up to the upper bound, are already in the
table.
Example 4-4 Fetching ResultSets and Setting Checkpoints
This example shows how collectors should obtain the
Connection
from ConnectionManager
whenever they
need one.
private ResultSet m_resultSet;
private Timestamp m_nextCheckpoint;
private void fetchEvents() throws AuditEventCollectorException {
m_logger.logDebugMethodEntered();
if (m_nextCheckpoint != null) {
m_auditService.setCheckpoint(m_nextCheckpoint);
m_previousCheckpoint = m_nextCheckpoint;
}
// It is not good to hold on to the Connection for long. As this is the
// only place we can release the connection, we release and reacquire the
// connection.
try {
if (m_connection != null) {
m_connectionManager.releaseConnection(m_connection);
}
} catch (AuditException ex) {
throw new AuditEventCollectorException(
ErrorCodes.FAILED_TO_RELEASE_CONNECTION_TO_DB, null, ex);
}
try {
m_connection = m_connectionManager.getConnection();
} catch (AuditException ex) {
throw new AuditEventCollectorException(
ErrorCodes.FAILED_TO_GET_CONNECTION_TO_DB, null, ex);
}
// This is the upper bound which is current time minus 5 seconds.
m_nextCheckpoint = new Timestamp(System.currentTimeMillis() - 5000);
String query = null;
try {
if (m_previousCheckpoint == null) {
query = "select * from AUD where EVENT_TIME <= ?";
m_preparedStatement = m_connection.prepareStatement(query);
m_preparedStatement.setTimestamp(1, m_nextCheckpoint);
} else {
query = "select * from AUD where EVENT_TIME > ? and EVENT_TIME <= ?";
m_preparedStatement = m_connection.prepareStatement(query);
m_preparedStatement.setTimestamp(1, m_previousCheckpoint);
m_preparedStatement.setTimestamp(2, m_nextCheckpoint);
}
m_resultSet = m_preparedStatement.executeQuery();
} catch (SQLException ex) {
throw new AuditEventCollectorException(
ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE,
new Object[] { query }, ex);
}
m_logger.logDebugMethodExited();
}
Example 4-5 Using hasNext to Fetch Records
In this example, thehasNext()
method runs the
fetchEvents()
method that you see defined in the preceding example to
to fetch records, and to set
checkpoints. public boolean hasNext() throws AuditEventCollectorException {
boolean hasMore;
try {
if(m_resultSet == null) {
fetchEvents();
return m_resultSet.next();
}
hasMore = m_resultSet.next();
if (!hasMore) {
fetchEvents();
hasMore = m_resultSet.next();
}
} catch (SQLException ex) {
throw new AuditEventCollectorException(
ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
}
return hasMore;
}
4.5.6 Transforming Source Event Values to Audit Vault Event Values
Learn about when and how the Oracle AVDF collection plug-in transforms source event values to Oracle AVDF values.
The collector retrieves values of specific fields from source. For some fields, in addition to retrieving the values, the collection plug-in must transform the values in certain ways. This section discusses transformations that are required for all source types.
4.5.6.1 Event Time to UTC
See how Oracle Audit Vault and Database Firewall transforms an event time from a source time zone to Coordinated Universal Time (UTC).
Event Time should be sent only in UTC time zone. Therefore, it must be transformed from the source time zone to the UTC time zone before returning a value. If the column from the source database is timezone aware, then this transformation is not necessary.
Example 4-6 Transforming EventTime from Source Time Zone to UTC
public Timestamp getEventTimeUTC() throws AuditEventCollectorException {
try {
Timestamp eventTime = m_resultSet.getTimestamp("EVENT_TIME");
// As the method name suggests, the timestamp must be returned only in
// UTC timone.
return new Timestamp(eventTime.getTime() - m_timeZoneOffset);
} catch (SQLException ex) {
throw new AuditEventCollectorException(
ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
}
}
4.5.6.2 Source Event Name to Audit Vault Event Name
Use this example to create your own source event names to Oracle Audit Vault event names mapping.
Each source event name maps to one Oracle Audit Vault event name. The
getCommandClass()
method should transform the source event name into a
value that Oracle Audit Vault can accept.
Example 4-7 Mapping Source Event Names to Audit Vault Event Names
private static final Map<Integer, String> eventNameMap = new HashMap<Integer,
String>();
static {
eventNameMap.put(1, "CREATE");
eventNameMap.put(2, "INSERT");
eventNameMap.put(3, "SELECT");
eventNameMap.put(4, "CREATE");
eventNameMap.put(15, "ALTER");
eventNameMap.put(30, "AUDIT");
eventNameMap.put(34, "CREATE");
eventNameMap.put(35, "ALTER");
eventNameMap.put(51, "CREATE");
eventNameMap.put(52, "CREATE");
}
public String getCommandClass() throws AuditEventCollectorException {
try {
int eventId = m_resultSet.getInt("ACTION");
return eventNameMap.get(eventId);
} catch (SQLException ex) {
throw new AuditEventCollectorException(
ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
}
}
Related Topics
4.5.6.3 Source Event ID to Source Event Name
Learn how to map the source event identifiers (IDs) to descriptive source event names in Oracle Audit Vault and Database Firewall.
For some sources, events reported as IDs may not mean anything if users are unfamiliar with the IDs. Therefore, it may be best to map the source event IDs to descriptive source event names. If the audit record itself contains descriptive event names, then they can directly be returned without any mapping. The source event name is optional, so the collection plug-in can return null if it does not have the information.
In the following example, you can see how to map the source event IDs to descriptive source event names.
Example 4-8 Mapping Source Event Ids to Source Event Names
private static final Map<Integer, String> sourceEventMap =
new HashMap<Integer, String>();
static {
targetTypeMap.put(1, "OBJECT:CREATED:TABLE");
targetTypeMap.put(2, "INSERT INTO TABLE");
targetTypeMap.put(3, "SELECT FROM TABLE");
targetTypeMap.put(4, "OBJECT:CREATED:TABLE");
targetTypeMap.put(15, "OBJECT:ALTERED:TABLE");
targetTypeMap.put(30, "AUDIT OBJECT");
targetTypeMap.put(34, "OBJECT:CREATED:DATABASE");
targetTypeMap.put(35, "OBJECT:ALTERED:DATABASE");
targetTypeMap.put(51, "OBJECT:CREATED:USER");
targetTypeMap.put(52, "OBJECT:CREATED:ROLE");
}
public String getEventName() throws AuditEventCollectorException {
try {
int eventId = m_resultSet.getInt("ACTION");
return sourceEventMap.get(eventId);
} catch (SQLException ex) {
throw new AuditEventCollectorException(
ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
}
}
4.5.6.4 Mapping Source Event Name or ID to Target Type
Learn how to map source event identifiers (IDs) to Oracle Audit Vault target types.
A target type is the type of the object on which an event has taken
place. For example, if the event is a SELECT
operation on a table, then
the target type is table. In some sources, the target type can be present within the source
event name and ID. For example, an event name can be select table
, which
implies that the target type is a table. In this case, you must map the source event name
or ID to a target type. Target type is an optional field, so the collection plug-in can
return null if there is no such information.
In the following example, source event IDs are mapped to Oracle Audit Vault target types.
Example 4-9 Mapping Source ID to Target Type
private static final Map<Integer, String> targetTypeMap =
new HashMap<Integer, String>();
static {
targetTypeMap.put(1, "TABLE");
targetTypeMap.put(2, "TABLE");
targetTypeMap.put(3, "TABLE");
targetTypeMap.put(4, "CLUSTER");
targetTypeMap.put(15, "TABLE");
targetTypeMap.put(30, "OBJECT");
targetTypeMap.put(34, "DATABASE");
targetTypeMap.put(35, "DATABASE");
targetTypeMap.put(51, "USER");
targetTypeMap.put(52, "ROLE");
}
public String getTargetType() throws AuditEventCollectorException {
try {
int eventId = m_resultSet.getInt("ACTION");
return targetTypeMap.get(eventId);
} catch (SQLException ex) {
throw new AuditEventCollectorException(
ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
}
}
4.5.6.5 Source Event Status to Oracle Audit Vault Event Status
Oracle Audit Vault has three EventStatus
values. See how you can
transform source event status values to the Oracle Audit Vault values.
There are only three allowed values for EventStatus
. They are
SUCCESS
, FAILURE
, and UNKNOWN
. You
must configure transformations of any source event values to one of the three supported
Oracle Audit Vault values. In the following example, you can see how source values are
transformed to Oracle Audit Vault values.
Example 4-10 Transforming Source Values to Oracle Audit Vault EventStatus Values
public EventStatus getEventStatus() throws AuditEventCollectorException {
try {
int status = m_resultSet.getInt("STATUS");
if (status == 1) {
return EventStatus.SUCCESS;
} else if (status == 0) {
return EventStatus.FAILURE;
} else {
return EventStatus.UNKNOWN;
}
} catch (SQLException ex) {
throw new AuditEventCollectorException(
ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
}
}
4.5.7 Retrieving Other Audit Field Values
When field values do not require transformations, the Oracle Audit Vault Java-based collection plug-in returns the value it obtains from the source.
In the following example, the Oracle Audit Vault collection plug-in obtains a user name, and returns it.
Example 4-11 Returning Values that Do Not Need Transformation
public String getUserName() throws AuditEventCollectorException {
try {
return m_resultSet.getString("USER_ID");
} catch (SQLException ex) {
throw new AuditEventCollectorException(
ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
}
}
4.5.8 Changing Oracle AVDF Attributes at Run Time
If you are an administrator, then you can change the attributes that a Java-based collector plug-in uses during Oracle AVDF audit trail collection.
If you are an Oracle AVDF administrator, then you can update attributes,
including source attributes, at any time. To update attributes, you can use either the Audit
Vault Server console, or you can use the AVCLI
command-line tool.
How Audit Vault Server Manages Attribute Updates
If the update occurs while collectors are collecting audit trails, then first
Audit Vault Server notifies all running collectors dynamically, by calling the
setAttribute
method of the collector. Next, the collection plug-in must
start using the new value immediately. If the collection plug-in is not configured for the
attribute value, or if the value cannot be used, then the collector responds with the
message SetAttributeException
.
In the following example, the collection plug-in receives and handles a new
time zone offset to use in converting the EventTime
to Coordinated
Universal Time (UTC) time zone for all subsequent events.
Example 4-12 Changing an Oracle Audit Vault and Database Firewall Attribute
public void setAttribute(String name, String value)
throws SetAttributeException {
if (name.equalsIgnoreCase("TimeZoneOffset")) {
m_timeZoneOffset = getTimeZoneOffsetInMs(value);
} else {
throw new SetAttributeException(ErrorCodes.INVALID_ATTRIBUTE_NAME,
new Object[] { name, value }, null);
}
}
Effects After Modifying Attributes
Use the preceding example to understand how the time zone offset transformation is affected in the example you can find in the following topic:
4.5.9 Changing Custom Attributes at Run Time
See how administrators can change custom collector plug-in attributes at runtime while Oracle Audit Vault and Database Firewall collects the audit trail.
As with Oracle Audit Vault and Database Firewall (Oracle AVDF) attributes, you can also change custom attributes at runtime.
If you want to change custom attributes, then you must implement the following methods to validate the custom attributes before you can use custom attributes in the setAttribute
method.
Example 4-13 Changing a Custom Attribute
private static final String[] s_attributes = new String[] { "av.collector.configureParameter1", "av.collector.configureParameter2" };
public String[] getAttributeNames() throws AuditEventCollectorException {
return s_attributes.clone();
}
public void setAttribute(String name, String value)
throws SetAttributeException {
if (name.equalsIgnoreCase("configureParameter1")) {
// use value
}else if (name.equalsIgnoreCase("configureParameter2"))
{
// use value
}else {
throw new SetAttributeException(ErrorCodes.INVALID_ATTRIBUTE_NAME,
new Object[] { name, value }, null);
}
}
4.5.10 Creating Extension Fields
See an example of how to create an extension field for Java-based collection plug-ins in Oracle Audit Vault and Database Firewall.
The extension field contains all the fields of the source event which are of interest to the user, but do not correspond to any of the core or large fields. The collector must form one string which contains the names and values of these extra fields. The format of this string is up to the collection plug-in. The Collection Framework never tries to parse this string. In this example of creating an extension field, it uses the following format, repeating as needed:
<field_name>=<field_value>;
Note that this example extension file sends three fields:
Example 4-14 Creating an Extension Field
public String getExtension() throws AuditEventCollectorException {
try {
StringBuilder sb = new StringBuilder();
sb.append("DB_ID=" + m_resultSet.getString("DB_ID") + ";");
sb.append("INSTANCE=" + m_resultSet.getString("INSTANCE") + ";");
sb.append("PROCESS=" + m_resultSet.getString("PROCESS"));
return sb.toString();
} catch (SQLException ex) {
throw new AuditEventCollectorException(
ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
}
}
4.5.11 Handling Large Audit Fields
See an example of how Oracle Audit Vault and Database Firewall handles very large audit record fields.
Some audit record fields can be very large, so that returning them as a string is not
feasible. Therefore, methods corresponding to those fields return an object of type
Reader
. If the source field is a character large object
(aCLOB
), then the Reader
can be obtained by using
clob.getCharacterStream()
.
Note:
The Reader
is only valid as long as the Connection to the source is alive.
You must design the collection plug-in to keep the connection to the source alive until all events using readers have been sent to the Audit Vault Server.
If the collector wants to reset the Connection
to the source, it
must do so immediately after setting the checkpoint. This is because the Collection
Framework sends batches of records, and then sets the checkpoint. The time the ckeckpoint
is sent is the only time that the collector knows that all records are flushed to Oracle
Audit Vault Server. Note that there are other occasions that records are sent to the Oracle
Audit Vault Server, but this is the only one with a checkpoint.
If the Reader
instance cannot be obtained directly, then the
collector must create and return a Reader
.
Example 4-15 Creating Large Fields
public Reader getCommandText() throws AuditEventCollectorException {
try {
Clob clob = m_resultSet.getClob("SQL_TEXT");
return clob.getCharacterStream();
} catch (SQLException ex) {
throw new AuditEventCollectorException(
ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
}
}
4.5.12 Creating Markers to Uniquely Identify Records
See an example of how to create a marker, and review guidelines for how to create markers for Oracle Audit Vault and Database Firewall.
The collector must generate markers which the collection framework uses to uniquely identify a record.
The collector must generate a unique marker for each record in a particular trail. It can use more than one event field to create a marker. It can even use information not present in the audit event, such as, table name, file name, file creation time, and so on if it is not a template-based collection plug-in. Smaller sized markers are preferred because they take less time to create, less space in recovery phase, and less time to match. Markers are useful in certain scenarios, particularly in the recovery phase, where any records which were sent after the last checkpoint must be filtered. When the collection plug-in starts collecting events, it starts from the last checkpoint of the last run. However, some records might have been collected after that checkpoint and sent to the Audit Vault Server. To prevent duplication, the Collection Framework compares incoming records against existing records in the Audit Vault Server using the record markers.
In the following example, The strings Session_ID
and
Entry_ID
are used to form a marker.
Example 4-16 Creating Markers
public String getMarker() throws AuditEventCollectorException {
// ENTRY_ID will identify an audit event uniquely with in a session. Hence
// ENTRY_ID along with SESSION_ID will uniquely identify an audit event
// across sessions.
try {
return m_resultSet.getString("SESSION_ID") + ":"
+ m_resultSet.getString("ENTRY_ID");
} catch (SQLException ex) {
throw new AuditEventCollectorException(
ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
}
}
4.5.13 Closing the Java-Based Collection Plug-in
See how you can close a Java-based collection plug-in for Oracle Audit Vault and Database Firewall.
The process of closing a Java-based collection plug-in begins when the Collection Framework receives a command to stop collecting a particular audit trail, causing the Collection Framework to notify the collector using the close()
method. In this method, the collector performs clean-up tasks, such as closing database connections or file handles. Once the close()
method returns control to the Collection Framework, the collection thread ends.
This method should not result in any exceptions errors. In case of an exception, it should log an error message, as shown in the following example.
Example 4-17 Calling Close and Releasing Resources
public void close() {
try {
if (m_resultSet != null) {
m_resultSet.close();
m_resultSet = null;
}
if (m_connectionManager != null) {
m_connectionManager.destroy();
m_connectionManager = null;
}
m_previousCheckpoint = null;
m_nextCheckpoint = null;
m_logger = null;
} catch (SQLException ex) {
m_logger.logError("SampleEventCollector", "close",
"SQLException occurred. ", ex);
} catch (AuditException ex) {
m_logger.logError("SampleEventCollector", "close",
"AuditException occurred. ", ex);
}
}
4.5.14 Using Exceptions in Collection Plug-ins
An Oracle Audit Vault and Database Firewall collector can generate several different types of exceptions.
The collector can throw the following two checked exceptions:
AuditEventCollectorException
and
SetAttributeException
.
The setAttribute
method can throw the
SetAttributeException
exception when the method cannot set a new
attribute. Upon receiving this exception, it is possible that the Collection Framework
does not stop the collector (see an example in "Changing Audit Vault and Database
Firewall Attributes at Run Time").
The rest of the methods except the close
method throw
AuditEventCollectorException
. This exception must be thrown only if
an unrecoverable condition has occurred. Upon receiving this exception, the Collection
Framework stops the collector. Before stopping the collector, the Collection Framework
calls close
method. See the previous sections for sample code to create
and throw these exceptions.
Related Topics
4.6 Java-Based Collection Plug-in Utility APIs
In addition to the Collection Framework, the Oracle Audit Vault API includes Java utility APIs that make the task of writing a collector easier.
4.6.1 About Connection to Database Sources Using ConnectionManager API
All of the Oracle Audit Vault and Database Firewall components (collectors, agents,
and server) that are written in Java must use the ConnectionManager
API to
manage their connections to databases.
You use the ConnectionManager
API to manage connections to
source databases, such as Oracle Database, Microsoft SQL Server, Sybase Adaptive Server,
and IBM DB2.
Benefits of Using the ConnectionManager API
-
It reduces the resource usage on the database server.
-
It makes client-side operations more graceful, so clients do not hang or die abruptly.
-
It provides better performance.
You must instantiate a concrete implementation of the connection manager with the appropriate parameters required for setting up a connection pool. Several constructors are available for use. All optional parameters that are not supplied by the caller take default Oracle Audit Vault-specific values, as follows:
-
CONNECTION_FACTORY_CLASSNAME=oracle.jdbc.pool.OracleDataSource
-
MIN_POOL_SIZE=0
-
INACTIVE_CONNECTION_TIMEOUT=1800
-
INITIAL_POOL_SIZE=0
-
VALIDATE_CONNECTION_ON_BORROW=true
4.6.2 Example of Using the ConnectionManager API to Connect to Database Sources
See how to use the ConnectionManager API to manage Oracle Audit Vault and Database Firewall Java compnent connections to databases.
ConnectionManager
API is based on the acquire, use, and release
model for managing the database connections. All of the Oracle Audit Vault and Database
Firewall components (collectors, agents, and server) that are written in Java must use the
ConnectionManager API to manage their connections to databases.
- Create an instance of ConnectionManager API.
- Get a connection to a database.
- Use the connection
- Release the connection back to the pool.
- Repeat steps 2 through 4 as many times as needed.
- Destroy the Connection Manager instance.
Example 4-18 Using the Connection Manager to Handle Connection Pooling
//Connection Manager
ConnectionManager cManager = null;
try {
/*
* Connection Pool Properties.
* Set the pool properties such as URL
* Initial pool size, Min pool size, etc.
* The set of supported connection pool properties are
* documented in the Oracle UCP documentation
*/
Properties pProps = new Properties();
pProps.put(URL, "jdbc:oracle:thin:@hostname:port:sid");
/*
* Connection Properties
*
* Set the connection properties here.
* The set of connection properties that can be set
* depends on the driver. To enable SSL using the
* the oracle jdbc driver, you need to set the following
* Properties cProps = new Properties();
* String walletLoc = "/path/to/walletdirectory/cwallet.sso";
* cProps.setProperty("oracle.net.authentication_services","(TCPS)");
* cProps.setProperty("javax.net.ssl.trustStore", walletLoc);
* cProps.setProperty("oracle.net.ssl_server_dn_match", "true") ;
* cProps.setProperty("javax.net.ssl.trustStoreType","SSO");
* cProps.setProperty("javax.net.ssl.keyStore", walletLoc);
* cProps.setProperty("javax.net.ssl.keyStoreType","SSO");
*/
Properties cProps = new Properties();
cManager = new ConnectionManagerImpl(pProps, cProps);
String username;
char[] passwd;
Connection conn = null;
/* Do something */
...
/* Retrieve and set the username and password for user1 */
username = "user1";
passwd = "user1passwd".toCharArray();
/* Get a connection as "user1"*/
conn = cManager.getConnection(username, passwd);
/* Use the "user1" connection and do something useful */
...
/* Release the connection */
cManager.releaseConnection(conn);
/* Retrieve and set the username and password for user2 */
username = "user2";
passwd = "user2passwd".toCharArray();
/* Get a connection as "user2" */
conn = cManager.getConnection(username, passwd);
/* Use the "user2" connection and do something useful */
...
/* Release the connection */
cManager.releaseConnection(conn);
} catch (Exception e) {
/* Take appropriate action here */
} finally {
if (cManager != null) {
try {
cManager.destroy();
} catch (AuditException ae) {
/* Take appropriate action here */
}
}
The ConnectionManager
API is designed so that a caller can
acquire and release database connections using different user credentials at any point in
time. For example, a caller can acquire a connection using alice
's database
credentials, and then later on acquire a connection with robert
's database
credentials using the same connection manager.
Note:
Ensure that the caller does not do the following:
- Keep a reference to the connection locally (through an instance or class variable).
- Hold on to the connection for a long time.
These requirements enable the connection pool to automatically recover connections that have the following behaviors:
- They have exceeded the
TIME_TO_LIVE
time limit. - They have abandoned connections, that is, connections that have not been in use for a while.
- There are connections that have been borrowed too many times. This requirement ensures that they to avoid resource leaks.
Related Topics
4.6.3 Using the Windows Event Log Access API
To parse Microsoft Windows event logs, you can use the Microsoft Windows
EventLog
API.
The Windows EventLog
API is a wrapper on Windows APIs that
access the Windows Event Log. This API is available only on the Windows platform, for collectors
that need to extract audit records.
The following diagram shows the classes that you can use to parse the Windows event logs.
Figure 4-3 Structure of Windows Event Logs

Description of "Figure 4-3 Structure of Windows Event Logs"
The EventLogRecord
class contains one record in the event log.
The EventLogReader
class helps to fetch event log records one by one. Operator
classes help filter the event log records. An operator works on a particular field of event log
record and determines whether the record is to be filtered based on the value of the field. For
example, you can use the Equals
operator to filter all event log records where
the value of the field does not equal the value specified. The InRange
and
OutsideRange
operators are ternary operators. The rest are binary operators.
To collect event log records, follow these steps:
Related Topics
4.6.4 Using Windows EventMetaData API
To obtain metadata of events, you can use this Microsoft Windows Metadata Java API procedure.
Microsoft Windows provides a new API that can obtain metadata of events from version 2008 and on. Given a publisher name, this API obtains metadata for each event. The following figure illustrates how the Windows Metadata Java is a wrapper over the Windows API.
The EventMetaDataRecord
contains the metadata of one event.
The EventMetaDataReader
helps to fetch event metadata records one by one.
Use this API as follows:
4.6.5 Using the AVLogger API to Log Messages
To log errors, warnings, informational, and debug messages into the Oracle Audit Vault
and Database Firewall logs, you can use the AVLogger
API.
Example 4-19 Using the AVLogger API
import oracle.av.platform.common.util.AVLogger;
import oracle.av.platform.common.exception.AuditException;
import oracle.av.platform.common.AuditErrorCodes;
public class Test
{
public static void main(String[] args) {
/* Logger objects */
AVLogger myModule = null;
try {
/* get Logger instances; this will auto-create the logger instance */
/* if one does not exist */
myModule = AVLogger.getLogger("someModule");
/* print INFO level message */
/* check log level if you are concatenating strings to avoid expensive */
/* string operations */
if(myModule.isInfoEnabled()) {
avServer.logInfo("Testing INFO level message...." + "another String" +
"one more string");
}
/* No need to check the log level if there is no string concatenation */
myModule.logInfo("Testing INFO level message for another component....");
/* changing the log level dynamically */
myModule.setLogLevel(AVLogger.AV_LOG_LEVEL_DEBUG);
myModule.logWarn("Testing WARN level message ....");
myModule.logDebug("Testing DEBUG level message ....");
/* Reset the log level back to INFO */
myModule.setLogLevel(AVLogger.AV_LOG_LEVEL_INFO);
/* Testing Exceptions: For now on, all exceptions will have */
/* an OAV-XXXX error code printed out automatically as long as */
/* they derive from AuditException object */
throw new AuditException (ErrorCodes.INTERNAL_ERROR, null, null);
} catch (Exception e) {
myModule.logError(e);
}
}
}
Related Topics
4.6.6 Using the Oracle XML Developer's Kit to Parse XML Files
If you are developing collections, then you can use the Oracle XML Developer's Kit to parse XML files and extract audit records from them.
The Oracle XML Developer's Kit is included. and available to use to develop collections.
See Also:
Oracle XML Developer's Kit Programmer's Guide for detailed information.
4.7 Using an Audit Trail Cleanup with Java-Based Collection Plug-ins
Learn how you can enable audit trail clean-up on the source after Oracle Audit Vault and Database Firewall has archived an audit trail.
Audit trail clean-up is a feature that some sources provide to remove audit records after they have been archived. If this type of feature exists in the source, then an Oracle Audit Vault collection plug-in can integrate with the feature, to tell the source to what extent the audit trail has been archived. When Oracle Audit Vault provides archive status information, a source is enabled to clean up the audit trail (remove the original audit data) to that point, because the Oracle Audit Vault status indicates that the audit trail is archived, and deleting the audit trail to the point of the archive record results in no loss of data. The Oracle Audit Vault collection plug-in gives the clean-up utility information about the checkpoint, which is he point up to which data has been collected.
The collection plug-in can write archive status information into the directory
agent_home\av\atc
, to a file with a
trail-specific name, using the following syntax
SecuredTargetName_TrailID.atc
(for example,
oracl_1.atc
).
The content of the atc
file should consist of the following:
securedTargetType=Oracle
SecuredTargetName=orcl
TrailType=TABLE
TrailName=sys.aud$
2016-04-15 10:26:53.7
(This time stamp represents the last checkpoint for these settings.)
The target clean-up utility can parse the checkpoint from the atc
file and purge audit records till this timestamp from audit trail.
For example, Oracle Database sources provide a target cleanup utility, in the
DMBS_AUDIT_MGMT
PL/SQL package. The Oracle Database prepackaged
collection plug-ins integrate with the DMBS_AUDIT_MGMT
package, which
enables audit trail cleanup operations on the source.
4.8 Java-Based Collection Plug-in Security Considerations
Oracle strongly recommends that you review security guidelines before developing Java-based collection plug-ins.
For sources, such as databases, that require a connection in order to extract audit records, it is your responsibility, as the developer, to properly document the privileges needed to perform this task. Oracle recommends that the account used for connection have only the minimal privileges needed for the job. Any extra privileges can create a security issue.
You must also parse the input audit records properly, and protect Oracle Audit Vault and Database Firewall (Oracle AVDV) from malicious data. For instance, audit records can be crafted to inject SQL or HTML into the audit trail, which could expose data stored in Oracle AVDF to attacks. You must ensure that all incoming audit data is sanitized properly before it is given to the Collection Framework.