]> source.dussan.org Git - archiva.git/commitdiff
[MRM-564] Audit log is not populated when artifacts are deployed.
authorJoakim Erdfelt <joakime@apache.org>
Thu, 8 Nov 2007 18:36:12 +0000 (18:36 +0000)
committerJoakim Erdfelt <joakime@apache.org>
Thu, 8 Nov 2007 18:36:12 +0000 (18:36 +0000)
Expanded Audit concepts into listener / event / log.
Using log4j for audit log (for consistency with other logging)
Moved AuditLog from webapp to repository-layer.

git-svn-id: https://svn.apache.org/repos/asf/maven/archiva/trunk@593246 13f79535-47bb-0310-9956-ffa450edef68

archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/audit/AuditEvent.java [new file with mode: 0644]
archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/audit/AuditListener.java [new file with mode: 0644]
archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/audit/AuditLog.java [new file with mode: 0644]
archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/audit/Auditable.java [new file with mode: 0644]
archiva-web/archiva-webapp/pom.xml
archiva-web/archiva-webapp/src/appserver-base/conf/archiva.xml [deleted file]
archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/AuditLog.java [deleted file]
archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/ProxiedDavServer.java
archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/RepositoryServlet.java
archiva-web/archiva-webapp/src/main/resources/log4j.xml

diff --git a/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/audit/AuditEvent.java b/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/audit/AuditEvent.java
new file mode 100644 (file)
index 0000000..399c820
--- /dev/null
@@ -0,0 +1,112 @@
+package org.apache.maven.archiva.repository.audit;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * AuditEvent 
+ *
+ * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class AuditEvent
+{
+    public static final String CREATE_DIR = "Created Directory";
+
+    public static final String CREATE_FILE = "Created File";
+
+    public static final String REMOVE_DIR = "Removed Directory";
+
+    public static final String REMOVE_FILE = "Removed File";
+
+    public static final String MODIFY_FILE = "Modify File";
+    
+    private String repositoryId;
+
+    private String userId;
+    
+    private String remoteIP;
+
+    private String resource;
+
+    private String action;
+
+    public AuditEvent()
+    {
+        /* do nothing */
+    }
+
+    public AuditEvent( String repoId, String user, String resource, String action )
+    {
+        this.repositoryId = repoId;
+        this.userId = user;
+        this.resource = resource;
+        this.action = action;
+    }
+
+    public String getRepositoryId()
+    {
+        return repositoryId;
+    }
+
+    public void setRepositoryId( String repositoryId )
+    {
+        this.repositoryId = repositoryId;
+    }
+
+    public String getUserId()
+    {
+        return userId;
+    }
+
+    public void setUserId( String userId )
+    {
+        this.userId = userId;
+    }
+
+    public String getResource()
+    {
+        return resource;
+    }
+
+    public void setResource( String resource )
+    {
+        this.resource = resource;
+    }
+
+    public String getAction()
+    {
+        return action;
+    }
+
+    public void setAction( String action )
+    {
+        this.action = action;
+    }
+
+    public String getRemoteIP()
+    {
+        return remoteIP;
+    }
+
+    public void setRemoteIP( String remoteIP )
+    {
+        this.remoteIP = remoteIP;
+    }
+}
diff --git a/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/audit/AuditListener.java b/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/audit/AuditListener.java
new file mode 100644 (file)
index 0000000..7335e96
--- /dev/null
@@ -0,0 +1,36 @@
+package org.apache.maven.archiva.repository.audit;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * AuditListener 
+ *
+ * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public interface AuditListener
+{
+    /**
+     * Notification that an audit event occured. 
+     * 
+     * @param event the event details.
+     */
+    public void auditEvent( AuditEvent event );
+}
diff --git a/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/audit/AuditLog.java b/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/audit/AuditLog.java
new file mode 100644 (file)
index 0000000..2dcc30f
--- /dev/null
@@ -0,0 +1,56 @@
+package org.apache.maven.archiva.repository.audit;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.log4j.Logger;
+
+/**
+ * AuditLog - Audit Log. 
+ *
+ * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
+ * @version $Id$
+ * 
+ * @plexus.component role="org.apache.maven.archiva.repository.audit.AuditListener"
+ *                   role-hint="logging"
+ */
+public class AuditLog
+    implements AuditListener
+{
+    public static final Logger logger = Logger.getLogger( "org.apache.archiva.AuditLog" );
+    
+    private static final char DELIM = ' '; 
+
+    /**
+     * Creates a log message in the following format ...
+     * 
+     * "{repository_id} {user_id} {remote_ip} \"{resource}\" \"{action}\""
+     */
+    public void auditEvent( AuditEvent event )
+    {
+        StringBuffer msg = new StringBuffer();
+        msg.append( event.getRepositoryId() ).append( DELIM );
+        msg.append( event.getUserId() ).append( DELIM );
+        msg.append( event.getRemoteIP() ).append( DELIM );
+        msg.append( '\"' ).append( event.getResource() ).append( '\"' ).append( DELIM );
+        msg.append( '\"' ).append( event.getAction() ).append( '\"' );
+
+        logger.info( msg.toString() );
+    }
+}
diff --git a/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/audit/Auditable.java b/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/audit/Auditable.java
new file mode 100644 (file)
index 0000000..949d2c3
--- /dev/null
@@ -0,0 +1,48 @@
+package org.apache.maven.archiva.repository.audit;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Auditable 
+ *
+ * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public interface Auditable
+{
+    /**
+     * Add an AuditListener.
+     * 
+     * @param the listener to add.
+     */
+    public void addAuditListener( AuditListener auditListener );
+
+    /**
+     * Remove an AuditListener.
+     * 
+     * @param the listener to remove.
+     */
+    public void removeAuditListener( AuditListener auditListener );
+
+    /**
+     * Remove all registered {@link AuditListener} objects.
+     */
+    public void clearAuditListeners();
+}
index 342dd6260cb9c838fb6cdea6a6f60e5d7e29cd2a..db05ca8fa141bb6fabbef42b8f71fec7382fe961 100644 (file)
           </roleDefaults>
         </configuration>
       </plugin>
