
org.jwall.web.audit.io.ConcurrentAuditWriter Maven / Gradle / Ivy
/*
* Copyright (C) 2007-2014 Christian Bockermann
*
* This file is part of the web-audit library.
*
* web-audit library is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The web-audit library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
package org.jwall.web.audit.io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.jwall.web.audit.AuditEvent;
import org.jwall.web.audit.ModSecurity;
import org.jwall.web.audit.util.MD5;
/**
*
*
* This class implements a simple writer that writes audit-events in
* the concurrent log format of modsecurity. It can be used with the
* AuditLogger tool to create concurrent audit-logs.
*
* It can also be used to convert serial auditlogs into the concurrent
* log format.
*
* @author Christian Bockermann <[email protected]>
*
*/
public class ConcurrentAuditWriter
implements AuditEventWriter
{
/* this format maps the date to a corresponding directory (relative to the base-directory) */
public final static SimpleDateFormat DIR_FORMAT = new SimpleDateFormat("yyyyMMdd/yyyyMMdd-HHmm");
/* this format specifies the date-format used in the summary-line of the index-file */
public final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("[dd/MMM/yyyy:HH:mm:ss Z]");
/** the base-directory where the event-files are stored */
private File dir = null;
/** the path to the summary-index file */
private File idx = null;
/** counts the number of events, written by this writer */
int count = 0;
/** the writer that appends the summary lines to index-file */
PrintStream indexWriter;
/**
*
* This constructor creates a new instance of the class that writes all events to
* files within the given directory baseDir
. In addition to that, the
* writer creates summary-entries in an index-file denoted by indexFile
.
*
* @param baseDir The directory where to store the event-data files.
* @param indexFile The file to which the index-entries are appended.
* @throws IOException In case an IO-error occurs (file-permissions, etc.)
*/
public ConcurrentAuditWriter( File baseDir, File indexFile )
throws IOException
{
dir = baseDir;
if( ! dir.exists() )
if( !dir.mkdirs() )
throw new IOException("Cannot create directory "+dir.getAbsolutePath());
if( ! (dir.isDirectory() && dir.canWrite() ) )
throw new IOException("Cannot write to "+dir.getAbsolutePath());
idx = indexFile;
indexWriter = new PrintStream( new FileOutputStream( idx, true ) );
}
/**
* Create a new audit-writer that writes events into sub-directories below the given
* directory base
according to their date. The index-file is assumed to
* be the file index
within that directory.
*
* @param baseDir The base directory where the audit-data files are stored.
* @throws IOException In case base
is not a directory or cannot be created or
* is not writable.
*/
public ConcurrentAuditWriter(File baseDir)
throws IOException
{
this( baseDir, new File( baseDir.getAbsolutePath()+ "/index" ) );
}
/**
* This method writes the given audit-event evt
to a file, whose name is
* deducted from the creation time of the event. The file is created relative to the
* base-directory given at construction-time of this writer-instance.
*
* Additionally a summary-entry will be created that is appended to the index-file.
*
* @param evt The AuditEvent-instance to be written to disk.
*/
public File write(AuditEvent evt) throws IOException
{
PrintStream wr = null;
try {
File f = getFileFor( evt );
wr = new PrintStream(new FileOutputStream( f , true));
wr.print( evt.toString() );
wr.flush();
wr.close();
count++;
indexWriter.println( ConcurrentAuditWriter.createSummary( evt ) );
return f;
} catch (IOException e ){
e.printStackTrace();
}
return null;
}
public File getFileFor( AuditEvent evt ) throws IOException {
SimpleDateFormat ff = new SimpleDateFormat("yyyyMMdd-HHmmss-");
File dir = getDirectoryFor( evt.getDate() );
File f = new File( dir.getAbsolutePath() + "/" + ff.format( evt.getDate() ) + evt.getEventId() );
int j = 0;
while( f.exists() ){
if( f.getAbsolutePath().endsWith("_"+(j-1) ) )
f = new File( f.getAbsolutePath().replaceAll("_\\d+$", "_"+j) );
else
f = new File( f.getAbsolutePath() + "_" + j );
j++;
}
return f;
}
public void writeEvent( AuditEvent evt ) throws IOException {
write( evt );
}
/**
*
* This method creates the file-name for the given date and also creates the
* file itself and the corresponding subdirectories.
*
* @param date The date of an event.
* @return A file, denoting the absolute path to the events data file.
* @throws IOException In case the file or any of the subdirectories cannot be created.
*/
public File getDirectoryFor( Date date )
throws IOException
{
File f = new File( dir.getAbsolutePath() + File.separator + DIR_FORMAT.format( date ) );
if(! f.isDirectory() )
if( ! f.mkdirs() )
throw new IOException( "Could not create directory "+f.getAbsolutePath() );
return f;
}
/**
*
* This method creates a summary-string from the given audit-event. The summary is used
* within the index-file.
*
* @param evt The event to create the summary from.
* @return A string, representing the summary of the event.
*/
public static String createSummary( AuditEvent evt ){
SimpleDateFormat fn = new SimpleDateFormat("/yyyyMMdd/yyyyMMdd-HHmm/yyyyMMdd-HHmmss-");
String hash = MD5.md5( evt.toString().getBytes() );
StringBuffer sum = new StringBuffer();
sum.append( evt.get( ModSecurity.REQUEST_HEADERS + ":Host" ) );
sum.append(" ");
sum.append( evt.get( ModSecurity.REMOTE_ADDR) );
sum.append(" - - ");
sum.append( DATE_FORMAT.format( evt.getDate() ) );
sum.append(" ");
sum.append("\""+evt.get( ModSecurity.REQUEST_LINE )+"\"" );
sum.append(" ");
sum.append( evt.get( ModSecurity.RESPONSE_STATUS ) ); // status
sum.append(" 0"); // bytes out
sum.append(" \"-\""); // referer
sum.append(" \"-\""); // user-agent
sum.append(" " + evt.getEventId() ); // unique-id
sum.append(" \"" + evt.getSessionId() + "\" "); // session-id
sum.append( fn.format( evt.getDate() ) );
sum.append( evt.getEventId() ); // file-name
sum.append( " 0 "); // offset
sum.append( evt.toString().length() ); // size
sum.append( " md5:" + hash );
return sum.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy