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>
|
</roleDefaults>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!--
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-antrun-plugin</artifactId>
|
<artifactId>maven-antrun-plugin</artifactId>
|
||||||
<executions>
|
<executions>
|
||||||
|
@ -439,7 +438,6 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
-->
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
<profiles>
|
<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.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import org.apache.maven.archiva.common.utils.PathUtil;
|
||||||
import org.apache.maven.archiva.model.ArtifactReference;
|
import org.apache.maven.archiva.model.ArtifactReference;
|
||||||
import org.apache.maven.archiva.model.ProjectReference;
|
import org.apache.maven.archiva.model.ProjectReference;
|
||||||
import org.apache.maven.archiva.model.VersionedReference;
|
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.RepositoryContentFactory;
|
||||||
import org.apache.maven.archiva.repository.RepositoryException;
|
import org.apache.maven.archiva.repository.RepositoryException;
|
||||||
import org.apache.maven.archiva.repository.RepositoryNotFoundException;
|
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.content.RepositoryRequest;
|
||||||
import org.apache.maven.archiva.repository.layout.LayoutException;
|
import org.apache.maven.archiva.repository.layout.LayoutException;
|
||||||
import org.apache.maven.archiva.repository.metadata.MetadataTools;
|
import org.apache.maven.archiva.repository.metadata.MetadataTools;
|
||||||
import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
|
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.DistributionManagement;
|
||||||
import org.apache.maven.model.Model;
|
import org.apache.maven.model.Model;
|
||||||
import org.apache.maven.model.Relocation;
|
import org.apache.maven.model.Relocation;
|
||||||
|
@ -49,6 +54,8 @@ import java.io.FileNotFoundException;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
@ -64,12 +71,18 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
*/
|
*/
|
||||||
public class ProxiedDavServer
|
public class ProxiedDavServer
|
||||||
extends AbstractDavServerComponent
|
extends AbstractDavServerComponent
|
||||||
|
implements Auditable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @plexus.requirement role-hint="simple"
|
* @plexus.requirement role-hint="simple"
|
||||||
*/
|
*/
|
||||||
private DavServerComponent davServer;
|
private DavServerComponent davServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @plexus.requirement role="org.apache.maven.archiva.repository.audit.AuditListener"
|
||||||
|
*/
|
||||||
|
private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @plexus.requirement
|
* @plexus.requirement
|
||||||
*/
|
*/
|
||||||
|
@ -89,6 +102,11 @@ public class ProxiedDavServer
|
||||||
* @plexus.requirement
|
* @plexus.requirement
|
||||||
*/
|
*/
|
||||||
private MetadataTools metadataTools;
|
private MetadataTools metadataTools;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @plexus.requirement role-hint="xwork"
|
||||||
|
*/
|
||||||
|
private ArchivaUser archivaUser;
|
||||||
|
|
||||||
private ManagedRepositoryContent managedRepository;
|
private ManagedRepositoryContent managedRepository;
|
||||||
|
|
||||||
|
@ -136,11 +154,11 @@ public class ProxiedDavServer
|
||||||
{
|
{
|
||||||
boolean isGet = WebdavMethodUtil.isReadMethod( request.getRequest().getMethod() );
|
boolean isGet = WebdavMethodUtil.isReadMethod( request.getRequest().getMethod() );
|
||||||
boolean isPut = WebdavMethodUtil.isWriteMethod( request.getRequest().getMethod() );
|
boolean isPut = WebdavMethodUtil.isWriteMethod( request.getRequest().getMethod() );
|
||||||
|
String resource = request.getLogicalResource();
|
||||||
|
|
||||||
if ( isGet )
|
if ( isGet )
|
||||||
{
|
{
|
||||||
// Default behaviour is to treat the resource natively.
|
// Default behaviour is to treat the resource natively.
|
||||||
String resource = request.getLogicalResource();
|
|
||||||
File resourceFile = new File( managedRepository.getRepoRoot(), resource );
|
File resourceFile = new File( managedRepository.getRepoRoot(), resource );
|
||||||
|
|
||||||
// If this a directory resource, then we are likely browsing.
|
// 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.
|
// Adjust the pathInfo resource to be in the format that the dav server impl expects.
|
||||||
request.getRequest().setPathInfo( resource );
|
request.getRequest().setPathInfo( resource );
|
||||||
|
|
||||||
|
boolean previouslyExisted = resourceFile.exists();
|
||||||
|
|
||||||
// Attempt to fetch the resource from any defined proxy.
|
// 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 )
|
catch ( LayoutException e )
|
||||||
{
|
{
|
||||||
|
@ -217,12 +240,24 @@ public class ProxiedDavServer
|
||||||
File rootDirectory = getRootDirectory();
|
File rootDirectory = getRootDirectory();
|
||||||
if ( rootDirectory != null )
|
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.
|
// Allow the dav server to process the put request.
|
||||||
davServer.process( request, response );
|
davServer.process( request, response );
|
||||||
|
|
||||||
|
processAuditEvents( request, resource, previouslyExisted, resourceFile, null );
|
||||||
|
|
||||||
// All done.
|
// All done.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -277,7 +312,7 @@ public class ProxiedDavServer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchContentFromProxies( DavServerRequest request, String resource )
|
private boolean fetchContentFromProxies( DavServerRequest request, String resource )
|
||||||
throws ServletException
|
throws ServletException
|
||||||
{
|
{
|
||||||
if ( repositoryRequest.isSupportFile( resource ) )
|
if ( repositoryRequest.isSupportFile( resource ) )
|
||||||
|
@ -285,16 +320,13 @@ public class ProxiedDavServer
|
||||||
// Checksums are fetched with artifact / metadata.
|
// Checksums are fetched with artifact / metadata.
|
||||||
|
|
||||||
// Need to adjust the path for the checksum resource.
|
// Need to adjust the path for the checksum resource.
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is it a Metadata resource?
|
// Is it a Metadata resource?
|
||||||
if ( repositoryRequest.isDefault( resource ) && repositoryRequest.isMetadata( resource ) )
|
if ( repositoryRequest.isDefault( resource ) && repositoryRequest.isMetadata( resource ) )
|
||||||
{
|
{
|
||||||
if ( fetchMetadataFromProxies( request, resource ) )
|
return fetchMetadataFromProxies( request, resource );
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not any of the above? Then it's gotta be an artifact reference.
|
// Not any of the above? Then it's gotta be an artifact reference.
|
||||||
|
@ -307,11 +339,11 @@ public class ProxiedDavServer
|
||||||
{
|
{
|
||||||
applyServerSideRelocation( artifact );
|
applyServerSideRelocation( artifact );
|
||||||
|
|
||||||
connectors.fetchFromProxies( managedRepository, artifact );
|
File proxiedFile = connectors.fetchFromProxies( managedRepository, artifact );
|
||||||
|
|
||||||
// Set the path to the resource using managed repository specific layout format.
|
// Set the path to the resource using managed repository specific layout format.
|
||||||
request.getRequest().setPathInfo( managedRepository.toPath( artifact ) );
|
request.getRequest().setPathInfo( managedRepository.toPath( artifact ) );
|
||||||
return;
|
return ( proxiedFile != null );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch ( LayoutException e )
|
catch ( LayoutException e )
|
||||||
|
@ -322,6 +354,7 @@ public class ProxiedDavServer
|
||||||
{
|
{
|
||||||
throw new ServletException( "Unable to fetch artifact resource.", e );
|
throw new ServletException( "Unable to fetch artifact resource.", e );
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean fetchMetadataFromProxies( DavServerRequest request, String resource )
|
private boolean fetchMetadataFromProxies( DavServerRequest request, String resource )
|
||||||
|
@ -481,4 +514,82 @@ public class ProxiedDavServer
|
||||||
{
|
{
|
||||||
return managedRepository;
|
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 HttpAuthenticator httpAuth;
|
||||||
|
|
||||||
private AuditLog audit;
|
|
||||||
|
|
||||||
private ArchivaConfiguration configuration;
|
private ArchivaConfiguration configuration;
|
||||||
|
|
||||||
private Map<String, ManagedRepositoryConfiguration> repositoryMap;
|
private Map<String, ManagedRepositoryConfiguration> repositoryMap;
|
||||||
|
@ -80,7 +78,6 @@ public class RepositoryServlet
|
||||||
|
|
||||||
securitySystem = (SecuritySystem) lookup( SecuritySystem.ROLE );
|
securitySystem = (SecuritySystem) lookup( SecuritySystem.ROLE );
|
||||||
httpAuth = (HttpAuthenticator) lookup( HttpAuthenticator.ROLE, "basic" );
|
httpAuth = (HttpAuthenticator) lookup( HttpAuthenticator.ROLE, "basic" );
|
||||||
audit = (AuditLog) lookup( AuditLog.ROLE );
|
|
||||||
|
|
||||||
configuration = (ArchivaConfiguration) lookup( ArchivaConfiguration.class.getName() );
|
configuration = (ArchivaConfiguration) lookup( ArchivaConfiguration.class.getName() );
|
||||||
configuration.addListener( this );
|
configuration.addListener( this );
|
||||||
|
@ -108,7 +105,6 @@ public class RepositoryServlet
|
||||||
DavServerComponent server = createServer( repo.getId(), repoDir, servletConfig );
|
DavServerComponent server = createServer( repo.getId(), repoDir, servletConfig );
|
||||||
|
|
||||||
server.setUseIndexHtml( true );
|
server.setUseIndexHtml( true );
|
||||||
server.addListener( audit );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,14 +128,6 @@ public class RepositoryServlet
|
||||||
log( "Unable to release HttpAuth : " + e.getMessage(), e );
|
log( "Unable to release HttpAuth : " + e.getMessage(), e );
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
|
||||||
release( audit );
|
|
||||||
}
|
|
||||||
catch ( ServletException e )
|
|
||||||
{
|
|
||||||
log( "Unable to release AuditLog : " + e.getMessage(), e );
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
release( configuration );
|
release( configuration );
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,15 @@
|
||||||
<param name="ConversionPattern" value="%-4r [%t] %-5p %c %x - %m%n"/>
|
<param name="ConversionPattern" value="%-4r [%t] %-5p %c %x - %m%n"/>
|
||||||
</layout>
|
</layout>
|
||||||
</appender>
|
</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">
|
<appender name="console" class="org.apache.log4j.ConsoleAppender">
|
||||||
<param name="Target" value="System.out"/>
|
<param name="Target" value="System.out"/>
|
||||||
|
@ -28,6 +37,11 @@
|
||||||
<level value="debug" />
|
<level value="debug" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
|
<logger name="org.apache.archiva.AuditLog">
|
||||||
|
<level value="info" />
|
||||||
|
<appender-ref ref="auditlog" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
<logger name="org.codehaus.plexus.security">
|
<logger name="org.codehaus.plexus.security">
|
||||||
<level value="info"/>
|
<level value="info"/>
|
||||||
</logger>
|
</logger>
|
||||||
|
|
Loading…
Reference in New Issue