-      <!--
       <plugin>
         <artifactId>maven-antrun-plugin</artifactId>
         <executions>
           </execution>
         </executions>
       </plugin>
-       -->
     </plugins>
   </build>
   <profiles>
diff --git a/archiva-web/archiva-webapp/src/appserver-base/conf/archiva.xml b/archiva-web/archiva-webapp/src/appserver-base/conf/archiva.xml
deleted file mode 100644 (file)
index 0d3c7ed..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration>
-  <version>2</version>
-  <managedRepositories>
-    <managedRepository>
-      <id>internal</id>
-      <name>Archiva Managed Internal Repository</name>
-      <location>${appserver.base}/data/repositories/internal</location>
-      <layout>default</layout>
-      <releases>true</releases>
-      <snapshots>false</snapshots>
-      <scanned>true</scanned>
-      <refreshCronExpression>0 0 0 * * ?</refreshCronExpression>
-      <daysOlder>30</daysOlder>
-    </managedRepository>
-    <managedRepository>
-      <id>snapshots</id>
-      <name>Archiva Managed Snapshot Repository</name>
-      <location>${appserver.base}/data/repositories/snapshots</location>
-      <layout>default</layout>
-      <releases>false</releases>
-      <snapshots>true</snapshots>
-      <scanned>true</scanned>
-      <refreshCronExpression>0 0\,30 0 * * ?</refreshCronExpression>
-      <daysOlder>30</daysOlder>
-    </managedRepository>
-  </managedRepositories>
-  <remoteRepositories>
-    <remoteRepository>
-      <id>central</id>
-      <name>Central Repository</name>
-      <url>http://repo1.maven.org/maven2</url>
-      <layout>default</layout>
-    </remoteRepository>
-    <remoteRepository>
-      <id>maven2-repository.dev.java.net</id>
-      <name>Java.net Repository for Maven 2</name>
-      <url>http://download.java.net/maven/2/</url>
-      <layout>default</layout>
-    </remoteRepository>
-  </remoteRepositories>
-
-  <proxyConnectors>
-    <proxyConnector>
-      <sourceRepoId>internal</sourceRepoId>
-      <targetRepoId>central</targetRepoId>
-      <proxyId/>
-      <policies>
-        <snapshots>disabled</snapshots>
-        <releases>once</releases>
-        <checksum>fix</checksum>
-        <cache-failures>cached</cache-failures>
-      </policies>
-      <whiteListPatterns>
-        <whiteListPattern>**/*</whiteListPattern>
-      </whiteListPatterns>
-    </proxyConnector>
-    <proxyConnector>
-      <sourceRepoId>internal</sourceRepoId>
-      <targetRepoId>maven2-repository.dev.java.net</targetRepoId>
-      <proxyId/>
-      <policies>
-        <snapshots>disabled</snapshots>
-        <releases>once</releases>
-        <checksum>fix</checksum>
-        <cache-failures>cached</cache-failures>
-      </policies>
-      <whiteListPatterns>
-        <whiteListPattern>javax/**</whiteListPattern>
-      </whiteListPatterns>
-    </proxyConnector>
-  </proxyConnectors>
-
-  <repositoryScanning>
-    <fileTypes>
-      <fileType>
-        <id>artifacts</id>
-        <patterns>
-          <pattern>**/*.pom</pattern>
-          <pattern>**/*.jar</pattern>
-          <pattern>**/*.ear</pattern>
-          <pattern>**/*.war</pattern>
-          <pattern>**/*.car</pattern>
-          <pattern>**/*.sar</pattern>
-          <pattern>**/*.mar</pattern>
-          <pattern>**/*.rar</pattern>
-          <pattern>**/*.dtd</pattern>
-          <pattern>**/*.tld</pattern>
-          <pattern>**/*.tar.gz</pattern>
-          <pattern>**/*.tar.bz2</pattern>
-          <pattern>**/*.zip</pattern>
-        </patterns>
-      </fileType>
-      <fileType>
-        <id>indexable-content</id>
-        <patterns>
-          <pattern>**/*.txt</pattern>
-          <pattern>**/*.TXT</pattern>
-          <pattern>**/*.block</pattern>
-          <pattern>**/*.config</pattern>
-          <pattern>**/*.pom</pattern>
-          <pattern>**/*.xml</pattern>
-          <pattern>**/*.xsd</pattern>
-          <pattern>**/*.dtd</pattern>
-          <pattern>**/*.tld</pattern>
-        </patterns>
-      </fileType>
-      <fileType>
-        <id>auto-remove</id>
-        <patterns>
-          <pattern>**/*.bak</pattern>
-          <pattern>**/*~</pattern>
-          <pattern>**/*-</pattern>
-        </patterns>
-      </fileType>
-      <fileType>
-        <id>ignored</id>
-        <patterns>
-          <pattern>**/.htaccess</pattern>
-          <pattern>**/KEYS</pattern>
-          <pattern>**/*.rb</pattern>
-          <pattern>**/*.sh</pattern>
-          <pattern>**/.svn/**</pattern>
-          <pattern>**/.DAV/**</pattern>
-        </patterns>
-      </fileType>
-    </fileTypes>
-    <knownContentConsumers>
-      <knownContentConsumer>update-db-artifact</knownContentConsumer>
-      <knownContentConsumer>create-missing-checksums</knownContentConsumer>
-      <knownContentConsumer>update-db-repository-metadata</knownContentConsumer>
-      <knownContentConsumer>validate-checksum</knownContentConsumer>
-      <knownContentConsumer>validate-signature</knownContentConsumer>
-      <knownContentConsumer>index-content</knownContentConsumer>
-      <knownContentConsumer>auto-remove</knownContentConsumer>
-      <knownContentConsumer>auto-rename</knownContentConsumer>
-      <knownContentConsumer>metadata-updater</knownContentConsumer>
-      <!--knownContentConsumer>repository-purge</knownContentConsumer-->
-    </knownContentConsumers>
-    <invalidContentConsumers>
-      <invalidContentConsumer>update-db-bad-content</invalidContentConsumer>
-    </invalidContentConsumers>
-  </repositoryScanning>
-
-  <databaseScanning>
-    <cronExpression>0 0 0 * * ?</cronExpression>
-    <unprocessedConsumers>
-      <unprocessedConsumer>index-artifact</unprocessedConsumer>
-      <unprocessedConsumer>update-db-project</unprocessedConsumer>
-      <unprocessedConsumer>validate-repository-metadata</unprocessedConsumer>
-      <unprocessedConsumer>index-archive-toc</unprocessedConsumer>
-      <unprocessedConsumer>update-db-bytecode-stats</unprocessedConsumer>
-      <unprocessedConsumer>index-public-methods</unprocessedConsumer>
-    </unprocessedConsumers>
-    <cleanupConsumers>
-      <cleanupConsumer>not-present-remove-db-artifact</cleanupConsumer>
-      <cleanupConsumer>not-present-remove-db-project</cleanupConsumer>
-      <cleanupConsumer>not-present-remove-indexed</cleanupConsumer>
-    </cleanupConsumers>
-  </databaseScanning>
-
-  <webapp>
-    <ui>
-      <showFindArtifacts>true</showFindArtifacts>
-      <appletFindEnabled>true</appletFindEnabled>
-    </ui>
-  </webapp>
-
-</configuration>
diff --git a/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/AuditLog.java b/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/AuditLog.java
deleted file mode 100644 (file)
index a6a50b4..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-package org.apache.maven.archiva.web.repository;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.commons.lang.StringUtils;
-import org.codehaus.plexus.evaluator.EvaluatorException;
-import org.codehaus.plexus.evaluator.ExpressionEvaluator;
-import org.codehaus.plexus.evaluator.ExpressionSource;
-import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
-import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
-import org.codehaus.plexus.webdav.DavServerComponent;
-import org.codehaus.plexus.webdav.DavServerListener;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-/**
- * AuditLog - Audit Log. 
- *
- * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
- * @version $Id$
- * 
- * @plexus.component role="org.apache.maven.archiva.web.repository.AuditLog"
- */
-public class AuditLog
-    implements DavServerListener, Initializable
-{
-    public static final String ROLE = AuditLog.class.getName();
-
-    /**
-     * @plexus.configuration default-value="${appserver.base}/logs/audit.log"
-     */
-    private String logFilename;
-
-    /**
-     * @plexus.configuration default-value="yyyy-MM-dd HH:mm:ss"
-     */
-    private String timestampFormat;
-
-    /**
-     * @plexus.requirement role-hint="default"
-     */
-    private ExpressionEvaluator expressionEvaluator;
-
-    /**
-     * @plexus.requirement role-hint="sysprops"
-     */
-    private ExpressionSource syspropExprSource;
-
-    private File logFile;
-
-    private PrintWriter writer;
-
-    private SimpleDateFormat timestamp;
-
-    private String getServerId( DavServerComponent server )
-    {
-        return "[" + server.getPrefix() + "]";
-    }
-
-    public void serverCollectionCreated( DavServerComponent server, String resource )
-    {
-        log( getServerId( server ) + " Created Directory \"" + resource + "\"" );
-    }
-
-    public void serverCollectionRemoved( DavServerComponent server, String resource )
-    {
-        log( getServerId( server ) + " Removed Directory \"" + resource + "\"" );
-    }
-
-    public void serverResourceCreated( DavServerComponent server, String resource )
-    {
-        log( getServerId( server ) + " Created File \"" + resource + "\"" );
-    }
-
-    public void serverResourceModified( DavServerComponent server, String resource )
-    {
-        log( getServerId( server ) + " Modified Existing File \"" + resource + "\"" );
-    }
-
-    public void serverResourceRemoved( DavServerComponent server, String resource )
-    {
-        log( getServerId( server ) + " Removed File \"" + resource + "\"" );
-    }
-
-    /**
-     * Log the message to the file.
-     * 
-     * @param msg the message.
-     */
-    public void log( String msg )
-    {
-        // Synchronize to prevent threading issues.
-        synchronized ( writer )
-        {
-            writer.println( timestamp.format( new Date() ) + " - " + msg );
-            // Manually flush buffer to ensure data is written to disk.
-            writer.flush();
-        }
-    }
-
-    public void initialize()
-        throws InitializationException
-    {
-        String actualFilename;
-        try
-        {
-            expressionEvaluator.addExpressionSource( syspropExprSource );
-            actualFilename = expressionEvaluator.expand( this.logFilename );
-        }
-        catch ( EvaluatorException e1 )
-        {
-            actualFilename = this.logFilename;
-        }
-
-        this.logFile = new File( actualFilename );
-
-        File parentDir = logFile.getParentFile();
-        if ( parentDir != null )
-        {
-            if ( !parentDir.exists() )
-            {
-                parentDir.mkdirs();
-            }
-        }
-
-        if ( StringUtils.isBlank( timestampFormat ) )
-        {
-            timestampFormat = "yyyy-MM-dd HH:mm:ss";
-        }
-
-        timestamp = new SimpleDateFormat( timestampFormat );
-
-        try
-        {
-            writer = new PrintWriter( new FileWriter( logFile ) );
-            log( "Logging Initialized." );
-        }
-        catch ( IOException e )
-        {
-            throw new InitializationException( "Unable to initialize log file writer: " + logFile.getAbsolutePath(), e );
-        }
-    }
-}
index 69dca5d1aa4a0bd8fc0e86dc37f2420560ce1214..ad9fc7039dcd246caf4931756765465fb7aedcee 100644 (file)
@@ -19,6 +19,7 @@ package org.apache.maven.archiva.web.repository;
  * under the License.
  */
 
+import org.apache.maven.archiva.common.utils.PathUtil;
 import org.apache.maven.archiva.model.ArtifactReference;
 import org.apache.maven.archiva.model.ProjectReference;
 import org.apache.maven.archiva.model.VersionedReference;
@@ -28,10 +29,14 @@ import org.apache.maven.archiva.repository.ManagedRepositoryContent;
 import org.apache.maven.archiva.repository.RepositoryContentFactory;
 import org.apache.maven.archiva.repository.RepositoryException;
 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
+import org.apache.maven.archiva.repository.audit.AuditEvent;
+import org.apache.maven.archiva.repository.audit.AuditListener;
+import org.apache.maven.archiva.repository.audit.Auditable;
 import org.apache.maven.archiva.repository.content.RepositoryRequest;
 import org.apache.maven.archiva.repository.layout.LayoutException;
 import org.apache.maven.archiva.repository.metadata.MetadataTools;
 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
+import org.apache.maven.archiva.security.ArchivaUser;
 import org.apache.maven.model.DistributionManagement;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.Relocation;
@@ -49,6 +54,8 @@ import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
@@ -64,12 +71,18 @@ import javax.servlet.http.HttpServletResponse;
  */
 public class ProxiedDavServer
     extends AbstractDavServerComponent
+    implements Auditable
 {
     /**
      * @plexus.requirement role-hint="simple"
      */
     private DavServerComponent davServer;
-
+    
+    /**
+     * @plexus.requirement role="org.apache.maven.archiva.repository.audit.AuditListener"
+     */
+    private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
+    
     /**
      * @plexus.requirement
      */
@@ -89,6 +102,11 @@ public class ProxiedDavServer
      * @plexus.requirement
      */
     private MetadataTools metadataTools;
+    
+    /**
+     * @plexus.requirement role-hint="xwork"
+     */
+    private ArchivaUser archivaUser;
 
     private ManagedRepositoryContent managedRepository;
 
@@ -136,11 +154,11 @@ public class ProxiedDavServer
     {
         boolean isGet = WebdavMethodUtil.isReadMethod( request.getRequest().getMethod() );
         boolean isPut = WebdavMethodUtil.isWriteMethod( request.getRequest().getMethod() );
+        String resource = request.getLogicalResource();
         
         if ( isGet )
         {
             // Default behaviour is to treat the resource natively.
-            String resource = request.getLogicalResource();
             File resourceFile = new File( managedRepository.getRepoRoot(), resource );
 
             // If this a directory resource, then we are likely browsing.
@@ -173,8 +191,13 @@ public class ProxiedDavServer
                 // Adjust the pathInfo resource to be in the format that the dav server impl expects.
                 request.getRequest().setPathInfo( resource );
 
+                boolean previouslyExisted = resourceFile.exists();
+                
                 // Attempt to fetch the resource from any defined proxy.
-                fetchContentFromProxies( request, resource );
+                if( fetchContentFromProxies( request, resource ) )
+                {
+                    processAuditEvents( request, resource, previouslyExisted, resourceFile, " (proxied)" );
+                }
             }
             catch ( LayoutException e )
             {
@@ -217,12 +240,24 @@ public class ProxiedDavServer
             File rootDirectory = getRootDirectory();
             if ( rootDirectory != null )
             {
-                new File( rootDirectory, request.getLogicalResource() ).getParentFile().mkdirs();
+                File destDir = new File( rootDirectory, resource ).getParentFile();
+                if( !destDir.exists() )
+                {
+                    destDir.mkdirs();
+                    String relPath = PathUtil.getRelative( rootDirectory.getAbsolutePath(), destDir );
+                    triggerAuditEvent( request, relPath, AuditEvent.CREATE_DIR );
+                }
             }
             
+            File resourceFile = new File( managedRepository.getRepoRoot(), resource );
+            
+            boolean previouslyExisted = resourceFile.exists();
+            
             // Allow the dav server to process the put request.
             davServer.process( request, response );
             
+            processAuditEvents( request, resource, previouslyExisted, resourceFile, null );
+            
             // All done.
             return;
         }
@@ -277,7 +312,7 @@ public class ProxiedDavServer
         }
     }
 
-    private void fetchContentFromProxies( DavServerRequest request, String resource )
+    private boolean fetchContentFromProxies( DavServerRequest request, String resource )
         throws ServletException
     {
         if ( repositoryRequest.isSupportFile( resource ) )
@@ -285,16 +320,13 @@ public class ProxiedDavServer
             // Checksums are fetched with artifact / metadata.
             
             // Need to adjust the path for the checksum resource.
-            return;
+            return false;
         }
 
         // Is it a Metadata resource?
         if ( repositoryRequest.isDefault( resource ) && repositoryRequest.isMetadata( resource ) )
         {
-            if ( fetchMetadataFromProxies( request, resource ) )
-            {
-                return;
-            }
+            return fetchMetadataFromProxies( request, resource );
         }
 
         // Not any of the above? Then it's gotta be an artifact reference.
@@ -307,11 +339,11 @@ public class ProxiedDavServer
             {
                 applyServerSideRelocation( artifact );
 
-                connectors.fetchFromProxies( managedRepository, artifact );
+                File proxiedFile = connectors.fetchFromProxies( managedRepository, artifact );
                 
                 // Set the path to the resource using managed repository specific layout format.
                 request.getRequest().setPathInfo( managedRepository.toPath( artifact ) );
-                return;
+                return ( proxiedFile != null );
             }
         }
         catch ( LayoutException e )
