[MRM-1302] add some prevention for concurrent modification of a list

Merged from: r917398


git-svn-id: https://svn.apache.org/repos/asf/archiva/branches/archiva-1.3.x@917399 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Brett Porter 2010-03-01 06:01:43 +00:00
parent 56d17960c0
commit d62eb54fde
1 changed files with 73 additions and 53 deletions

View File

@ -88,6 +88,14 @@ import org.codehaus.redback.integration.filter.authentication.HttpAuthenticator;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
/** /**
* @plexus.component role="org.apache.maven.archiva.webdav.ArchivaDavResourceFactory" * @plexus.component role="org.apache.maven.archiva.webdav.ArchivaDavResourceFactory"
*/ */
@ -207,9 +215,12 @@ public class ArchivaDavResourceFactory
} }
else else
{ {
resource = // make a copy to avoid potential concurrent modifications (eg. by configuration)
processRepositoryGroup( request, archivaLocator, repoGroupConfig.getRepositories(), // TODO: ultimately, locking might be more efficient than copying in this fashion since updates are
activePrincipal, resourcesInAbsolutePath ); // infrequent
ArrayList<String> repositories = new ArrayList<String>( repoGroupConfig.getRepositories() );
resource = processRepositoryGroup( request, archivaLocator, repositories, activePrincipal,
resourcesInAbsolutePath );
} }
} }
else else
@ -222,8 +233,8 @@ public class ArchivaDavResourceFactory
} }
catch ( RepositoryNotFoundException e ) catch ( RepositoryNotFoundException e )
{ {
throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Invalid repository: " + throw new DavException( HttpServletResponse.SC_NOT_FOUND,
archivaLocator.getRepositoryId() ); "Invalid repository: " + archivaLocator.getRepositoryId() );
} }
catch ( RepositoryException e ) catch ( RepositoryException e )
{ {
@ -235,15 +246,16 @@ public class ArchivaDavResourceFactory
resource = processRepository( request, archivaLocator, activePrincipal, managedRepository ); resource = processRepository( request, archivaLocator, activePrincipal, managedRepository );
String logicalResource = RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ); String logicalResource = RepositoryPathUtil.getLogicalResource( locator.getResourcePath() );
resourcesInAbsolutePath.add( new File( managedRepository.getRepoRoot(), logicalResource ).getAbsolutePath() ); resourcesInAbsolutePath.add( new File( managedRepository.getRepoRoot(),
logicalResource ).getAbsolutePath() );
} }
String requestedResource = request.getRequestURI(); String requestedResource = request.getRequestURI();
// MRM-872 : merge all available metadata // MRM-872 : merge all available metadata
// merge metadata only when requested via the repo group // merge metadata only when requested via the repo group
if ( ( repositoryRequest.isMetadata( requestedResource ) || repositoryRequest.isMetadataSupportFile( requestedResource ) ) && if ( ( repositoryRequest.isMetadata( requestedResource ) || repositoryRequest.isMetadataSupportFile(
repoGroupConfig != null ) requestedResource ) ) && repoGroupConfig != null )
{ {
// this should only be at the project level not version level! // this should only be at the project level not version level!
if ( isProjectReference( requestedResource ) ) if ( isProjectReference( requestedResource ) )
@ -252,19 +264,19 @@ public class ArchivaDavResourceFactory
artifactId = StringUtils.substringAfterLast( artifactId, "/" ); artifactId = StringUtils.substringAfterLast( artifactId, "/" );
ArchivaDavResource res = (ArchivaDavResource) resource; ArchivaDavResource res = (ArchivaDavResource) resource;
String filePath = String filePath = StringUtils.substringBeforeLast( res.getLocalResource().getAbsolutePath().replace(
StringUtils.substringBeforeLast( res.getLocalResource().getAbsolutePath().replace( '\\', '/' ), "/" ); '\\', '/' ), "/" );
filePath = filePath + "/maven-metadata-" + repoGroupConfig.getId() + ".xml"; filePath = filePath + "/maven-metadata-" + repoGroupConfig.getId() + ".xml";
// for MRM-872 handle checksums of the merged metadata files // for MRM-872 handle checksums of the merged metadata files
if ( repositoryRequest.isSupportFile( requestedResource ) ) if ( repositoryRequest.isSupportFile( requestedResource ) )
{ {
File metadataChecksum = File metadataChecksum = new File( filePath + "." + StringUtils.substringAfterLast(
new File( filePath + "." + StringUtils.substringAfterLast( requestedResource, "." ) ); requestedResource, "." ) );
if ( metadataChecksum.exists() ) if ( metadataChecksum.exists() )
{ {
LogicalResource logicalResource = LogicalResource logicalResource = new LogicalResource( RepositoryPathUtil.getLogicalResource(
new LogicalResource( RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ) ); locator.getResourcePath() ) );
resource = resource =
new ArchivaDavResource( metadataChecksum.getAbsolutePath(), logicalResource.getPath(), new ArchivaDavResource( metadataChecksum.getAbsolutePath(), logicalResource.getPath(),
@ -298,8 +310,8 @@ public class ArchivaDavResourceFactory
{ {
File resourceFile = writeMergedMetadataToFile( mergedMetadata, filePath ); File resourceFile = writeMergedMetadataToFile( mergedMetadata, filePath );
LogicalResource logicalResource = LogicalResource logicalResource = new LogicalResource(
new LogicalResource( RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ) ); RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ) );
resource = resource =
new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(),
@ -348,7 +360,7 @@ public class ArchivaDavResourceFactory
for ( String repositoryId : repositories ) for ( String repositoryId : repositories )
{ {
ManagedRepositoryContent managedRepository = null; ManagedRepositoryContent managedRepository;
try try
{ {
managedRepository = repositoryFactory.getManagedRepositoryContent( repositoryId ); managedRepository = repositoryFactory.getManagedRepositoryContent( repositoryId );
@ -364,8 +376,8 @@ public class ArchivaDavResourceFactory
try try
{ {
DavResource updatedResource = DavResource updatedResource = processRepository( request, archivaLocator, activePrincipal,
processRepository( request, archivaLocator, activePrincipal, managedRepository ); managedRepository );
if ( resource == null ) if ( resource == null )
{ {
resource = updatedResource; resource = updatedResource;
@ -376,7 +388,8 @@ public class ArchivaDavResourceFactory
{ {
logicalResource = logicalResource.substring( 1 ); logicalResource = logicalResource.substring( 1 );
} }
resourcesInAbsolutePath.add( new File( managedRepository.getRepoRoot(), logicalResource ).getAbsolutePath() ); resourcesInAbsolutePath.add( new File( managedRepository.getRepoRoot(),
logicalResource ).getAbsolutePath() );
} }
catch ( DavException e ) catch ( DavException e )
{ {
@ -448,8 +461,8 @@ public class ArchivaDavResourceFactory
{ {
// Perform an adjustment of the resource to the managed // Perform an adjustment of the resource to the managed
// repository expected path. // repository expected path.
String localResourcePath = String localResourcePath = repositoryRequest.toNativePath( logicalResource.getPath(),
repositoryRequest.toNativePath( logicalResource.getPath(), managedRepository ); managedRepository );
resourceFile = new File( managedRepository.getRepoRoot(), localResourcePath ); resourceFile = new File( managedRepository.getRepoRoot(), localResourcePath );
resource = resource =
new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(),
@ -467,8 +480,7 @@ public class ArchivaDavResourceFactory
if ( fromProxy ) if ( fromProxy )
{ {
String event = String event = ( previouslyExisted ? AuditEvent.MODIFY_FILE : AuditEvent.CREATE_FILE ) +
( previouslyExisted ? AuditEvent.MODIFY_FILE : AuditEvent.CREATE_FILE ) +
PROXIED_SUFFIX; PROXIED_SUFFIX;
log.debug( "Proxied artifact '" + resourceFile.getName() + "' in repository '" + log.debug( "Proxied artifact '" + resourceFile.getName() + "' in repository '" +
@ -503,9 +515,11 @@ public class ArchivaDavResourceFactory
if ( !VersionUtil.isSnapshot( artifact.getVersion() ) ) if ( !VersionUtil.isSnapshot( artifact.getVersion() ) )
{ {
// check if artifact already exists and if artifact re-deployment to the repository is allowed // check if artifact already exists and if artifact re-deployment to the repository is allowed
if ( managedRepository.hasContent( artifact ) && managedRepository.getRepository().isBlockRedeployments() ) if ( managedRepository.hasContent( artifact ) &&
managedRepository.getRepository().isBlockRedeployments() )
{ {
log.warn( "Overwriting released artifacts in repository '" + managedRepository.getId() + "' is not allowed." ); log.warn( "Overwriting released artifacts in repository '" + managedRepository.getId() +
"' is not allowed." );
throw new DavException( HttpServletResponse.SC_CONFLICT, throw new DavException( HttpServletResponse.SC_CONFLICT,
"Overwriting released artifacts is not allowed." ); "Overwriting released artifacts is not allowed." );
} }
@ -532,8 +546,9 @@ public class ArchivaDavResourceFactory
destDir.mkdirs(); destDir.mkdirs();
String relPath = PathUtil.getRelative( rootDirectory.getAbsolutePath(), destDir ); String relPath = PathUtil.getRelative( rootDirectory.getAbsolutePath(), destDir );
log.debug( "Creating destination directory '" + destDir.getName() + "' (current user '" + log.debug(
activePrincipal + "')" ); "Creating destination directory '" + destDir.getName() + "' (current user '" + activePrincipal +
"')" );
triggerAuditEvent( request.getRemoteAddr(), managedRepository.getId(), relPath, triggerAuditEvent( request.getRemoteAddr(), managedRepository.getId(), relPath,
AuditEvent.CREATE_DIR, activePrincipal ); AuditEvent.CREATE_DIR, activePrincipal );
@ -555,8 +570,8 @@ public class ArchivaDavResourceFactory
} }
catch ( RepositoryNotFoundException e ) catch ( RepositoryNotFoundException e )
{ {
throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Invalid repository: " + throw new DavException( HttpServletResponse.SC_NOT_FOUND,
archivaLocator.getRepositoryId() ); "Invalid repository: " + archivaLocator.getRepositoryId() );
} }
catch ( RepositoryException e ) catch ( RepositoryException e )
{ {
@ -622,7 +637,8 @@ public class ArchivaDavResourceFactory
catch ( ProxyDownloadException e ) catch ( ProxyDownloadException e )
{ {
log.error( e.getMessage(), e ); log.error( e.getMessage(), e );
throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unable to fetch artifact resource." ); throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Unable to fetch artifact resource." );
} }
return false; return false;
} }
@ -715,6 +731,7 @@ public class ArchivaDavResourceFactory
} }
// TODO: remove? // TODO: remove?
private void triggerAuditEvent( String remoteIP, String repositoryId, String resource, String action, private void triggerAuditEvent( String remoteIP, String repositoryId, String resource, String action,
String principal ) String principal )
{ {
@ -811,9 +828,10 @@ public class ArchivaDavResourceFactory
AuthenticationResult result = httpAuth.getAuthenticationResult( request, null ); AuthenticationResult result = httpAuth.getAuthenticationResult( request, null );
SecuritySession securitySession = httpAuth.getSecuritySession( request.getSession( true ) ); SecuritySession securitySession = httpAuth.getSecuritySession( request.getSession( true ) );
return servletAuth.isAuthenticated( request, result ) && return servletAuth.isAuthenticated( request, result ) && servletAuth.isAuthorized( request, securitySession,
servletAuth.isAuthorized( request, securitySession, repositoryId, repositoryId,
WebdavMethodUtil.getMethodPermission( request.getMethod() ) ); WebdavMethodUtil.getMethodPermission(
request.getMethod() ) );
} }
catch ( AuthenticationException e ) catch ( AuthenticationException e )
{ {
@ -821,8 +839,7 @@ public class ArchivaDavResourceFactory
String guest = UserManager.GUEST_USERNAME; String guest = UserManager.GUEST_USERNAME;
try try
{ {
if ( servletAuth.isAuthorized( if ( servletAuth.isAuthorized( guest,
guest,
( (ArchivaDavResourceLocator) request.getRequestLocator() ).getRepositoryId(), ( (ArchivaDavResourceLocator) request.getRequestLocator() ).getRepositoryId(),
WebdavMethodUtil.getMethodPermission( request.getMethod() ) ) ) WebdavMethodUtil.getMethodPermission( request.getMethod() ) ) )
{ {
@ -915,8 +932,9 @@ public class ArchivaDavResourceFactory
catch ( DavException e ) catch ( DavException e )
{ {
// TODO: review exception handling // TODO: review exception handling
log.debug( "Skipping repository '" + managedRepository + "' for user '" + activePrincipal + log.debug(
"': " + e.getMessage() ); "Skipping repository '" + managedRepository + "' for user '" + activePrincipal + "': " +
e.getMessage() );
} }
} }
else else
@ -925,7 +943,8 @@ public class ArchivaDavResourceFactory
try try
{ {
if ( servletAuth.isAuthorized( activePrincipal, repository, if ( servletAuth.isAuthorized( activePrincipal, repository,
WebdavMethodUtil.getMethodPermission( request.getMethod() ) ) ) WebdavMethodUtil.getMethodPermission(
request.getMethod() ) ) )
{ {
mergedRepositoryContents.add( resourceFile ); mergedRepositoryContents.add( resourceFile );
log.debug( "Repository '" + repository + "' accessed by '" + activePrincipal + "'" ); log.debug( "Repository '" + repository + "' accessed by '" + activePrincipal + "'" );
@ -934,8 +953,9 @@ public class ArchivaDavResourceFactory
catch ( UnauthorizedException e ) catch ( UnauthorizedException e )
{ {
// TODO: review exception handling // TODO: review exception handling
log.debug( "Skipping repository '" + managedRepository + "' for user '" + activePrincipal + log.debug(
"': " + e.getMessage() ); "Skipping repository '" + managedRepository + "' for user '" + activePrincipal + "': " +
e.getMessage() );
} }
} }
} }
@ -946,9 +966,9 @@ public class ArchivaDavResourceFactory
throw new UnauthorizedDavException( locator.getRepositoryId(), "User not authorized." ); throw new UnauthorizedDavException( locator.getRepositoryId(), "User not authorized." );
} }
ArchivaVirtualDavResource resource = ArchivaVirtualDavResource resource = new ArchivaVirtualDavResource( mergedRepositoryContents,
new ArchivaVirtualDavResource( mergedRepositoryContents, logicalResource.getPath(), mimeTypes, locator, logicalResource.getPath(), mimeTypes,
this ); locator, this );
// compatibility with MRM-440 to ensure browsing the repository group works ok // compatibility with MRM-440 to ensure browsing the repository group works ok
if ( resource.isCollection() && !request.getRequestURI().endsWith( "/" ) ) if ( resource.isCollection() && !request.getRequestURI().endsWith( "/" ) )
@ -1002,8 +1022,8 @@ public class ArchivaDavResourceFactory
{ {
try try
{ {
if ( servletAuth.isAuthorized( activePrincipal, repository, if ( servletAuth.isAuthorized( activePrincipal, repository, WebdavMethodUtil.getMethodPermission(
WebdavMethodUtil.getMethodPermission( request.getMethod() ) ) ) request.getMethod() ) ) )
{ {
allow = true; allow = true;
break; break;