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.
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.
Parent topic: Java-Based Audit Trail Collection Plug-ins
For a Java-based collection plug-in, you must have the JDK to compile and test your code. Oracle recommends that you use the same JDK as the one you use to start the agent because the collection plug-in runs under the same JVM once it is shipped. Compile your classes with JDK by setting the -target
option of the javac
compiler to the same version. Refer to the JDK documentation for details.
Parent topic: Java-Based Audit Trail Collection Plug-ins
Once a collection plug-in accesses an audit trail and extracts an audit record and its related fields from the audit trail, it then maps the audit record to an Audit Vault event, and all the fields to Audit Vault fields. The collection plug-in then passes the Audit Vault event and fields to the Collection Framework, which sends the information to the Audit Vault Server.
The flow of control process for the audit trail collection is as follows:
Parent topic: Java-Based Audit Trail Collection Plug-ins
Learn about Oracle Audit Vault Java-based collection plug-in cvlasses 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
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
Parent topic: Java-Based Audit Trail Collection Plug-ins
Review the tasks required to create and use Java-based collection plug-ins for Oracle Data Vault.
AUD
.Parent topic: Java-Based Audit Trail Collection Plug-ins
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.
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 Example 4-1, 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(); } }
Parent topic: How to Create a Java-Based Collection Plug-in
Learn how to use source attributes, which provide the Oracle Data Vault 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.
Parent topic: How to Create a Java-Based Collection Plug-in
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
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
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
Other attributes that the collector may need can be returned by passing the attribute name to the getAttribute
method.
For example, if a source required SourceVersion
in order to collect audit data, then the collector for the source calls collectorContext.getAttribute('SourceVersion')
to get the value of SourceVersion
.
The getAttribute
method returns the attribute value as a String if the attribute is present. Otherwise, the method returns null.
If the collector receives a null or an invalid value for any mandatory attribute, it must throw an AuditEventCollectorException
exception from the initializeCollector
method. Then, the Collection Framework shuts down.
See Also:
Changing Audit Vault and Database Firewall Attributes at Run Time for information about changing collection plug-in attributes at run time
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(); }
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
may 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. This 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 the records, up to the upper bound, are already in the table.
As shown in Example 4-4, collectors should get the Connection
from ConnectionManager
whenever they need one.
In Example 4-5, the hasNext()
method runs the fetchEvents()
method, defined in Example 4-4, to fetch records and set checkpoints.
Example 4-4 Fetching ResultSets and Setting Checkpoints
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
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; }
Parent topic: How to Create a Java-Based Collection Plug-in
Learn about when and how the Oracle Audit Vault collection plug-in transforms source event values to Oracle Data Vault 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.
Parent topic: How to Create a Java-Based Collection Plug-in
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);
}
}
Each source event name maps to one Audit Vault event name. The getCommandClass()
method should transform the source event name into a value that 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); } }
See Also:
Oracle Audit Vault and Database Firewall Fields for a comprehensive list of Audit Vault event names.
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, 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.
Example 4-8 maps 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); } }
Target Type is the type of the object on which the 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 may 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 need to 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.
Example 4-9 maps source event ids to 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); } }
There are only three allowed values for EventStatus
. They are SUCCESS
, FAILURE
, and UNKNOWN
. Any source value must be transformed to one of these values as shown Example 4-10.
Example 4-10 Transforming Source Values to 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);
}
}
For fields that do not require transformations, the collection plug-in returns the value it obtained from the source, as shown in Example 4-11, which gets 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);
}
}
Parent topic: How to Create a Java-Based Collection Plug-in
An Oracle Audit Vault and Database Firewall administrator can update attributes, including source attributes, at run time using either the Audit Vault and Database Firewall Console or the AVCLI
command-line tool.
If the update occurs while collectors are collecting audit trails, then Audit Vault Server notifies all running collectors dynamically, by calling the setAttribute
method of the collector. Then, the collection plug-in must start using the new value immediately. If the collection plug-in does not understand the attribute or if the value cannot be used, then the collector should throw SetAttributeException
.
In Example 4-12, the collection plug-in receives and handles a new time zone offset to use in converting the EventTime
to UTC time zone for all subsequent events. This affects the time zone offset transformation that happens in Example 4-6.
See Also:
Using the CollectorContext Class When Creating a Java-Based Collection Plug-in for information about attributes and how they are initialized.
Using Exceptions in Collection Plug-ins for information about using exceptions in collection plug-ins.
Example 4-12 Changing an 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);
}
}
Parent topic: How to Create a Java-Based Collection Plug-in
Similar to AVDF attributes, you can 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); } }
Parent topic: How to Create a Java-Based Collection Plug-in
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. Example 4-14 uses the following format, repeating as needed:
<field_name>=<field_value>;
Example 4-14 sends three fields as part of the extension:
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); } }
Parent topic: How to Create a Java-Based Collection Plug-in
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 CLOB
, the Reader
can be obtained 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, making this the only time that the collector knows that all records are flushed to Audit Vault Server. Note that there are other occasions that records are sent to the Audit Vault Server, but this is the only one with a checkpoint.
If the Reader
instance cannot be obtained directly, 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);
}
}
Parent topic: How to Create a Java-Based Collection Plug-in
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.
Example 4-16 uses Session
_ID
and Entry
_ID
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); } }
Parent topic: How to Create a Java-Based Collection Plug-in
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 is not expected to throw any exceptions. In case of an exception, it should log an error message as shown in Example 4-17.
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);
}
}
Parent topic: How to Create a Java-Based Collection Plug-in
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, the Collection Framework may or may not stop the collector (see Example 4-12). 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.
Parent topic: How to Create a Java-Based Collection Plug-in
In addition to the Collection Framework, the Oracle Audit Vault API includes Java utility APIs that make the task of writing a collector easier.
ConnectionManager
API to manage their connections to databases.EventLog
API.AVLogger
API.Parent topic: Java-Based Audit Trail Collection Plug-ins
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
Parent topic: Java-Based Collection Plug-in Utility APIs
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.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:
These requirements enable the connection pool to automatically recover connections that have the following behaviors:
TIME_TO_LIVE
time limit.Related Topics
Parent topic: Java-Based Collection Plug-in Utility APIs
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
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
Parent topic: Java-Based Collection Plug-in Utility APIs
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:
Parent topic: Java-Based Collection Plug-in Utility APIs
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
Parent topic: Java-Based Collection Plug-in Utility APIs
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.
Parent topic: Java-Based Collection Plug-in Utility APIs
Audit trail clean-up is a feature that some sources provide to remove audit records once they have been archived. If this type of feature exists in the source, then an Audit Vault collection plug-in can integrate with it, to tell the source to what extent the audit trail has been archived. This enables the source to clean up the audit trail (remove the original audit data) to that point, knowing this will not result in loss of data. The Audit Vault collection plug-in gives the clean-up utility information about the checkpoint, the point up to which data has been collected.
The collection plug-in can write this information into the agent_home
\av\atc
directory, 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 be:
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 secured 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 provides this type of utility in the DMBS_AUDIT_MGMT
PL/SQL package. The Oracle Database prepackaged collection plug-ins integrate with this package to enable their audit trail cleanup operations.
Parent topic: Java-Based Audit Trail 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 may be a security issue.
You must also parse the input audit records properly and protect Oracle Audit Vault and Database Firewall from malicious data. For instance, audit records may be crafted to inject SQL or HTML into the audit trail which could expose data stored in AVDF to attacks. All incoming audit data must be properly sanitized before it is given to the Collection Framework.
Parent topic: Java-Based Audit Trail Collection Plug-ins