mirror of https://github.com/apache/archiva.git
[MRM-564] Audit log is not populated when artifacts are deployed.
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
This commit is contained in:
parent
9f4dee3c71
commit
729ad246d2
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -420,7 +420,6 @@
|
|||
</roleDefaults>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!--
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
|
@ -439,7 +438,6 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
-->
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
|
|
|
@ -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>
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
@ -90,6 +103,11 @@ public class ProxiedDavServer
|
|||
*/
|
||||
private MetadataTools metadataTools;
|
||||
|
||||
/**
|
||||
* @plexus.requirement role-hint="xwork"
|
||||
*/
|
||||
private ArchivaUser archivaUser;
|
||||
|
||||
private ManagedRepositoryContent managedRepository;
|
||||
|
||||
public String getPrefix()
|
||||
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -12,6 +12,15 @@
|
|||
</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"/>
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
|
@ -28,6 +37,11 @@
|
|||
<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>
|
||||
|
|
Loading…
Reference in New Issue