@@ -322,6 +354,7 @@ public class ProxiedDavServer
         {
             throw new ServletException( "Unable to fetch artifact resource.", e );
         }
+        return false;
     }
 
     private boolean fetchMetadataFromProxies( DavServerRequest request, String resource )
@@ -481,4 +514,82 @@ public class ProxiedDavServer
     {
         return managedRepository;
     }
+    
+    private void processAuditEvents( DavServerRequest request, String resource, boolean previouslyExisted,
+                                     File resourceFile, String suffix )
+    {
+        if( suffix == null )
+        {
+            suffix = "";
+        }
+        
+        // Process Create Audit Events.
+        if ( !previouslyExisted && resourceFile.exists() )
+        {
+            if ( resourceFile.isFile() )
+            {
+                triggerAuditEvent( request, resource, AuditEvent.CREATE_FILE + suffix );
+            }
+            else if ( resourceFile.isDirectory() )
+            {
+                triggerAuditEvent( request, resource, AuditEvent.CREATE_DIR + suffix );
+            }
+        }
+        // Process Remove Audit Events.
+        else if ( previouslyExisted && !resourceFile.exists() )
+        {
+            if ( resourceFile.isFile() )
+            {
+                triggerAuditEvent( request, resource, AuditEvent.REMOVE_FILE + suffix );
+            }
+            else if ( resourceFile.isDirectory() )
+            {
+                triggerAuditEvent( request, resource, AuditEvent.REMOVE_DIR + suffix );
+            }
+        }
+        // Process modify events.
+        else
+        {
+            if ( resourceFile.isFile() )
+            {
+                triggerAuditEvent( request, resource, AuditEvent.MODIFY_FILE + suffix );
+            }
+        }
+    }
+    
+    private void triggerAuditEvent( String user, String remoteIP, String resource, String action )
+    {
+        AuditEvent event = new AuditEvent( this.getPrefix(), user, resource, action );
+        event.setRemoteIP( remoteIP );
+
+        for ( AuditListener listener : auditListeners )
+        {
+            listener.auditEvent( event );
+        }
+    }
+
+    private void triggerAuditEvent( DavServerRequest request, String resource, String action )
+    {
+        triggerAuditEvent( archivaUser.getActivePrincipal(), getRemoteIP( request ), resource, action );
+    }
+
+    private String getRemoteIP( DavServerRequest request )
+    {
+        return request.getRequest().getRemoteAddr();
+    }
+
+    public void addAuditListener( AuditListener listener )
+    {
+        this.auditListeners.add( listener );
+    }
+
+    public void clearAuditListeners()
+    {
+        this.auditListeners.clear();
+    }
+
+    public void removeAuditListener( AuditListener listener )
+    {
+        this.auditListeners.remove( listener );
+    }
 }
