mirror of https://github.com/apache/archiva.git
[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:
parent
56d17960c0
commit
d62eb54fde
|
@ -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"
|
||||||
*/
|
*/
|
||||||
|
@ -206,10 +214,13 @@ public class ArchivaDavResourceFactory
|
||||||
return getResource( request, repoGroupConfig.getRepositories(), archivaLocator );
|
return getResource( request, repoGroupConfig.getRepositories(), archivaLocator );
|
||||||
}
|
}
|
||||||
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 )
|
||||||
{
|
{
|
||||||
|
@ -231,19 +242,20 @@ public class ArchivaDavResourceFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug( "Managed repository '" + managedRepository.getId() + "' accessed by '" + activePrincipal + "'" );
|
log.debug( "Managed repository '" + managedRepository.getId() + "' accessed by '" + activePrincipal + "'" );
|
||||||
|
|
||||||
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,9 +480,8 @@ 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 '" +
|
||||||
managedRepository.getId() + "' (current user '" + activePrincipal + "')" );
|
managedRepository.getId() + "' (current user '" + activePrincipal + "')" );
|
||||||
|
@ -489,7 +501,7 @@ public class ArchivaDavResourceFactory
|
||||||
if ( request.getMethod().equals( HTTP_PUT_METHOD ) )
|
if ( request.getMethod().equals( HTTP_PUT_METHOD ) )
|
||||||
{
|
{
|
||||||
String resourcePath = logicalResource.getPath();
|
String resourcePath = logicalResource.getPath();
|
||||||
|
|
||||||
// check if target repo is enabled for releases
|
// check if target repo is enabled for releases
|
||||||
// we suppose that release-artifacts can be deployed only to repos enabled for releases
|
// we suppose that release-artifacts can be deployed only to repos enabled for releases
|
||||||
if ( managedRepository.getRepository().isReleases() && !repositoryRequest.isMetadata( resourcePath ) &&
|
if ( managedRepository.getRepository().isReleases() && !repositoryRequest.isMetadata( resourcePath ) &&
|
||||||
|
@ -499,13 +511,15 @@ public class ArchivaDavResourceFactory
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
artifact = managedRepository.toArtifactReference( resourcePath );
|
artifact = managedRepository.toArtifactReference( resourcePath );
|
||||||
|
|
||||||
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( "/" ) )
|
||||||
|
@ -967,7 +987,7 @@ public class ArchivaDavResourceFactory
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the current user is authorized to access any of the repos
|
* Check if the current user is authorized to access any of the repos
|
||||||
*
|
*
|
||||||
* @param request
|
* @param request
|
||||||
* @param repositories
|
* @param repositories
|
||||||
* @param activePrincipal
|
* @param activePrincipal
|
||||||
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue