[MRM-831] When deploying artifacts to the repo, they should be added to the index instantly. Improve audit logging as well

git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@673360 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Brett Porter 2008-07-02 11:23:05 +00:00
parent 1b3e3f374f
commit a5636c4509
7 changed files with 286 additions and 189 deletions

View File

@ -35,7 +35,15 @@ public class AuditEvent
public static final String REMOVE_FILE = "Removed File"; public static final String REMOVE_FILE = "Removed File";
public static final String MODIFY_FILE = "Modify File"; public static final String MODIFY_FILE = "Modified File";
public static final String MOVE_FILE = "Moved File";
public static final String MOVE_DIRECTORY = "Moved Directory";
public static final String COPY_DIRECTORY = "Copied Directory";
public static final String COPY_FILE = "Copied File";
public static final String UPLOAD_FILE = "Uploaded File"; public static final String UPLOAD_FILE = "Uploaded File";

View File

@ -19,24 +19,52 @@ package org.apache.maven.archiva.webdav;
* under the License. * under the License.
*/ */
import org.apache.jackrabbit.webdav.*; import java.io.File;
import org.apache.jackrabbit.webdav.property.*; import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.jackrabbit.util.Text;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.DavResource;
import org.apache.jackrabbit.webdav.DavResourceFactory;
import org.apache.jackrabbit.webdav.DavResourceIterator;
import org.apache.jackrabbit.webdav.DavResourceIteratorImpl;
import org.apache.jackrabbit.webdav.DavResourceLocator;
import org.apache.jackrabbit.webdav.DavServletResponse;
import org.apache.jackrabbit.webdav.DavSession;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
import org.apache.jackrabbit.webdav.io.InputContext; import org.apache.jackrabbit.webdav.io.InputContext;
import org.apache.jackrabbit.webdav.io.OutputContext; import org.apache.jackrabbit.webdav.io.OutputContext;
import org.apache.jackrabbit.webdav.lock.*; import org.apache.jackrabbit.webdav.lock.ActiveLock;
import org.apache.jackrabbit.util.Text; import org.apache.jackrabbit.webdav.lock.LockInfo;
import org.apache.commons.io.IOUtils; import org.apache.jackrabbit.webdav.lock.LockManager;
import org.apache.commons.io.FileUtils; import org.apache.jackrabbit.webdav.lock.Scope;
import org.apache.maven.archiva.webdav.util.MimeTypes; import org.apache.jackrabbit.webdav.lock.Type;
import org.apache.jackrabbit.webdav.property.DavProperty;
import org.apache.jackrabbit.webdav.property.DavPropertyName;
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
import org.apache.jackrabbit.webdav.property.DavPropertySet;
import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
import org.apache.jackrabbit.webdav.property.ResourceType;
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.maven.archiva.repository.audit.AuditEvent;
import org.apache.maven.archiva.repository.audit.AuditListener;
import org.apache.maven.archiva.repository.scanner.RepositoryContentConsumers;
import org.apache.maven.archiva.security.ArchivaXworkUser;
import org.apache.maven.archiva.webdav.util.IndexWriter; import org.apache.maven.archiva.webdav.util.IndexWriter;
import org.apache.maven.archiva.webdav.util.MimeTypes;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat; import org.joda.time.format.ISODateTimeFormat;
import javax.servlet.http.HttpServletResponse; import com.opensymphony.xwork.ActionContext;
import java.util.List;
import java.util.ArrayList;
import java.io.*;
/** /**
* @author <a href="mailto:james@atlassian.com">James William Dumay</a> Portions from the Apache Jackrabbit Project * @author <a href="mailto:james@atlassian.com">James William Dumay</a> Portions from the Apache Jackrabbit Project
@ -46,8 +74,6 @@ public class ArchivaDavResource
{ {
public static final String HIDDEN_PATH_PREFIX = "."; public static final String HIDDEN_PATH_PREFIX = ".";
private final MimeTypes mimeTypes;
private final ArchivaDavResourceLocator locator; private final ArchivaDavResourceLocator locator;
private final DavResourceFactory factory; private final DavResourceFactory factory;
@ -56,33 +82,51 @@ public class ArchivaDavResource
private final String logicalResource; private final String logicalResource;
private DavPropertySet properties; private DavPropertySet properties = null;
private boolean propsInitialized = false;
private LockManager lockManager; private LockManager lockManager;
private final DavSession session; private final DavSession session;
public ArchivaDavResource( String localResource, private String remoteAddr;
String logicalResource,
MimeTypes mimeTypes, private final ManagedRepositoryConfiguration repository;
DavSession session,
ArchivaDavResourceLocator locator, private final RepositoryContentConsumers consumers;
DavResourceFactory factory )
private final MimeTypes mimeTypes;
private List<AuditListener> auditListeners;
public ArchivaDavResource( String localResource, String logicalResource, ManagedRepositoryConfiguration repository,
DavSession session, ArchivaDavResourceLocator locator, DavResourceFactory factory,
MimeTypes mimeTypes, List<AuditListener> auditListeners,
RepositoryContentConsumers consumers )
{ {
this.mimeTypes = mimeTypes;
this.localResource = new File( localResource ); this.localResource = new File( localResource );
this.logicalResource = logicalResource; this.logicalResource = logicalResource;
this.locator = locator; this.locator = locator;
this.factory = factory; this.factory = factory;
this.session = session; this.session = session;
this.properties = new DavPropertySet();
// TODO: push into locator as well as moving any references out of the resource factory
this.repository = repository;
// TODO: these should be pushed into the repository layer, along with the physical file operations in this class
this.mimeTypes = mimeTypes;
this.consumers = consumers;
this.auditListeners = auditListeners;
} }
public String getContentType() public ArchivaDavResource( String localResource, String logicalResource, ManagedRepositoryConfiguration repository,
String remoteAddr, DavSession session, ArchivaDavResourceLocator locator,
DavResourceFactory factory, MimeTypes mimeTypes, List<AuditListener> auditListeners,
RepositoryContentConsumers consumers )
{ {
return mimeTypes.getMimeType( localResource.getName() ); this( localResource, logicalResource, repository, session, locator, factory, mimeTypes, auditListeners,
consumers );
this.remoteAddr = remoteAddr;
} }
public String getComplianceClass() public String getComplianceClass()
@ -133,16 +177,9 @@ public class ArchivaDavResource
public long getModificationTime() public long getModificationTime()
{ {
initProperties();
return localResource.lastModified(); return localResource.lastModified();
} }
public long getContentLength()
{
initProperties();
return localResource.length();
}
public void spool( OutputContext outputContext ) public void spool( OutputContext outputContext )
throws IOException throws IOException
{ {
@ -151,8 +188,8 @@ public class ArchivaDavResource
FileInputStream is = null; FileInputStream is = null;
try try
{ {
outputContext.setContentLength( getContentLength() ); outputContext.setContentLength( localResource.length() );
outputContext.setContentType( getContentType() ); outputContext.setContentType( mimeTypes.getMimeType( localResource.getName() ) );
// Write content to stream // Write content to stream
is = new FileInputStream( localResource ); is = new FileInputStream( localResource );
@ -177,14 +214,12 @@ public class ArchivaDavResource
public DavProperty getProperty( DavPropertyName name ) public DavProperty getProperty( DavPropertyName name )
{ {
initProperties(); return getProperties().get( name );
return properties.get( name );
} }
public DavPropertySet getProperties() public DavPropertySet getProperties()
{ {
initProperties(); return initProperties();
return properties;
} }
public void setProperty( DavProperty property ) public void setProperty( DavProperty property )
@ -203,6 +238,7 @@ public class ArchivaDavResource
return null; return null;
} }
@SuppressWarnings("unchecked")
public MultiStatusResponse alterProperties( List changeList ) public MultiStatusResponse alterProperties( List changeList )
throws DavException throws DavException
{ {
@ -236,20 +272,15 @@ public class ArchivaDavResource
throws DavException throws DavException
{ {
File localFile = new File( localResource, resource.getDisplayName() ); File localFile = new File( localResource, resource.getDisplayName() );
boolean exists = localFile.exists();
if ( isCollection() && inputContext.hasStream() ) // New File if ( isCollection() && inputContext.hasStream() ) // New File
{ {
boolean deleteFile = false;
FileOutputStream stream = null; FileOutputStream stream = null;
try try
{ {
stream = new FileOutputStream( localFile ); stream = new FileOutputStream( localFile );
IOUtils.copy( inputContext.getInputStream(), stream ); IOUtils.copy( inputContext.getInputStream(), stream );
if ( inputContext.getContentLength() != localFile.length() )
{
deleteFile = true;
throw new DavException( HttpServletResponse.SC_BAD_REQUEST, "Content Header length was " +
inputContext.getContentLength() + " but was " + localFile.length() );
}
} }
catch ( IOException e ) catch ( IOException e )
{ {
@ -258,15 +289,26 @@ public class ArchivaDavResource
finally finally
{ {
IOUtils.closeQuietly( stream ); IOUtils.closeQuietly( stream );
if ( deleteFile ) }
if ( inputContext.getContentLength() != localFile.length() )
{ {
FileUtils.deleteQuietly( localFile ); FileUtils.deleteQuietly( localFile );
throw new DavException( HttpServletResponse.SC_BAD_REQUEST, "Content Header length was " +
inputContext.getContentLength() + " but was " + localFile.length() );
} }
}
// Just-in-time update of the index and database by executing the consumers for this artifact
consumers.executeConsumers( repository, localFile );
triggerAuditEvent( resource, exists ? AuditEvent.MODIFY_FILE : AuditEvent.CREATE_FILE );
} }
else if ( !inputContext.hasStream() && isCollection() ) // New directory else if ( !inputContext.hasStream() && isCollection() ) // New directory
{ {
localFile.mkdir(); localFile.mkdir();
triggerAuditEvent( resource, AuditEvent.CREATE_DIR );
} }
else else
{ {
@ -277,7 +319,7 @@ public class ArchivaDavResource
public DavResourceIterator getMembers() public DavResourceIterator getMembers()
{ {
ArrayList list = new ArrayList(); List<DavResource> list = new ArrayList<DavResource>();
if ( exists() && isCollection() ) if ( exists() && isCollection() )
{ {
for ( String item : localResource.list() ) for ( String item : localResource.list() )
@ -291,9 +333,11 @@ public class ArchivaDavResource
locator.getFactory().createResourceLocator( locator.getPrefix(), path ); locator.getFactory().createResourceLocator( locator.getPrefix(), path );
DavResource resource = factory.createResource( resourceLocator, session ); DavResource resource = factory.createResource( resourceLocator, session );
if ( resource != null ) if ( resource != null )
{
list.add( resource ); list.add( resource );
} }
} }
}
catch ( DavException e ) catch ( DavException e )
{ {
// Should not occur // Should not occur
@ -314,14 +358,18 @@ public class ArchivaDavResource
{ {
if ( resource.isDirectory() ) if ( resource.isDirectory() )
{ {
FileUtils.deleteDirectory(resource); FileUtils.deleteDirectory( resource );
triggerAuditEvent( member, AuditEvent.REMOVE_DIR );
} }
else else
{ {
if (!resource.delete()) if ( !resource.delete() )
{ {
throw new IOException("Could not remove file"); throw new IOException( "Could not remove file" );
} }
triggerAuditEvent( member, AuditEvent.REMOVE_FILE );
} }
} }
catch ( IOException e ) catch ( IOException e )
@ -335,6 +383,14 @@ public class ArchivaDavResource
} }
} }
private void triggerAuditEvent( DavResource member, String event ) throws DavException
{
String path = logicalResource + "/" + member.getDisplayName();
triggerAuditEvent( checkDavResourceIsArchivaDavResource( member ).remoteAddr, locator.getRepositoryId(), path,
event );
}
public void move( DavResource destination ) public void move( DavResource destination )
throws DavException throws DavException
{ {
@ -349,10 +405,14 @@ public class ArchivaDavResource
if ( isCollection() ) if ( isCollection() )
{ {
FileUtils.moveDirectory( getLocalResource(), resource.getLocalResource() ); FileUtils.moveDirectory( getLocalResource(), resource.getLocalResource() );
triggerAuditEvent( remoteAddr, locator.getRepositoryId(), logicalResource, AuditEvent.MOVE_DIRECTORY );
} }
else else
{ {
FileUtils.moveFile( getLocalResource(), resource.getLocalResource() ); FileUtils.moveFile( getLocalResource(), resource.getLocalResource() );
triggerAuditEvent( remoteAddr, locator.getRepositoryId(), logicalResource, AuditEvent.MOVE_FILE );
} }
} }
catch ( IOException e ) catch ( IOException e )
@ -380,10 +440,14 @@ public class ArchivaDavResource
if ( isCollection() ) if ( isCollection() )
{ {
FileUtils.copyDirectory( getLocalResource(), resource.getLocalResource() ); FileUtils.copyDirectory( getLocalResource(), resource.getLocalResource() );
triggerAuditEvent( remoteAddr, locator.getRepositoryId(), logicalResource, AuditEvent.COPY_DIRECTORY );
} }
else else
{ {
FileUtils.copyFile( getLocalResource(), resource.getLocalResource() ); FileUtils.copyFile( getLocalResource(), resource.getLocalResource() );
triggerAuditEvent( remoteAddr, locator.getRepositoryId(), logicalResource, AuditEvent.COPY_FILE );
} }
} }
catch ( IOException e ) catch ( IOException e )
@ -485,13 +549,20 @@ public class ArchivaDavResource
/** /**
* Fill the set of properties * Fill the set of properties
*/ */
protected void initProperties() protected DavPropertySet initProperties()
{ {
if ( !exists() || propsInitialized ) if ( !exists() )
{ {
return; properties = new DavPropertySet();
} }
if ( properties != null )
{
return properties;
}
DavPropertySet properties = new DavPropertySet();
// set (or reset) fundamental properties // set (or reset) fundamental properties
if ( getDisplayName() != null ) if ( getDisplayName() != null )
{ {
@ -522,7 +593,9 @@ public class ArchivaDavResource
properties.add( new DefaultDavProperty( DavPropertyName.GETCONTENTLENGTH, localResource.length() ) ); properties.add( new DefaultDavProperty( DavPropertyName.GETCONTENTLENGTH, localResource.length() ) );
propsInitialized = true; this.properties = properties;
return properties;
} }
private ArchivaDavResource checkDavResourceIsArchivaDavResource( DavResource resource ) private ArchivaDavResource checkDavResourceIsArchivaDavResource( DavResource resource )
@ -535,4 +608,16 @@ public class ArchivaDavResource
} }
return (ArchivaDavResource) resource; return (ArchivaDavResource) resource;
} }
private void triggerAuditEvent( String remoteIP, String repositoryId, String resource, String action )
{
String activePrincipal = ArchivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
AuditEvent event = new AuditEvent( repositoryId, activePrincipal, resource, action );
event.setRemoteIP( remoteIP );
for ( AuditListener listener : auditListeners )
{
listener.auditEvent( event );
}
}
} }