index 61919910d913052b57f973494f9315a61f2db3ed..f0fed7486fe2d5709249192050e19b10be229253 100644 (file)
@@ -63,8 +63,6 @@ public class RepositoryServlet
 
     private HttpAuthenticator httpAuth;
 
-    private AuditLog audit;
-
     private ArchivaConfiguration configuration;
 
     private Map<String, ManagedRepositoryConfiguration> repositoryMap;
@@ -80,7 +78,6 @@ public class RepositoryServlet
         
         securitySystem = (SecuritySystem) lookup( SecuritySystem.ROLE );
         httpAuth = (HttpAuthenticator) lookup( HttpAuthenticator.ROLE, "basic" );
-        audit = (AuditLog) lookup( AuditLog.ROLE );
 
         configuration = (ArchivaConfiguration) lookup( ArchivaConfiguration.class.getName() );
         configuration.addListener( this );
@@ -108,7 +105,6 @@ public class RepositoryServlet
             DavServerComponent server = createServer( repo.getId(), repoDir, servletConfig );
 
             server.setUseIndexHtml( true );
-            server.addListener( audit );
         }
     }
     
@@ -132,14 +128,6 @@ public class RepositoryServlet
             log( "Unable to release HttpAuth : " + e.getMessage(), e );
         }
         try
-        {
-            release( audit );
-        }
-        catch ( ServletException e )
-        {
-            log( "Unable to release AuditLog : " + e.getMessage(), e );
-        }
-        try
         {
             release( configuration );
         }
index 40fb48983cf0d0bcf6950d0c49403e4ffea679cf..2a7ccf7f4d95beaf8e2f6d1418167971fe65e2cc 100644 (file)
       <param name="ConversionPattern" value="%-4r [%t] %-5p %c %x - %m%n"/>
     </layout>
   </appender>
+  
+  <appender name="auditlog" class="org.apache.log4j.DailyRollingFileAppender">
+    <param name="file" value="${appserver.base}/logs/audit.log" />
+    <param name="append" value="true" />
+    <param name="datePattern" value="'.'yyyy-MM-dd" />
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %m%n"/>
+    </layout>
+  </appender>
 
   <appender name="console" class="org.apache.log4j.ConsoleAppender">
     <param name="Target" value="System.out"/>
     <level value="debug" />
   </logger>
 
+  <logger name="org.apache.archiva.AuditLog">
+    <level value="info" />
+    <appender-ref ref="auditlog" />
+  </logger>
+  
   <logger name="org.codehaus.plexus.security">
     <level value="info"/>
   </logger>