1 package org.apache.maven.archiva.webdav;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
23 import java.io.FileNotFoundException;
24 import java.io.FileReader;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.List;
29 import javax.servlet.http.HttpServletResponse;
31 import org.apache.commons.io.FileUtils;
32 import org.apache.commons.lang.StringUtils;
33 import org.apache.jackrabbit.webdav.DavException;
34 import org.apache.jackrabbit.webdav.DavResource;
35 import org.apache.jackrabbit.webdav.DavResourceFactory;
36 import org.apache.jackrabbit.webdav.DavResourceLocator;
37 import org.apache.jackrabbit.webdav.DavServletRequest;
38 import org.apache.jackrabbit.webdav.DavServletResponse;
39 import org.apache.jackrabbit.webdav.DavSession;
40 import org.apache.jackrabbit.webdav.lock.LockManager;
41 import org.apache.jackrabbit.webdav.lock.SimpleLockManager;
42 import org.apache.maven.archiva.common.utils.PathUtil;
43 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
44 import org.apache.maven.archiva.configuration.RepositoryGroupConfiguration;
45 import org.apache.maven.archiva.model.ArchivaRepositoryMetadata;
46 import org.apache.maven.archiva.model.ArtifactReference;
47 import org.apache.maven.archiva.policies.ProxyDownloadException;
48 import org.apache.maven.archiva.proxy.RepositoryProxyConnectors;
49 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
50 import org.apache.maven.archiva.repository.RepositoryContentFactory;
51 import org.apache.maven.archiva.repository.RepositoryException;
52 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
53 import org.apache.maven.archiva.repository.audit.AuditEvent;
54 import org.apache.maven.archiva.repository.audit.AuditListener;
55 import org.apache.maven.archiva.repository.audit.Auditable;
56 import org.apache.maven.archiva.repository.content.RepositoryRequest;
57 import org.apache.maven.archiva.repository.layout.LayoutException;
58 import org.apache.maven.archiva.repository.metadata.MetadataTools;
59 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
60 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataMerge;
61 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataReader;
62 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataWriter;
63 import org.apache.maven.archiva.repository.scanner.RepositoryContentConsumers;
64 import org.apache.maven.archiva.scheduled.ArchivaTaskScheduler;
65 import org.apache.maven.archiva.security.ServletAuthenticator;
66 import org.apache.maven.archiva.webdav.util.MimeTypes;
67 import org.apache.maven.archiva.webdav.util.RepositoryPathUtil;
68 import org.apache.maven.archiva.webdav.util.WebdavMethodUtil;
69 import org.apache.maven.model.DistributionManagement;
70 import org.apache.maven.model.Model;
71 import org.apache.maven.model.Relocation;
72 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
73 import org.codehaus.plexus.digest.ChecksumFile;
74 import org.codehaus.plexus.digest.Digester;
75 import org.codehaus.plexus.digest.DigesterException;
76 import org.codehaus.plexus.redback.authentication.AuthenticationException;
77 import org.codehaus.plexus.redback.authentication.AuthenticationResult;
78 import org.codehaus.plexus.redback.authorization.AuthorizationException;
79 import org.codehaus.plexus.redback.authorization.UnauthorizedException;
80 import org.codehaus.plexus.redback.policy.AccountLockedException;
81 import org.codehaus.plexus.redback.policy.MustChangePasswordException;
82 import org.codehaus.plexus.redback.system.SecuritySession;
83 import org.codehaus.plexus.redback.users.User;
84 import org.codehaus.plexus.redback.users.UserManager;
85 import org.codehaus.plexus.taskqueue.execution.TaskExecutor;
86 import org.codehaus.plexus.taskqueue.execution.TaskQueueExecutor;
87 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
88 import org.codehaus.redback.integration.filter.authentication.HttpAuthenticator;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
93 * @plexus.component role="org.apache.maven.archiva.webdav.ArchivaDavResourceFactory"
95 public class ArchivaDavResourceFactory
96 implements DavResourceFactory, Auditable
98 private static final String PROXIED_SUFFIX = " (proxied)";
100 private static final String HTTP_PUT_METHOD = "PUT";
102 private Logger log = LoggerFactory.getLogger( ArchivaDavResourceFactory.class );
105 * @plexus.requirement role="org.apache.maven.archiva.repository.audit.AuditListener"
107 private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
110 * @plexus.requirement
112 private RepositoryContentFactory repositoryFactory;
115 * @plexus.requirement
117 private RepositoryRequest repositoryRequest;
120 * @plexus.requirement role-hint="default"
122 private RepositoryProxyConnectors connectors;
125 * @plexus.requirement
127 private MetadataTools metadataTools;
130 * @plexus.requirement
132 private MimeTypes mimeTypes;
135 * @plexus.requirement
137 private ArchivaConfiguration archivaConfiguration;
140 * @plexus.requirement
142 private ServletAuthenticator servletAuth;
145 * @plexus.requirement role-hint="basic"
147 private HttpAuthenticator httpAuth;
150 * Lock Manager - use simple implementation from JackRabbit
152 private final LockManager lockManager = new SimpleLockManager();
155 * @plexus.requirement
157 private RepositoryContentConsumers consumers;
160 * @plexus.requirement
162 private ChecksumFile checksum;
165 * @plexus.requirement role-hint="sha1"
167 private Digester digestSha1;
170 * @plexus.requirement role-hint="md5";
172 private Digester digestMd5;
175 * @plexus.requirement role-hint="repository-scanning"
177 private TaskExecutor taskExecutor;
180 * @plexus.requirement
182 private ArchivaTaskScheduler scheduler;
185 * @plexus.requirement role-hint="repository-scanning"
187 private TaskQueueExecutor repoScanningTaskQueueExecutor;
189 public DavResource createResource( final DavResourceLocator locator, final DavServletRequest request,
190 final DavServletResponse response )
193 ArchivaDavResourceLocator archivaLocator = checkLocatorIsInstanceOfRepositoryLocator( locator );
195 RepositoryGroupConfiguration repoGroupConfig =
196 archivaConfiguration.getConfiguration().getRepositoryGroupsAsMap().get( archivaLocator.getRepositoryId() );
198 String activePrincipal = getActivePrincipal( request );
200 List<String> resourcesInAbsolutePath = new ArrayList<String>();
202 boolean readMethod = WebdavMethodUtil.isReadMethod( request.getMethod() );
203 DavResource resource;
204 if ( repoGroupConfig != null )
208 throw new DavException( HttpServletResponse.SC_METHOD_NOT_ALLOWED,
209 "Write method not allowed for repository groups." );
212 // handle browse requests for virtual repos
213 if ( RepositoryPathUtil.getLogicalResource( archivaLocator.getOrigResourcePath() ).endsWith( "/" ) )
215 return getResource( request, repoGroupConfig.getRepositories(), archivaLocator );
220 processRepositoryGroup( request, archivaLocator, repoGroupConfig.getRepositories(),
221 activePrincipal, resourcesInAbsolutePath );
226 ManagedRepositoryContent managedRepository = null;
230 managedRepository = repositoryFactory.getManagedRepositoryContent( archivaLocator.getRepositoryId() );
232 catch ( RepositoryNotFoundException e )
234 throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Invalid repository: "
235 + archivaLocator.getRepositoryId() );
237 catch ( RepositoryException e )
239 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e );
242 resource = processRepository( request, archivaLocator, activePrincipal, managedRepository );
244 String logicalResource = RepositoryPathUtil.getLogicalResource( locator.getResourcePath() );
245 resourcesInAbsolutePath.add( new File( managedRepository.getRepoRoot(), logicalResource ).getAbsolutePath() );
248 String requestedResource = request.getRequestURI();
250 // MRM-872 : merge all available metadata
251 // merge metadata only when requested via the repo group
252 if ( ( repositoryRequest.isMetadata( requestedResource ) || ( requestedResource.endsWith( "metadata.xml.sha1" ) || requestedResource.endsWith( "metadata.xml.md5" ) ) )
253 && repoGroupConfig != null )
255 // this should only be at the project level not version level!
256 if ( isProjectReference( requestedResource ) )
258 String artifactId = StringUtils.substringBeforeLast( requestedResource.replace( '\\', '/' ), "/" );
259 artifactId = StringUtils.substringAfterLast( artifactId, "/" );
261 ArchivaDavResource res = (ArchivaDavResource) resource;
263 StringUtils.substringBeforeLast( res.getLocalResource().getAbsolutePath().replace( '\\', '/' ), "/" );
264 filePath = filePath + "/maven-metadata-" + repoGroupConfig.getId() + ".xml";
266 // for MRM-872 handle checksums of the merged metadata files
267 if ( repositoryRequest.isSupportFile( requestedResource ) )
269 File metadataChecksum =
270 new File( filePath + "." + StringUtils.substringAfterLast( requestedResource, "." ) );
271 if ( metadataChecksum.exists() )
273 LogicalResource logicalResource =
274 new LogicalResource( RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ) );
277 new ArchivaDavResource( metadataChecksum.getAbsolutePath(), logicalResource.getPath(),
278 null, request.getRemoteAddr(), activePrincipal,
279 request.getDavSession(), archivaLocator, this, mimeTypes,
280 auditListeners, scheduler );
285 if ( resourcesInAbsolutePath != null && resourcesInAbsolutePath.size() > 1 )
287 // merge the metadata of all repos under group
288 ArchivaRepositoryMetadata mergedMetadata = new ArchivaRepositoryMetadata();
289 for ( String resourceAbsPath : resourcesInAbsolutePath )
293 File metadataFile = new File( resourceAbsPath );
294 ArchivaRepositoryMetadata repoMetadata = RepositoryMetadataReader.read( metadataFile );
295 mergedMetadata = RepositoryMetadataMerge.merge( mergedMetadata, repoMetadata );
297 catch ( RepositoryMetadataException r )
299 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
300 "Error occurred while reading metadata file." );
306 File resourceFile = writeMergedMetadataToFile( mergedMetadata, filePath );
308 LogicalResource logicalResource =
309 new LogicalResource( RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ) );
312 new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(),
313 null, request.getRemoteAddr(), activePrincipal,
314 request.getDavSession(), archivaLocator, this, mimeTypes,
315 auditListeners, scheduler );
317 catch ( RepositoryMetadataException r )
319 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
320 "Error occurred while writing metadata file." );
322 catch ( IOException ie )
324 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
325 "Error occurred while generating checksum files." );
327 catch ( DigesterException de )
329 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
330 "Error occurred while generating checksum files." );
337 setHeaders( response, locator, resource );
339 // compatibility with MRM-440 to ensure browsing the repository works ok
340 if ( resource.isCollection() && !request.getRequestURI().endsWith( "/" ) )
342 throw new BrowserRedirectException( resource.getHref() );
344 resource.addLockManager( lockManager );
348 private DavResource processRepositoryGroup( final DavServletRequest request,
349 ArchivaDavResourceLocator archivaLocator, List<String> repositories,
350 String activePrincipal, List<String> resourcesInAbsolutePath )
353 DavResource resource = null;
354 DavException storedException = null;
356 for ( String repositoryId : repositories )
358 ManagedRepositoryContent managedRepository = null;
362 managedRepository = repositoryFactory.getManagedRepositoryContent( repositoryId );
364 catch ( RepositoryNotFoundException e )
366 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e );
368 catch ( RepositoryException e )
370 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e );
375 DavResource updatedResource =
376 processRepository( request, archivaLocator, activePrincipal, managedRepository );
377 if ( resource == null )
379 resource = updatedResource;
382 String logicalResource = RepositoryPathUtil.getLogicalResource( archivaLocator.getResourcePath() );
383 resourcesInAbsolutePath.add( new File( managedRepository.getRepoRoot(), logicalResource ).getAbsolutePath() );
385 catch ( DavException e )
391 if ( resource == null )
393 if ( storedException != null )
395 throw storedException;
399 throw new DavException( HttpServletResponse.SC_NOT_FOUND );
405 private DavResource processRepository( final DavServletRequest request, ArchivaDavResourceLocator archivaLocator,
406 String activePrincipal, ManagedRepositoryContent managedRepository )
409 DavResource resource = null;
410 if ( isAuthorized( request, managedRepository.getId() ) )
412 LogicalResource logicalResource =
413 new LogicalResource( RepositoryPathUtil.getLogicalResource( archivaLocator.getResourcePath() ) );
415 File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() );
417 new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(),
418 managedRepository.getRepository(), request.getRemoteAddr(), activePrincipal,
419 request.getDavSession(), archivaLocator, this, mimeTypes, auditListeners,
422 if ( WebdavMethodUtil.isReadMethod( request.getMethod() ) )
424 if ( archivaLocator.getHref( false ).endsWith( "/" ) && !resourceFile.isDirectory() )
426 // force a resource not found
427 throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Resource does not exist" );
431 if ( !resource.isCollection() )
433 boolean previouslyExisted = resourceFile.exists();
435 // Attempt to fetch the resource from any defined proxy.
436 boolean fromProxy = fetchContentFromProxies( managedRepository, request, logicalResource );
438 // At this point the incoming request can either be in default or
439 // legacy layout format.
442 // Perform an adjustment of the resource to the managed
443 // repository expected path.
444 String localResourcePath =
445 repositoryRequest.toNativePath( logicalResource.getPath(), managedRepository );
446 resourceFile = new File( managedRepository.getRepoRoot(), localResourcePath );
448 new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(),
449 managedRepository.getRepository(), request.getRemoteAddr(),
450 activePrincipal, request.getDavSession(), archivaLocator, this,
451 mimeTypes, auditListeners, scheduler );
453 catch ( LayoutException e )
455 if ( !resourceFile.exists() )
457 throw new DavException( HttpServletResponse.SC_NOT_FOUND, e );
464 ( previouslyExisted ? AuditEvent.MODIFY_FILE : AuditEvent.CREATE_FILE )
466 triggerAuditEvent( request.getRemoteAddr(), archivaLocator.getRepositoryId(),
467 logicalResource.getPath(), event, activePrincipal );
470 if ( !resourceFile.exists() )
472 throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Resource does not exist" );
478 if ( request.getMethod().equals( HTTP_PUT_METHOD ) )
481 * Create parent directories that don't exist when writing a file This actually makes this
482 * implementation not compliant to the WebDAV RFC - but we have enough knowledge about how the
483 * collection is being used to do this reasonably and some versions of Maven's WebDAV don't correctly
484 * create the collections themselves.
487 File rootDirectory = new File( managedRepository.getRepoRoot() );
488 File destDir = new File( rootDirectory, logicalResource.getPath() ).getParentFile();
490 if ( !destDir.exists() )
493 String relPath = PathUtil.getRelative( rootDirectory.getAbsolutePath(), destDir );
494 triggerAuditEvent( request.getRemoteAddr(), logicalResource.getPath(), relPath,
495 AuditEvent.CREATE_DIR, activePrincipal );
502 public DavResource createResource( final DavResourceLocator locator, final DavSession davSession )
505 ArchivaDavResourceLocator archivaLocator = checkLocatorIsInstanceOfRepositoryLocator( locator );
507 ManagedRepositoryContent managedRepository;
510 managedRepository = repositoryFactory.getManagedRepositoryContent( archivaLocator.getRepositoryId() );
512 catch ( RepositoryNotFoundException e )
514 throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Invalid repository: "
515 + archivaLocator.getRepositoryId() );
517 catch ( RepositoryException e )
519 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e );
522 String logicalResource = RepositoryPathUtil.getLogicalResource( locator.getResourcePath() );
523 File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource );
524 DavResource resource =
525 new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource, managedRepository.getRepository(),
526 davSession, archivaLocator, this, mimeTypes, auditListeners, scheduler );
528 resource.addLockManager( lockManager );
532 private boolean fetchContentFromProxies( ManagedRepositoryContent managedRepository, DavServletRequest request,
533 LogicalResource resource )
536 String path = resource.getPath();
537 if ( repositoryRequest.isSupportFile( path ) )
539 File proxiedFile = connectors.fetchFromProxies( managedRepository, path );
541 return ( proxiedFile != null );
544 // Is it a Metadata resource?
545 if ( repositoryRequest.isDefault( path ) && repositoryRequest.isMetadata( path ) )
547 return connectors.fetchMetatadaFromProxies( managedRepository, path ) != null;
550 // Not any of the above? Then it's gotta be an artifact reference.
553 // Get the artifact reference in a layout neutral way.
554 ArtifactReference artifact = repositoryRequest.toArtifactReference( path );
556 if ( artifact != null )
558 applyServerSideRelocation( managedRepository, artifact );
560 File proxiedFile = connectors.fetchFromProxies( managedRepository, artifact );
562 resource.setPath( managedRepository.toPath( artifact ) );
564 return ( proxiedFile != null );
567 catch ( LayoutException e )
571 catch ( ProxyDownloadException e )
573 log.error( e.getMessage(), e );
574 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unable to fetch artifact resource." );
580 * A relocation capable client will request the POM prior to the artifact, and will then read meta-data and do
581 * client side relocation. A simplier client (like maven 1) will only request the artifact and not use the
584 * For such clients, archiva does server-side relocation by reading itself the <relocation> element in
585 * metadatas and serving the expected artifact.
587 protected void applyServerSideRelocation( ManagedRepositoryContent managedRepository, ArtifactReference artifact )
588 throws ProxyDownloadException
590 if ( "pom".equals( artifact.getType() ) )
595 // Build the artifact POM reference
596 ArtifactReference pomReference = new ArtifactReference();
597 pomReference.setGroupId( artifact.getGroupId() );
598 pomReference.setArtifactId( artifact.getArtifactId() );
599 pomReference.setVersion( artifact.getVersion() );
600 pomReference.setType( "pom" );
602 // Get the artifact POM from proxied repositories if needed
603 connectors.fetchFromProxies( managedRepository, pomReference );
605 // Open and read the POM from the managed repo
606 File pom = managedRepository.toFile( pomReference );
615 // MavenXpp3Reader leaves the file open, so we need to close it ourselves.
616 FileReader reader = new FileReader( pom );
620 model = new MavenXpp3Reader().read( reader );
624 if ( reader != null )
630 DistributionManagement dist = model.getDistributionManagement();
633 Relocation relocation = dist.getRelocation();
634 if ( relocation != null )
636 // artifact is relocated : update the repositoryPath
637 if ( relocation.getGroupId() != null )
639 artifact.setGroupId( relocation.getGroupId() );
641 if ( relocation.getArtifactId() != null )
643 artifact.setArtifactId( relocation.getArtifactId() );
645 if ( relocation.getVersion() != null )
647 artifact.setVersion( relocation.getVersion() );
652 catch ( FileNotFoundException e )
654 // Artifact has no POM in repo : ignore
656 catch ( IOException e )
658 // Unable to read POM : ignore.
660 catch ( XmlPullParserException e )
662 // Invalid POM : ignore
667 private void triggerAuditEvent( String remoteIP, String repositoryId, String resource, String action,
670 AuditEvent event = new AuditEvent( repositoryId, principal, resource, action );
671 event.setRemoteIP( remoteIP );
673 for ( AuditListener listener : auditListeners )
675 listener.auditEvent( event );
679 public void addAuditListener( AuditListener listener )
681 this.auditListeners.add( listener );
684 public void clearAuditListeners()
686 this.auditListeners.clear();
689 public void removeAuditListener( AuditListener listener )
691 this.auditListeners.remove( listener );
694 private void setHeaders( DavServletResponse response, DavResourceLocator locator, DavResource resource )
696 // [MRM-503] - Metadata file need Pragma:no-cache response
698 if ( locator.getResourcePath().endsWith( "/maven-metadata.xml" ) )
700 response.addHeader( "Pragma", "no-cache" );
701 response.addHeader( "Cache-Control", "no-cache" );
704 // We need to specify this so connecting wagons can work correctly
705 response.addDateHeader( "last-modified", resource.getModificationTime() );
707 // TODO: [MRM-524] determine http caching options for other types of files (artifacts, sha1, md5, snapshots)
710 private ArchivaDavResourceLocator checkLocatorIsInstanceOfRepositoryLocator( DavResourceLocator locator )
713 if ( !( locator instanceof ArchivaDavResourceLocator ) )
715 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
716 "Locator does not implement RepositoryLocator" );
720 if ( locator.getResourcePath().startsWith( ArchivaDavResource.HIDDEN_PATH_PREFIX ) )
722 throw new DavException( HttpServletResponse.SC_NOT_FOUND );
725 ArchivaDavResourceLocator archivaLocator = (ArchivaDavResourceLocator) locator;
727 // MRM-419 - Windows Webdav support. Should not 404 if there is no content.
728 if ( StringUtils.isEmpty( archivaLocator.getRepositoryId() ) )
730 throw new DavException( HttpServletResponse.SC_NO_CONTENT );
732 return archivaLocator;
735 private static class LogicalResource
739 public LogicalResource( String path )
744 public String getPath()
749 public void setPath( String path )
755 protected boolean isAuthorized( DavServletRequest request, String repositoryId )
760 AuthenticationResult result = httpAuth.getAuthenticationResult( request, null );
761 SecuritySession securitySession = httpAuth.getSecuritySession( request.getSession( true ) );
763 return servletAuth.isAuthenticated( request, result )
764 && servletAuth.isAuthorized( request, securitySession, repositoryId,
765 WebdavMethodUtil.getMethodPermission( request.getMethod() ) );
767 catch ( AuthenticationException e )
769 // safety check for MRM-911
770 String guest = UserManager.GUEST_USERNAME;
773 if ( servletAuth.isAuthorized(
775 ( (ArchivaDavResourceLocator) request.getRequestLocator() ).getRepositoryId(),
776 WebdavMethodUtil.getMethodPermission( request.getMethod() ) ) )
781 catch ( UnauthorizedException ae )
783 throw new UnauthorizedDavException( repositoryId,
784 "You are not authenticated and authorized to access any repository." );
787 throw new UnauthorizedDavException( repositoryId, "You are not authenticated" );
789 catch ( MustChangePasswordException e )
791 throw new UnauthorizedDavException( repositoryId, "You must change your password." );
793 catch ( AccountLockedException e )
795 throw new UnauthorizedDavException( repositoryId, "User account is locked." );
797 catch ( AuthorizationException e )
799 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
800 "Fatal Authorization Subsystem Error." );
802 catch ( UnauthorizedException e )
804 throw new UnauthorizedDavException( repositoryId, e.getMessage() );
808 private DavResource getResource( DavServletRequest request, List<String> repositories,
809 ArchivaDavResourceLocator locator )
812 List<File> mergedRepositoryContents = new ArrayList<File>();
813 LogicalResource logicalResource =
814 new LogicalResource( RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ) );
817 // if the current user logged in has permission to any of the repositories, allow user to
818 // browse the repo group but displaying only the repositories which the user has permission to access.
819 // otherwise, prompt for authentication.
821 String activePrincipal = getActivePrincipal( request );
823 boolean allow = isAllowedToContinue( request, repositories, activePrincipal );
827 for ( String repository : repositories )
829 ManagedRepositoryContent managedRepository = null;
833 managedRepository = repositoryFactory.getManagedRepositoryContent( repository );
835 catch ( RepositoryNotFoundException e )
837 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
838 "Invalid managed repository <" + repository + ">: " + e.getMessage() );
840 catch ( RepositoryException e )
842 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
843 "Invalid managed repository <" + repository + ">: " + e.getMessage() );
846 File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() );
847 if ( resourceFile.exists() )
849 // for prompted authentication
850 if ( httpAuth.getSecuritySession( request.getSession( true ) ) != null )
854 if ( isAuthorized( request, repository ) )
856 mergedRepositoryContents.add( resourceFile );
859 catch ( DavException e )
861 // TODO: review exception handling
862 log.debug( "Skipping repository '" + managedRepository + "' for user '" + activePrincipal
863 + "': " + e.getMessage() );
868 // for the current user logged in
871 if ( servletAuth.isAuthorized( activePrincipal, repository,
872 WebdavMethodUtil.getMethodPermission( request.getMethod() ) ) )
874 mergedRepositoryContents.add( resourceFile );
877 catch ( UnauthorizedException e )
879 // TODO: review exception handling
880 log.debug( "Skipping repository '" + managedRepository + "' for user '" + activePrincipal
881 + "': " + e.getMessage() );
889 throw new UnauthorizedDavException( locator.getRepositoryId(), "User not authorized." );
892 ArchivaVirtualDavResource resource =
893 new ArchivaVirtualDavResource( mergedRepositoryContents, logicalResource.getPath(), mimeTypes, locator,
896 // compatibility with MRM-440 to ensure browsing the repository group works ok
897 if ( resource.isCollection() && !request.getRequestURI().endsWith( "/" ) )
899 throw new BrowserRedirectException( resource.getHref() );
905 private String getActivePrincipal( DavServletRequest request )
907 User sessionUser = httpAuth.getSessionUser( request.getSession() );
908 return sessionUser != null ? sessionUser.getUsername() : UserManager.GUEST_USERNAME;
912 * Check if the current user is authorized to access any of the repos
915 * @param repositories
916 * @param activePrincipal
919 private boolean isAllowedToContinue( DavServletRequest request, List<String> repositories, String activePrincipal )
921 boolean allow = false;
923 // if securitySession != null, it means that the user was prompted for authentication
924 if ( httpAuth.getSecuritySession( request.getSession() ) != null )
926 for ( String repository : repositories )
930 if ( isAuthorized( request, repository ) )
936 catch ( DavException e )
944 for ( String repository : repositories )
948 if ( servletAuth.isAuthorized( activePrincipal, repository,
949 WebdavMethodUtil.getMethodPermission( request.getMethod() ) ) )
955 catch ( UnauthorizedException e )
965 private File writeMergedMetadataToFile( ArchivaRepositoryMetadata mergedMetadata, String outputFilename )
966 throws RepositoryMetadataException, DigesterException, IOException
968 File outputFile = new File( outputFilename );
969 if ( outputFile.exists() )
971 FileUtils.deleteQuietly( outputFile );
974 outputFile.getParentFile().mkdirs();
975 RepositoryMetadataWriter.write( mergedMetadata, outputFile );
977 createChecksumFile( outputFilename, digestSha1 );
978 createChecksumFile( outputFilename, digestMd5 );
983 private void createChecksumFile( String path, Digester digester )
984 throws DigesterException, IOException
986 File checksumFile = new File( path + digester.getFilenameExtension() );
987 if ( !checksumFile.exists() )
989 FileUtils.deleteQuietly( checksumFile );
990 checksum.createChecksum( new File( path ), digester );
992 else if ( !checksumFile.isFile() )
994 log.error( "Checksum file is not a file." );
998 private boolean isProjectReference( String requestedResource )
1002 metadataTools.toVersionedReference( requestedResource );
1005 catch ( RepositoryMetadataException re )
1011 public void setServletAuth( ServletAuthenticator servletAuth )
1013 this.servletAuth = servletAuth;
1016 public void setHttpAuth( HttpAuthenticator httpAuth )
1018 this.httpAuth = httpAuth;
1021 public void setTaskExecutor( TaskExecutor taskExecutor )
1023 this.taskExecutor = taskExecutor;
1026 public void setScheduler( ArchivaTaskScheduler scheduler )
1028 this.scheduler = scheduler;