View File

@ -19,23 +19,27 @@ package org.apache.maven.archiva.webdav;
* under the License. * under the License.
*/ */
import com.opensymphony.xwork.ActionContext; import java.io.File;
import org.apache.jackrabbit.webdav.*; import java.io.FileNotFoundException;
import org.apache.maven.archiva.repository.ManagedRepositoryContent; import java.io.FileReader;
import org.apache.maven.archiva.repository.RepositoryNotFoundException; import java.io.IOException;
import org.apache.maven.archiva.repository.RepositoryException; import java.util.ArrayList;
import org.apache.maven.archiva.repository.RepositoryContentFactory; import java.util.HashMap;
import org.apache.maven.archiva.repository.layout.LayoutException; import java.util.List;
import org.apache.maven.archiva.repository.content.RepositoryRequest; import java.util.Map;
import org.apache.maven.archiva.repository.audit.AuditListener;
import org.apache.maven.archiva.repository.audit.Auditable; import javax.servlet.http.HttpServletResponse;
import org.apache.maven.archiva.repository.audit.AuditEvent;
import org.apache.maven.archiva.repository.metadata.MetadataTools; import org.apache.commons.lang.StringUtils;
import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException; import org.apache.jackrabbit.webdav.DavException;
import org.apache.maven.archiva.webdav.util.WebdavMethodUtil; import org.apache.jackrabbit.webdav.DavResource;
import org.apache.maven.archiva.webdav.util.MimeTypes; import org.apache.jackrabbit.webdav.DavResourceFactory;
import org.apache.maven.archiva.webdav.util.RepositoryPathUtil; import org.apache.jackrabbit.webdav.DavResourceLocator;
import org.apache.maven.archiva.proxy.RepositoryProxyConnectors; import org.apache.jackrabbit.webdav.DavServletRequest;
import org.apache.jackrabbit.webdav.DavServletResponse;
import org.apache.jackrabbit.webdav.DavSession;
import org.apache.jackrabbit.webdav.lock.LockManager;
import org.apache.jackrabbit.webdav.lock.SimpleLockManager;
import org.apache.maven.archiva.common.utils.PathUtil; import org.apache.maven.archiva.common.utils.PathUtil;
import org.apache.maven.archiva.configuration.ArchivaConfiguration; import org.apache.maven.archiva.configuration.ArchivaConfiguration;
import org.apache.maven.archiva.configuration.RepositoryGroupConfiguration; import org.apache.maven.archiva.configuration.RepositoryGroupConfiguration;
@ -43,8 +47,24 @@ 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;
import org.apache.maven.archiva.policies.ProxyDownloadException; import org.apache.maven.archiva.policies.ProxyDownloadException;
import org.apache.maven.archiva.proxy.RepositoryProxyConnectors;
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.repository.scanner.RepositoryContentConsumers;
import org.apache.maven.archiva.security.ArchivaXworkUser; import org.apache.maven.archiva.security.ArchivaXworkUser;
import org.apache.maven.archiva.security.ServletAuthenticator; import org.apache.maven.archiva.security.ServletAuthenticator;
import org.apache.maven.archiva.webdav.util.MimeTypes;
import org.apache.maven.archiva.webdav.util.RepositoryPathUtil;
import org.apache.maven.archiva.webdav.util.WebdavMethodUtil;
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;
@ -62,15 +82,7 @@ import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletResponse; import com.opensymphony.xwork.ActionContext;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.*;
import org.apache.commons.lang.StringUtils;
import org.apache.jackrabbit.webdav.lock.LockManager;
import org.apache.jackrabbit.webdav.lock.SimpleLockManager;
/** /**
* @author <a href="mailto:james@atlassian.com">James William Dumay</a> * @author <a href="mailto:james@atlassian.com">James William Dumay</a>
@ -79,6 +91,8 @@ import org.apache.jackrabbit.webdav.lock.SimpleLockManager;
public class ArchivaDavResourceFactory public class ArchivaDavResourceFactory
implements DavResourceFactory, Auditable implements DavResourceFactory, Auditable
{ {
private static final String PROXIED_SUFFIX = " (proxied)";
private static final String HTTP_PUT_METHOD = "PUT"; private static final String HTTP_PUT_METHOD = "PUT";
private Logger log = LoggerFactory.getLogger( ArchivaDavResourceFactory.class ); private Logger log = LoggerFactory.getLogger( ArchivaDavResourceFactory.class );
@ -134,6 +148,9 @@ public class ArchivaDavResourceFactory
*/ */
private final LockManager lockManager = new SimpleLockManager(); private final LockManager lockManager = new SimpleLockManager();
/** @plexus.requirement */
private RepositoryContentConsumers consumers;
public DavResource createResource( final DavResourceLocator locator, final DavServletRequest request, public DavResource createResource( final DavResourceLocator locator, final DavServletRequest request,
final DavServletResponse response ) final DavServletResponse response )
throws DavException throws DavException
@ -142,8 +159,7 @@ public class ArchivaDavResourceFactory
ArchivaDavResourceLocator archivaLocator = (ArchivaDavResourceLocator) locator; ArchivaDavResourceLocator archivaLocator = (ArchivaDavResourceLocator) locator;
RepositoryGroupConfiguration repoGroupConfig = RepositoryGroupConfiguration repoGroupConfig =
archivaConfiguration.getConfiguration().getRepositoryGroupsAsMap().get( archivaConfiguration.getConfiguration().getRepositoryGroupsAsMap().get( archivaLocator.getRepositoryId() );
( (RepositoryLocator) locator ).getRepositoryId() );
List<String> repositories = new ArrayList<String>(); List<String> repositories = new ArrayList<String>();
boolean isGet = WebdavMethodUtil.isReadMethod( request.getMethod() ); boolean isGet = WebdavMethodUtil.isReadMethod( request.getMethod() );
@ -166,7 +182,7 @@ public class ArchivaDavResourceFactory
} }
else else
{ {
repositories.add( ( (RepositoryLocator) locator ).getRepositoryId() ); repositories.add( archivaLocator.getRepositoryId() );
} }
//MRM-419 - Windows Webdav support. Should not 404 if there is no content. //MRM-419 - Windows Webdav support. Should not 404 if there is no content.
@ -260,8 +276,9 @@ public class ArchivaDavResourceFactory
String logicalResource = RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ); String logicalResource = RepositoryPathUtil.getLogicalResource( locator.getResourcePath() );
File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource ); File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource );
resource = resource =
new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource, mimeTypes, davSession, archivaLocator, new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource,
this ); managedRepository.getRepository(), davSession, archivaLocator, this, mimeTypes,
auditListeners, consumers );
} }
resource.addLockManager(lockManager); resource.addLockManager(lockManager);
return resource; return resource;
@ -273,16 +290,18 @@ public class ArchivaDavResourceFactory
{ {
File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() ); File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() );
ArchivaDavResource resource = ArchivaDavResource resource =
new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), mimeTypes, request.getDavSession(), locator, this ); new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(),
managedRepository.getRepository(), request.getRemoteAddr(),
request.getDavSession(), locator, this, mimeTypes, auditListeners, consumers );
if ( !resource.isCollection() ) if ( !resource.isCollection() )
{ {
boolean previouslyExisted = resourceFile.exists();
// At this point the incoming request can either be in default or // At this point the incoming request can either be in default or
// legacy layout format. // legacy layout format.
boolean fromProxy = fetchContentFromProxies( managedRepository, request, logicalResource ); boolean fromProxy = fetchContentFromProxies( managedRepository, request, logicalResource );
boolean previouslyExisted = resourceFile.exists();
try try
{ {
// Perform an adjustment of the resource to the managed // Perform an adjustment of the resource to the managed
@ -303,17 +322,23 @@ public class ArchivaDavResourceFactory
// Attempt to fetch the resource from any defined proxy. // Attempt to fetch the resource from any defined proxy.
if ( fromProxy ) if ( fromProxy )
{ {
processAuditEvents( request, locator.getWorkspaceName(), logicalResource.getPath(), previouslyExisted, String repositoryId = locator.getRepositoryId();
resourceFile, " (proxied)" ); String event = ( previouslyExisted ? AuditEvent.MODIFY_FILE : AuditEvent.CREATE_FILE ) + PROXIED_SUFFIX;
triggerAuditEvent( request.getRemoteAddr(), repositoryId, logicalResource.getPath(), event );
} }
resource =
new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), mimeTypes, request.getDavSession(), locator,
this );
if ( !resourceFile.exists() ) if ( !resourceFile.exists() )
{ {
resource = null; resource = null;
} }
else
{
resource =
new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(),
managedRepository.getRepository(), request.getRemoteAddr(),
request.getDavSession(), locator, this, mimeTypes, auditListeners,
consumers );
}
} }
return resource; return resource;
} }
@ -334,18 +359,14 @@ public class ArchivaDavResourceFactory
{ {
destDir.mkdirs(); destDir.mkdirs();
String relPath = PathUtil.getRelative( rootDirectory.getAbsolutePath(), destDir ); String relPath = PathUtil.getRelative( rootDirectory.getAbsolutePath(), destDir );
triggerAuditEvent( request, logicalResource.getPath(), relPath, AuditEvent.CREATE_DIR ); triggerAuditEvent( request.getRemoteAddr(), logicalResource.getPath(), relPath, AuditEvent.CREATE_DIR );
} }
File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() ); File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() );
boolean previouslyExisted = resourceFile.exists(); return new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(),
managedRepository.getRepository(), request.getRemoteAddr(),
processAuditEvents( request, locator.getRepositoryId(), logicalResource.getPath(), previouslyExisted, request.getDavSession(), locator, this, mimeTypes, auditListeners, consumers );
resourceFile, null );
return new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), mimeTypes, request.getDavSession(), locator,
this );
} }
private boolean fetchContentFromProxies( ManagedRepositoryContent managedRepository, DavServletRequest request, private boolean fetchContentFromProxies( ManagedRepositoryContent managedRepository, DavServletRequest request,
@ -507,51 +528,11 @@ public class ArchivaDavResourceFactory
} }
} }
private void processAuditEvents( DavServletRequest request, String repositoryId, String resource, // TODO: remove?
boolean previouslyExisted, File resourceFile, String suffix ) private void triggerAuditEvent( String remoteIP, String repositoryId, String resource, String action )
{ {
if ( suffix == null ) String activePrincipal = ArchivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
{ AuditEvent event = new AuditEvent( repositoryId, activePrincipal, resource, action );
suffix = "";
}
// Process Create Audit Events.
if ( !previouslyExisted && resourceFile.exists() )
{
if ( resourceFile.isFile() )
{
triggerAuditEvent( request, repositoryId, resource, AuditEvent.CREATE_FILE + suffix );
}
else if ( resourceFile.isDirectory() )
{
triggerAuditEvent( request, repositoryId, resource, AuditEvent.CREATE_DIR + suffix );
}
}
// Process Remove Audit Events.
else if ( previouslyExisted && !resourceFile.exists() )
{
if ( resourceFile.isFile() )
{
triggerAuditEvent( request, repositoryId, resource, AuditEvent.REMOVE_FILE + suffix );
}
else if ( resourceFile.isDirectory() )
{
triggerAuditEvent( request, repositoryId, resource, AuditEvent.REMOVE_DIR + suffix );
}
}
// Process modify events.
else
{
if ( resourceFile.isFile() )
{
triggerAuditEvent( request, repositoryId, resource, AuditEvent.MODIFY_FILE + suffix );
}
}
}
private void triggerAuditEvent( String user, String remoteIP, String repositoryId, String resource, String action )
{
AuditEvent event = new AuditEvent( repositoryId, user, resource, action );
event.setRemoteIP( remoteIP ); event.setRemoteIP( remoteIP );
for ( AuditListener listener : auditListeners ) for ( AuditListener listener : auditListeners )
@ -560,17 +541,6 @@ public class ArchivaDavResourceFactory
} }
} }
private void triggerAuditEvent( DavServletRequest request, String repositoryId, String resource, String action )
{
triggerAuditEvent( ArchivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() ),
getRemoteIP( request ), repositoryId, resource, action );
}
private String getRemoteIP( DavServletRequest request )
{
return request.getRemoteAddr();
}
public void addAuditListener( AuditListener listener ) public void addAuditListener( AuditListener listener )
{ {
this.auditListeners.add( listener ); this.auditListeners.add( listener );

View File

@ -29,15 +29,15 @@ import org.apache.jackrabbit.util.Text;
public class ArchivaDavResourceLocator public class ArchivaDavResourceLocator
implements DavResourceLocator, RepositoryLocator implements DavResourceLocator, RepositoryLocator
{ {
private String prefix; private final String prefix;
private String resourcePath; private final String resourcePath;
private String href; private final String href;
private String repositoryId; private final String repositoryId;
private DavLocatorFactory davLocatorFactory; private final DavLocatorFactory davLocatorFactory;
public ArchivaDavResourceLocator( String prefix, String resourcePath, String repositoryId, public ArchivaDavResourceLocator( String prefix, String resourcePath, String repositoryId,
DavLocatorFactory davLocatorFactory ) DavLocatorFactory davLocatorFactory )
@ -45,11 +45,12 @@ public class ArchivaDavResourceLocator
this.prefix = prefix; this.prefix = prefix;
this.repositoryId = repositoryId; this.repositoryId = repositoryId;
this.davLocatorFactory = davLocatorFactory; this.davLocatorFactory = davLocatorFactory;
this.resourcePath = resourcePath;
String path = resourcePath;
if (!resourcePath.startsWith("/")) if (!resourcePath.startsWith("/"))
{ {
this.resourcePath = "/" + resourcePath; path = "/" + resourcePath;
} }
String escapedPath = Text.escapePath( resourcePath ); String escapedPath = Text.escapePath( resourcePath );
@ -66,8 +67,10 @@ public class ArchivaDavResourceLocator
//Remove trailing slashes otherwise Text.getRelativeParent fails //Remove trailing slashes otherwise Text.getRelativeParent fails
if (resourcePath.endsWith("/") && resourcePath.length() > 1) if (resourcePath.endsWith("/") && resourcePath.length() > 1)
{ {
this.resourcePath = resourcePath.substring( 0, resourcePath.length() - 1 ); path = resourcePath.substring( 0, resourcePath.length() - 1 );
} }
this.resourcePath = path;
} }
public String getRepositoryId() public String getRepositoryId()

View File

@ -19,27 +19,39 @@ package org.apache.maven.archiva.webdav;
* under the License. * under the License.
*/ */
import java.io.File;
import java.io.IOException;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.DavLocatorFactory;
import org.apache.jackrabbit.webdav.DavMethods;
import org.apache.jackrabbit.webdav.DavResource;
import org.apache.jackrabbit.webdav.DavResourceFactory;
import org.apache.jackrabbit.webdav.DavServletResponse;
import org.apache.jackrabbit.webdav.DavSessionProvider;
import org.apache.jackrabbit.webdav.WebdavRequest;
import org.apache.jackrabbit.webdav.WebdavRequestImpl;
import org.apache.jackrabbit.webdav.WebdavResponse;
import org.apache.jackrabbit.webdav.WebdavResponseImpl;
import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
import org.apache.maven.archiva.configuration.ArchivaConfiguration; import org.apache.maven.archiva.configuration.ArchivaConfiguration;
import org.apache.maven.archiva.configuration.ConfigurationEvent; import org.apache.maven.archiva.configuration.ConfigurationEvent;
import org.apache.maven.archiva.configuration.ConfigurationListener; import org.apache.maven.archiva.configuration.ConfigurationListener;
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration; import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet; import org.apache.maven.archiva.repository.audit.AuditEvent;
import org.apache.jackrabbit.webdav.*;
import org.codehaus.plexus.spring.PlexusToSpringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import org.apache.maven.archiva.security.ServletAuthenticator; import org.apache.maven.archiva.security.ServletAuthenticator;
import org.codehaus.plexus.redback.xwork.filter.authentication.HttpAuthenticator; import org.codehaus.plexus.redback.xwork.filter.authentication.HttpAuthenticator;
import org.codehaus.plexus.spring.PlexusToSpringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/** /**
* RepositoryServlet * RepositoryServlet

View File

@ -20,6 +20,8 @@ package org.apache.maven.archiva.webdav;
*/ */
import java.io.File; import java.io.File;
import java.util.List;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.jackrabbit.webdav.DavException; import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.DavResource; import org.apache.jackrabbit.webdav.DavResource;
@ -34,9 +36,15 @@ import org.apache.jackrabbit.webdav.lock.LockManager;
import org.apache.jackrabbit.webdav.lock.Scope; import org.apache.jackrabbit.webdav.lock.Scope;
import org.apache.jackrabbit.webdav.lock.SimpleLockManager; import org.apache.jackrabbit.webdav.lock.SimpleLockManager;
import org.apache.jackrabbit.webdav.lock.Type; import org.apache.jackrabbit.webdav.lock.Type;
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.maven.archiva.repository.audit.AuditListener;
import org.apache.maven.archiva.repository.scanner.RepositoryContentConsumers;
import org.apache.maven.archiva.webdav.util.MimeTypes; import org.apache.maven.archiva.webdav.util.MimeTypes;
import org.codehaus.plexus.spring.PlexusInSpringTestCase; import org.codehaus.plexus.spring.PlexusInSpringTestCase;
import org.codehaus.plexus.spring.PlexusToSpringUtils; import org.codehaus.plexus.spring.PlexusToSpringUtils;
import org.easymock.MockControl;
import edu.emory.mathcs.backport.java.util.Collections;
public class DavResourceTest extends PlexusInSpringTestCase public class DavResourceTest extends PlexusInSpringTestCase
{ {
@ -58,6 +66,10 @@ public class DavResourceTest extends PlexusInSpringTestCase
private LockManager lockManager; private LockManager lockManager;
private RepositoryContentConsumers consumers;
private ManagedRepositoryConfiguration repository = new ManagedRepositoryConfiguration();
@Override @Override
protected void setUp() protected void setUp()
throws Exception throws Exception
@ -74,6 +86,7 @@ public class DavResourceTest extends PlexusInSpringTestCase
resource = getDavResource(resourceLocator.getHref(false), myResource); resource = getDavResource(resourceLocator.getHref(false), myResource);
lockManager = new SimpleLockManager(); lockManager = new SimpleLockManager();
resource.addLockManager(lockManager); resource.addLockManager(lockManager);
consumers = new RepositoryContentConsumers();
} }
@Override @Override
@ -87,7 +100,8 @@ public class DavResourceTest extends PlexusInSpringTestCase
private DavResource getDavResource(String logicalPath, File file) private DavResource getDavResource(String logicalPath, File file)
{ {
return new ArchivaDavResource(file.getAbsolutePath(), logicalPath, mimeTypes, session, resourceLocator, resourceFactory); return new ArchivaDavResource( file.getAbsolutePath(), logicalPath, repository, session, resourceLocator,
resourceFactory, mimeTypes, Collections.emptyList(), consumers );
} }
public void testDeleteNonExistantResourceShould404() public void testDeleteNonExistantResourceShould404()
@ -287,7 +301,8 @@ public class DavResourceTest extends PlexusInSpringTestCase
} }
public DavResource createResource(DavResourceLocator locator, DavSession session) throws DavException { public DavResource createResource(DavResourceLocator locator, DavSession session) throws DavException {
return new ArchivaDavResource(baseDir.getAbsolutePath(), "/", mimeTypes, session, resourceLocator, resourceFactory); return new ArchivaDavResource( baseDir.getAbsolutePath(), "/", repository, session, resourceLocator,
resourceFactory, mimeTypes, Collections.emptyList(), consumers );
} }
} }
} }

View File

@ -148,6 +148,10 @@
<role-hint>basic</role-hint> <role-hint>basic</role-hint>
<field-name>httpAuth</field-name> <field-name>httpAuth</field-name>
</requirement> </requirement>
<requirement>
<role>org.apache.maven.archiva.repository.scanner.RepositoryContentConsumers</role>
<role-hint>default</role-hint>
</requirement>
</requirements> </requirements>
</component> </component>
</components> </components>