Author: oching
Date: Tue Oct 13 10:36:24 2009
New Revision: 824677
URL: http://svn.apache.org/viewvc?rev=824677&view=rev
Log:
[MRM-747] Archiva should prevent re-deployment of released or non-snapshot
versioned artifacts
submitted by Marc Lustig
o added checks in webdav to block re-deployment if artifact version already
exists in the repo and throw a 409 in such cases
o added tests for deploying and re-deploying an artifact
additional modifications to the patch:
o update checking for artifact types that will be blocked
o add tests for deploying metadata and support file
Added:
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ReleaseArtifactAlreadyExistsException.java
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/test/resources/artifact.jar.sha1
Modified:
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/AbstractRepositoryServletTestCase.java
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/RepositoryServletDeployTest.java
Modified:
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java
URL:
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java?rev=824677&r1=824676&r2=824677&view=diff
==============================================================================
---
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java
(original)
+++
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java
Tue Oct 13 10:36:24 2009
@@ -40,6 +40,7 @@
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.VersionUtil;
import org.apache.maven.archiva.configuration.ArchivaConfiguration;
import org.apache.maven.archiva.configuration.RepositoryGroupConfiguration;
import org.apache.maven.archiva.model.ArchivaRepositoryMetadata;
@@ -162,12 +163,12 @@
* @plexus.requirement role-hint="md5";
*/
private Digester digestMd5;
-
+
/**
* @plexus.requirement
*/
private ArchivaTaskScheduler scheduler;
-
+
public DavResource createResource( final DavResourceLocator locator, final
DavServletRequest request,
final DavServletResponse response )
throws DavException
@@ -190,7 +191,7 @@
throw new DavException(
HttpServletResponse.SC_METHOD_NOT_ALLOWED,
"Write method not allowed for
repository groups." );
}
-
+
log.debug( "Repository group '" + repoGroupConfig.getId() + "'
accessed by '" + activePrincipal + "'" );
// handle browse requests for virtual repos
@@ -200,9 +201,16 @@
}
else
{
- resource =
- processRepositoryGroup( request, archivaLocator,
repoGroupConfig.getRepositories(),
- activePrincipal,
resourcesInAbsolutePath );
+ try
+ {
+ resource =
+ processRepositoryGroup( request, archivaLocator,
repoGroupConfig.getRepositories(),
+ activePrincipal,
resourcesInAbsolutePath );
+ }
+ catch ( ReleaseArtifactAlreadyExistsException e )
+ {
+ throw new DavException( HttpServletResponse.SC_CONFLICT );
+ }
}
}
else
@@ -215,8 +223,8 @@
}
catch ( RepositoryNotFoundException e )
{
- throw new DavException( HttpServletResponse.SC_NOT_FOUND,
"Invalid repository: "
- + archivaLocator.getRepositoryId() );
+ throw new DavException( HttpServletResponse.SC_NOT_FOUND,
"Invalid repository: " +
+ archivaLocator.getRepositoryId() );
}
catch ( RepositoryException e )
{
@@ -225,7 +233,14 @@
log.debug( "Managed repository '" + managedRepository.getId() + "'
accessed by '" + activePrincipal + "'" );
- resource = processRepository( request, archivaLocator,
activePrincipal, managedRepository );
+ try
+ {
+ resource = processRepository( request, archivaLocator,
activePrincipal, managedRepository );
+ }
+ catch ( ReleaseArtifactAlreadyExistsException e )
+ {
+ throw new DavException( HttpServletResponse.SC_CONFLICT, e );
+ }
String logicalResource = RepositoryPathUtil.getLogicalResource(
locator.getResourcePath() );
resourcesInAbsolutePath.add( new File(
managedRepository.getRepoRoot(), logicalResource ).getAbsolutePath() );
@@ -235,8 +250,8 @@
// MRM-872 : merge all available metadata
// merge metadata only when requested via the repo group
- if ( ( repositoryRequest.isMetadata( requestedResource ) || (
requestedResource.endsWith( "metadata.xml.sha1" ) ||
requestedResource.endsWith( "metadata.xml.md5" ) ) )
- && repoGroupConfig != null )
+ if ( ( repositoryRequest.isMetadata( requestedResource ) || (
requestedResource.endsWith( "metadata.xml.sha1" ) ||
requestedResource.endsWith( "metadata.xml.md5" ) ) ) &&
+ repoGroupConfig != null )
{
// this should only be at the project level not version level!
if ( isProjectReference( requestedResource ) )
@@ -334,9 +349,9 @@
private DavResource processRepositoryGroup( final DavServletRequest
request,
ArchivaDavResourceLocator
archivaLocator, List<String> repositories,
String activePrincipal,
List<String> resourcesInAbsolutePath )
- throws DavException
+ throws DavException, ReleaseArtifactAlreadyExistsException
{
- DavResource resource = null;
+ DavResource resource = null;
List<DavException> storedExceptions = new ArrayList<DavException>();
for ( String repositoryId : repositories )
@@ -372,24 +387,24 @@
resourcesInAbsolutePath.add( new File(
managedRepository.getRepoRoot(), logicalResource ).getAbsolutePath() );
}
catch ( DavException e )
- {
+ {
storedExceptions.add( e );
}
}
if ( resource == null )
- {
+ {
if ( !storedExceptions.isEmpty() )
- {
+ {
// MRM-1232
- for( DavException e : storedExceptions )
+ for ( DavException e : storedExceptions )
{
- if( 401 == e.getErrorCode() )
+ if ( 401 == e.getErrorCode() )
{
throw e;
}
}
-
+
throw new DavException( HttpServletResponse.SC_NOT_FOUND );
}
else
@@ -402,7 +417,7 @@
private DavResource processRepository( final DavServletRequest request,
ArchivaDavResourceLocator archivaLocator,
String activePrincipal,
ManagedRepositoryContent managedRepository )
- throws DavException
+ throws DavException, ReleaseArtifactAlreadyExistsException
{
DavResource resource = null;
if ( isAuthorized( request, managedRepository.getId() ) )
@@ -412,13 +427,12 @@
{
path = path.substring( 1 );
}
- LogicalResource logicalResource = new LogicalResource( path );
+ LogicalResource logicalResource = new LogicalResource( path );
File resourceFile = new File( managedRepository.getRepoRoot(),
path );
resource =
- new ArchivaDavResource( resourceFile.getAbsolutePath(), path,
- managedRepository.getRepository(),
request.getRemoteAddr(), activePrincipal,
- request.getDavSession(),
archivaLocator, this, mimeTypes, auditListeners,
- scheduler );
+ new ArchivaDavResource( resourceFile.getAbsolutePath(), path,
managedRepository.getRepository(),
+ request.getRemoteAddr(),
activePrincipal, request.getDavSession(),
+ archivaLocator, this, mimeTypes,
auditListeners, scheduler );
if ( WebdavMethodUtil.isReadMethod( request.getMethod() ) )
{
@@ -432,7 +446,7 @@
if ( !resource.isCollection() )
{
boolean previouslyExisted = resourceFile.exists();
-
+
// Attempt to fetch the resource from any defined
proxy.
boolean fromProxy = fetchContentFromProxies(
managedRepository, request, logicalResource );
@@ -462,11 +476,11 @@
if ( fromProxy )
{
String event =
- ( previouslyExisted ? AuditEvent.MODIFY_FILE :
AuditEvent.CREATE_FILE )
- + PROXIED_SUFFIX;
-
+ ( previouslyExisted ? AuditEvent.MODIFY_FILE :
AuditEvent.CREATE_FILE ) +
+ PROXIED_SUFFIX;
+
log.debug( "Proxied artifact '" +
resourceFile.getName() + "' in repository '" +
- managedRepository.getId() + "' (current
user '" + activePrincipal + "')" );
+ managedRepository.getId() + "' (current user
'" + activePrincipal + "')" );
triggerAuditEvent( request.getRemoteAddr(),
archivaLocator.getRepositoryId(),
logicalResource.getPath(),
event, activePrincipal );
@@ -482,6 +496,35 @@
if ( request.getMethod().equals( HTTP_PUT_METHOD ) )
{
+ String resourcePath = logicalResource.getPath();
+
+ // check if target repo is enabled for releases
+ // we suppose that release-artifacts can deployed only to
repos enabled for releases
+ if ( managedRepository.getRepository().isReleases() &&
!repositoryRequest.isMetadata( resourcePath ) &&
+ !repositoryRequest.isSupportFile( resourcePath ) )
+ {
+ ArtifactReference artifact = null;
+ try
+ {
+ artifact = managedRepository.toArtifactReference(
resourcePath );
+ }
+ catch ( LayoutException e )
+ {
+ throw new DavException(
HttpServletResponse.SC_BAD_REQUEST, e );
+ }
+
+ if ( !VersionUtil.isSnapshot( artifact.getVersion() ) )
+ {
+ // check if artifact already exists
+ if ( managedRepository.hasContent( artifact ) )
+ {
+ log.warn( "Overwriting released artifacts is not
allowed." );
+ throw new ReleaseArtifactAlreadyExistsException(
managedRepository.getId(),
+
"Overwriting released artifacts is not allowed." );
+ }
+ }
+ }
+
/*
* Create parent directories that don't exist when writing a
file This actually makes this
* implementation not compliant to the WebDAV RFC - but we
have enough knowledge about how the
@@ -496,9 +539,10 @@
{
destDir.mkdirs();
String relPath = PathUtil.getRelative(
rootDirectory.getAbsolutePath(), destDir );
-
- log.debug( "Creating destination directory '" +
destDir.getName() + "' (current user '" + activePrincipal + "')" );
-
+
+ log.debug( "Creating destination directory '" +
destDir.getName() + "' (current user '" +
+ activePrincipal + "')" );
+
triggerAuditEvent( request.getRemoteAddr(),
logicalResource.getPath(), relPath,
AuditEvent.CREATE_DIR, activePrincipal
);
}
@@ -519,8 +563,8 @@
}
catch ( RepositoryNotFoundException e )
{
- throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Invalid
repository: "
- + archivaLocator.getRepositoryId() );
+ throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Invalid
repository: " +
+ archivaLocator.getRepositoryId() );
}
catch ( RepositoryException e )
{
@@ -572,8 +616,9 @@
File proxiedFile = connectors.fetchFromProxies(
managedRepository, artifact );
resource.setPath( managedRepository.toPath( artifact ) );
-
- log.debug( "Proxied artifact '" + artifact.getGroupId() + ":"
+ artifact.getArtifactId() + ":" + artifact.getVersion() + "'" );
+
+ log.debug( "Proxied artifact '" + artifact.getGroupId() + ":"
+ artifact.getArtifactId() + ":" +
+ artifact.getVersion() + "'" );
return ( proxiedFile != null );
}
@@ -774,9 +819,9 @@
AuthenticationResult result = httpAuth.getAuthenticationResult(
request, null );
SecuritySession securitySession = httpAuth.getSecuritySession(
request.getSession( true ) );
- return servletAuth.isAuthenticated( request, result )
- && servletAuth.isAuthorized( request, securitySession,
repositoryId,
-
WebdavMethodUtil.getMethodPermission( request.getMethod() ) );
+ return servletAuth.isAuthenticated( request, result ) &&
+ servletAuth.isAuthorized( request, securitySession,
repositoryId,
+
WebdavMethodUtil.getMethodPermission( request.getMethod() ) );
}
catch ( AuthenticationException e )
{
@@ -878,8 +923,8 @@
catch ( DavException e )
{
// TODO: review exception handling
- log.debug( "Skipping repository '" +
managedRepository + "' for user '" + activePrincipal
- + "': " + e.getMessage() );
+ log.debug( "Skipping repository '" +
managedRepository + "' for user '" + activePrincipal +
+ "': " + e.getMessage() );
}
}
else
@@ -897,8 +942,8 @@
catch ( UnauthorizedException e )
{
// TODO: review exception handling
- log.debug( "Skipping repository '" +
managedRepository + "' for user '" + activePrincipal
- + "': " + e.getMessage() );
+ log.debug( "Skipping repository '" +
managedRepository + "' for user '" + activePrincipal +
+ "': " + e.getMessage() );
}
}
}
@@ -1057,7 +1102,7 @@
{
this.repositoryRequest = repositoryRequest;
}
-
+
public void setConnectors( RepositoryProxyConnectors connectors )
{
this.connectors = connectors;
Added:
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ReleaseArtifactAlreadyExistsException.java
URL:
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ReleaseArtifactAlreadyExistsException.java?rev=824677&view=auto
==============================================================================
---
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ReleaseArtifactAlreadyExistsException.java
(added)
+++
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ReleaseArtifactAlreadyExistsException.java
Tue Oct 13 10:36:24 2009
@@ -0,0 +1,38 @@
+package org.apache.maven.archiva.webdav;
+
+/*
+ * 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.
+ */
+
+/**
+ */
+public class ReleaseArtifactAlreadyExistsException
+ extends Exception
+{
+ final private String repositoryName;
+
+ public ReleaseArtifactAlreadyExistsException( String repositoryName,
String message )
+ {
+ this.repositoryName = repositoryName;
+ }
+
+ public String getRepositoryName()
+ {
+ return repositoryName;
+ }
+}
Modified:
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/AbstractRepositoryServletTestCase.java
URL:
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/AbstractRepositoryServletTestCase.java?rev=824677&r1=824676&r2=824677&view=diff
==============================================================================
---
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/AbstractRepositoryServletTestCase.java
(original)
+++
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/AbstractRepositoryServletTestCase.java
Tue Oct 13 10:36:24 2009
@@ -111,6 +111,13 @@
Assert.assertEquals( "Should have been an 500/Internal Server Error
response code.", HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response
.getResponseCode() );
}
+
+ protected void assertResponseConflictError( WebResponse response )
+ {
+ assertNotNull( "Should have received a response", response );
+ Assert.assertEquals( "Should have been a 409/Conflict response code.",
HttpServletResponse.SC_CONFLICT,
+ response.getResponseCode() );
+ }
protected ManagedRepositoryConfiguration createManagedRepository( String
id, String name, File location )
{
Modified:
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/RepositoryServletDeployTest.java
URL:
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/RepositoryServletDeployTest.java?rev=824677&r1=824676&r2=824677&view=diff
==============================================================================
---
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/RepositoryServletDeployTest.java
(original)
+++
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/RepositoryServletDeployTest.java
Tue Oct 13 10:36:24 2009
@@ -38,20 +38,64 @@
public class RepositoryServletDeployTest
extends AbstractRepositoryServletTestCase
{
+ private static final String ARTIFACT_DEFAULT_LAYOUT =
"/path/to/artifact/1.0.0/artifact-1.0.0.jar";
+
public void testPutWithMissingParentCollection()
throws Exception
{
setupCleanRepo( repoRootInternal );
- String putUrl =
"http://machine.com/repository/internal/path/to/artifact.jar";
+ String putUrl = "http://machine.com/repository/internal" +
ARTIFACT_DEFAULT_LAYOUT;
InputStream is = getClass().getResourceAsStream( "/artifact.jar" );
+ // verify that the file exists in resources-dir
assertNotNull( "artifact.jar inputstream", is );
WebRequest request = new PutMethodWebRequest( putUrl, is,
"application/octet-stream" );
WebResponse response = sc.getResponse( request );
assertResponseCreated( response );
- assertFileContents( "artifact.jar\n", repoRootInternal,
"path/to/artifact.jar" );
+ assertFileContents( "artifact.jar\n", repoRootInternal,
ARTIFACT_DEFAULT_LAYOUT );
+ }
+
+ /**
+ * MRM-747
+ * test whether trying to overwrite existing relase-artifact is blocked by
returning HTTP-code 409
+ *
+ * @throws Exception
+ */
+ public void testPreventOverwritingReleaseArtifacts()
+ throws Exception
+ {
+ setupCleanRepo( repoRootInternal );
+
+ String putUrl = "http://machine.com/repository/internal" +
ARTIFACT_DEFAULT_LAYOUT;
+ String metadataUrl =
"http://machine.com/repository/internal/path/to/artifact/maven-metadata.xml";
+ String checksumUrl = "http://machine.com/repository/internal" +
ARTIFACT_DEFAULT_LAYOUT + ".sha1";
+
+ InputStream is = getClass().getResourceAsStream( "/artifact.jar" );
+ // verify that the file exists in resources-dir
+ assertNotNull( "artifact.jar inputstream", is );
+
+ // send request #1 and verify it's successful
+ WebRequest request = new PutMethodWebRequest( putUrl, is,
"application/octet-stream" );
+ WebResponse response = sc.getResponse( request );
+ assertResponseCreated( response );
+
+ is = getClass().getResourceAsStream( "/artifact.jar.sha1" );
+ request = new PutMethodWebRequest( checksumUrl, is,
"application/octet-stream" );
+ response = sc.getResponse( request );
+ assertResponseCreated( response );
+
+ is = getClass().getResourceAsStream( "/maven-metadata.xml" );
+ request = new PutMethodWebRequest( metadataUrl, is,
"application/octet-stream" );
+ response = sc.getResponse( request );
+ assertResponseCreated( response );
+
+ // send request #2 and verify it's blocked
+ is = getClass().getResourceAsStream( "/artifact.jar" );
+ request = new PutMethodWebRequest( putUrl, is,
"application/octet-stream" );
+ response = sc.getResponse( request );
+ assertResponseConflictError( response );
}
public void testMkColWithMissingParentCollectionFails()
Added:
archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/test/resources/artifact.jar.sha1
URL:
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-web/archiva-webdav/src/test/resources/artifact.jar.sha1?rev=824677&view=auto
==============================================================================
(empty)