]> source.dussan.org Git - archiva.git/blob
0d52a68a02de35f23438487a920c7468e6d85df4
[archiva.git] /
1 package org.apache.maven.archiva.webdav;
2
3 /*
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
11  *
12  *  http://www.apache.org/licenses/LICENSE-2.0
13  *
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
19  * under the License.
20  */
21
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.io.FileReader;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30
31 import javax.servlet.http.HttpServletResponse;
32
33 import org.apache.commons.lang.StringUtils;
34 import org.apache.jackrabbit.webdav.DavException;
35 import org.apache.jackrabbit.webdav.DavResource;
36 import org.apache.jackrabbit.webdav.DavResourceFactory;
37 import org.apache.jackrabbit.webdav.DavResourceLocator;
38 import org.apache.jackrabbit.webdav.DavServletRequest;
39 import org.apache.jackrabbit.webdav.DavServletResponse;
40 import org.apache.jackrabbit.webdav.DavSession;
41 import org.apache.jackrabbit.webdav.lock.LockManager;
42 import org.apache.jackrabbit.webdav.lock.SimpleLockManager;
43 import org.apache.maven.archiva.common.utils.PathUtil;
44 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
45 import org.apache.maven.archiva.configuration.RepositoryGroupConfiguration;
46 import org.apache.maven.archiva.model.ArtifactReference;
47 import org.apache.maven.archiva.model.ProjectReference;
48 import org.apache.maven.archiva.model.VersionedReference;
49 import org.apache.maven.archiva.policies.ProxyDownloadException;
50 import org.apache.maven.archiva.proxy.RepositoryProxyConnectors;
51 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
52 import org.apache.maven.archiva.repository.RepositoryContentFactory;
53 import org.apache.maven.archiva.repository.RepositoryException;
54 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
55 import org.apache.maven.archiva.repository.audit.AuditEvent;
56 import org.apache.maven.archiva.repository.audit.AuditListener;
57 import org.apache.maven.archiva.repository.audit.Auditable;
58 import org.apache.maven.archiva.repository.content.RepositoryRequest;
59 import org.apache.maven.archiva.repository.layout.LayoutException;
60 import org.apache.maven.archiva.repository.metadata.MetadataTools;
61 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
62 import org.apache.maven.archiva.repository.scanner.RepositoryContentConsumers;
63 import org.apache.maven.archiva.security.ArchivaXworkUser;
64 import org.apache.maven.archiva.security.ServletAuthenticator;
65 import org.apache.maven.archiva.webdav.util.MimeTypes;
66 import org.apache.maven.archiva.webdav.util.RepositoryPathUtil;
67 import org.apache.maven.archiva.webdav.util.WebdavMethodUtil;
68 import org.apache.maven.model.DistributionManagement;
69 import org.apache.maven.model.Model;
70 import org.apache.maven.model.Relocation;
71 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
72 import org.codehaus.plexus.redback.authentication.AuthenticationException;
73 import org.codehaus.plexus.redback.authentication.AuthenticationResult;
74 import org.codehaus.plexus.redback.authorization.AuthorizationException;
75 import org.codehaus.plexus.redback.authorization.UnauthorizedException;
76 import org.codehaus.plexus.redback.policy.AccountLockedException;
77 import org.codehaus.plexus.redback.policy.MustChangePasswordException;
78 import org.codehaus.plexus.redback.system.SecuritySession;
79 import org.codehaus.plexus.redback.system.SecuritySystemConstants;
80 import org.codehaus.plexus.redback.xwork.filter.authentication.HttpAuthenticator;
81 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
84
85 import com.opensymphony.xwork.ActionContext;
86
87 /**
88  * @author <a href="mailto:james@atlassian.com">James William Dumay</a>
89  * @plexus.component role="org.apache.maven.archiva.webdav.ArchivaDavResourceFactory"
90  */
91 public class ArchivaDavResourceFactory
92     implements DavResourceFactory, Auditable
93 {
94     private static final String PROXIED_SUFFIX = " (proxied)";
95
96     private static final String HTTP_PUT_METHOD = "PUT";
97
98     private Logger log = LoggerFactory.getLogger( ArchivaDavResourceFactory.class );
99
100     /**
101      * @plexus.requirement role="org.apache.maven.archiva.repository.audit.AuditListener"
102      */
103     private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
104
105     /**
106      * @plexus.requirement
107      */
108     private RepositoryContentFactory repositoryFactory;
109
110     /**
111      * @plexus.requirement
112      */
113     private RepositoryRequest repositoryRequest;
114
115     /**
116      * @plexus.requirement role-hint="default"
117      */
118     private RepositoryProxyConnectors connectors;
119
120     /**
121      * @plexus.requirement
122      */
123     private MetadataTools metadataTools;
124
125     /**
126      * @plexus.requirement
127      */
128     private MimeTypes mimeTypes;
129
130     /**
131      * @plexus.requirement
132      */
133     private ArchivaConfiguration archivaConfiguration;
134
135     /**
136      * @plexus.requirement
137      */
138     private ServletAuthenticator servletAuth;
139
140     /**
141      * @plexus.requirement role-hint="basic"
142      */
143     private HttpAuthenticator httpAuth;
144
145
146     /**
147      * Lock Manager - use simple implementation from JackRabbit
148      */
149     private final LockManager lockManager = new SimpleLockManager();
150
151     /** @plexus.requirement */
152     private RepositoryContentConsumers consumers;
153
154     public DavResource createResource( final DavResourceLocator locator, final DavServletRequest request,
155                                        final DavServletResponse response )
156         throws DavException
157     {
158         checkLocatorIsInstanceOfRepositoryLocator( locator );
159         ArchivaDavResourceLocator archivaLocator = (ArchivaDavResourceLocator) locator;
160
161         RepositoryGroupConfiguration repoGroupConfig =
162             archivaConfiguration.getConfiguration().getRepositoryGroupsAsMap().get( archivaLocator.getRepositoryId() );
163         List<String> repositories = new ArrayList<String>();
164
165         boolean isGet = WebdavMethodUtil.isReadMethod( request.getMethod() );
166         boolean isPut = WebdavMethodUtil.isWriteMethod( request.getMethod() );
167
168         if ( repoGroupConfig != null )
169         {
170             if( WebdavMethodUtil.isWriteMethod( request.getMethod() ) )
171             {
172                 throw new DavException( HttpServletResponse.SC_METHOD_NOT_ALLOWED,
173                                         "Write method not allowed for repository groups." );
174             }
175             repositories.addAll( repoGroupConfig.getRepositories() );
176
177             // handle browse requests for virtual repos
178             if ( RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ).endsWith( "/" ) )
179             {
180                 return getResource( request, repositories, archivaLocator );
181             }
182         }
183         else
184         {
185             repositories.add( archivaLocator.getRepositoryId() );
186         }
187
188         //MRM-419 - Windows Webdav support. Should not 404 if there is no content.
189         if (StringUtils.isEmpty(archivaLocator.getRepositoryId()))
190         {
191             throw new DavException(HttpServletResponse.SC_NO_CONTENT);
192         }
193
194         List<DavResource> availableResources = new ArrayList<DavResource>();
195         DavException e = null;
196
197         for ( String repositoryId : repositories )
198         {
199             ManagedRepositoryContent managedRepository = null;
200
201             try
202             {
203                 managedRepository = getManagedRepository( repositoryId );
204             }
205             catch ( DavException de )
206             {
207                 throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Invalid managed repository <" +
208                     repositoryId + ">" );
209             }
210
211             DavResource resource = null;
212             if ( !locator.getResourcePath().startsWith( ArchivaDavResource.HIDDEN_PATH_PREFIX ) )
213             {
214                 if ( managedRepository != null )
215                 {
216                     try
217                     {
218                         if( isAuthorized( request, repositoryId ) )
219                         {
220                             LogicalResource logicalResource =
221                                 new LogicalResource( RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ) );
222
223                             if ( isGet )
224                             {
225                                 resource = doGet( managedRepository, request, archivaLocator, logicalResource );
226                             }
227
228                             if ( isPut )
229                             {
230                                 resource = doPut( managedRepository, request, archivaLocator, logicalResource );
231                             }
232                         }
233                     }
234                     catch ( DavException de )
235                     {
236                         e = de;
237                         continue;
238                     }
239
240                     if( resource == null )
241                     {
242                         e = new DavException( HttpServletResponse.SC_NOT_FOUND, "Resource does not exist" );
243                     }
244                     else
245                     {
246                         availableResources.add( resource );
247                     }
248                 }
249                 else
250                 {
251                     e = new DavException( HttpServletResponse.SC_NOT_FOUND, "Repository does not exist" );
252                 }
253             }
254         }
255
256         if (availableResources.isEmpty())
257         {
258             throw e;
259         }
260
261         if ( request.getRequestURI().endsWith( "metadata.xml" ) )
262         {
263             // TODO MRM-872 : must merge all available metadatas
264         }
265
266         DavResource resource = availableResources.get( 0 );
267         setHeaders(response, locator, resource );
268
269         // compatibility with MRM-440 to ensure browsing the repository works ok
270         if ( resource.isCollection() && !request.getRequestURI().endsWith("/" ) )
271         {
272             throw new BrowserRedirectException( resource.getHref() );
273         }
274         resource.addLockManager(lockManager);
275         return resource;
276     }
277
278     public DavResource createResource( final DavResourceLocator locator, final DavSession davSession )
279         throws DavException
280     {
281         checkLocatorIsInstanceOfRepositoryLocator( locator );
282         ArchivaDavResourceLocator archivaLocator = (ArchivaDavResourceLocator) locator;
283
284         DavResource resource = null;
285         if ( !locator.getResourcePath().startsWith( ArchivaDavResource.HIDDEN_PATH_PREFIX ) )
286         {
287             ManagedRepositoryContent managedRepository = getManagedRepository( archivaLocator.getRepositoryId() );
288             String logicalResource = RepositoryPathUtil.getLogicalResource( locator.getResourcePath() );
289             File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource );
290             resource =
291                 new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource,
292                                         managedRepository.getRepository(), davSession, archivaLocator, this, mimeTypes,
293                                         auditListeners, consumers );
294         }
295         resource.addLockManager(lockManager);
296         return resource;
297     }
298
299     private DavResource doGet( ManagedRepositoryContent managedRepository, DavServletRequest request,
300                                ArchivaDavResourceLocator locator, LogicalResource logicalResource )
301         throws DavException
302     {
303         File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() );
304         ArchivaDavResource resource =
305             new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(),
306                                     managedRepository.getRepository(), request.getRemoteAddr(),
307                                     request.getDavSession(), locator, this, mimeTypes, auditListeners, consumers );
308
309         if ( !resource.isCollection() )
310         {
311             boolean previouslyExisted = resourceFile.exists();
312
313             // At this point the incoming request can either be in default or
314             // legacy layout format.
315             boolean fromProxy = fetchContentFromProxies( managedRepository, request, logicalResource );
316
317             try
318             {
319                 // Perform an adjustment of the resource to the managed
320                 // repository expected path.
321                 String localResourcePath =
322                     repositoryRequest.toNativePath( logicalResource.getPath(), managedRepository );
323                 resourceFile = new File( managedRepository.getRepoRoot(), localResourcePath );
324             }
325             catch ( LayoutException e )
326             {
327                 if ( previouslyExisted )
328                 {
329                     return resource;
330                 }
331                 throw new DavException( HttpServletResponse.SC_NOT_FOUND, e );
332             }
333
334             // Attempt to fetch the resource from any defined proxy.
335             if ( fromProxy )
336             {
337                 String repositoryId = locator.getRepositoryId();
338                 String event = ( previouslyExisted ? AuditEvent.MODIFY_FILE : AuditEvent.CREATE_FILE ) + PROXIED_SUFFIX;
339                 triggerAuditEvent( request.getRemoteAddr(), repositoryId, logicalResource.getPath(), event );
340             }
341
342             if ( !resourceFile.exists() )
343             {
344                 resource = null;
345             }
346             else
347             {
348                 resource =
349                     new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(),
350                                             managedRepository.getRepository(), request.getRemoteAddr(),
351                                             request.getDavSession(), locator, this, mimeTypes, auditListeners,
352                                             consumers );
353             }
354         }
355         return resource;
356     }
357
358     private DavResource doPut( ManagedRepositoryContent managedRepository, DavServletRequest request,
359                                ArchivaDavResourceLocator locator, LogicalResource logicalResource )
360         throws DavException
361     {
362         /*
363          * Create parent directories that don't exist when writing a file This actually makes this implementation not
364          * compliant to the WebDAV RFC - but we have enough knowledge about how the collection is being used to do this
365          * reasonably and some versions of Maven's WebDAV don't correctly create the collections themselves.
366          */
367
368         File rootDirectory = new File( managedRepository.getRepoRoot() );
369         File destDir = new File( rootDirectory, logicalResource.getPath() ).getParentFile();
370         if ( request.getMethod().equals(HTTP_PUT_METHOD) && !destDir.exists() )
371         {
372             destDir.mkdirs();
373             String relPath = PathUtil.getRelative( rootDirectory.getAbsolutePath(), destDir );
374             triggerAuditEvent( request.getRemoteAddr(), logicalResource.getPath(), relPath, AuditEvent.CREATE_DIR );
375         }
376
377         File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() );
378
379         return new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(),
380                                        managedRepository.getRepository(), request.getRemoteAddr(),
381                                        request.getDavSession(), locator, this, mimeTypes, auditListeners, consumers );
382     }
383
384     private boolean fetchContentFromProxies( ManagedRepositoryContent managedRepository, DavServletRequest request,
385                                              LogicalResource resource )
386         throws DavException
387     {
388         if ( repositoryRequest.isSupportFile( resource.getPath() ) )
389         {
390             // Checksums are fetched with artifact / metadata.
391
392             // Need to adjust the path for the checksum resource.
393             return false;
394         }
395
396         // Is it a Metadata resource?
397         if ( repositoryRequest.isDefault( resource.getPath() ) && repositoryRequest.isMetadata( resource.getPath() ) )
398         {
399             return fetchMetadataFromProxies( managedRepository, request, resource );
400         }
401
402         // Not any of the above? Then it's gotta be an artifact reference.
403         try
404         {
405             // Get the artifact reference in a layout neutral way.
406             ArtifactReference artifact = repositoryRequest.toArtifactReference( resource.getPath() );
407
408             if ( artifact != null )
409             {
410                 applyServerSideRelocation( managedRepository, artifact );
411
412                 File proxiedFile = connectors.fetchFromProxies( managedRepository, artifact );
413
414                 resource.setPath( managedRepository.toPath( artifact ) );
415
416                 return ( proxiedFile != null );
417             }
418         }
419         catch ( LayoutException e )
420         {
421             /* eat it */
422         }
423         catch ( ProxyDownloadException e )
424         {
425             log.error( e.getMessage(), e );
426             throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unable to fetch artifact resource." );
427         }
428         return false;
429     }
430
431     private boolean fetchMetadataFromProxies( ManagedRepositoryContent managedRepository, DavServletRequest request,
432                                               LogicalResource resource )
433         throws DavException
434     {
435         ProjectReference project;
436         VersionedReference versioned;
437
438         try
439         {
440
441             versioned = metadataTools.toVersionedReference( resource.getPath() );
442             if ( versioned != null )
443             {
444                 connectors.fetchFromProxies( managedRepository, versioned );
445                 return true;
446             }
447         }
448         catch ( RepositoryMetadataException e )
449         {
450             /* eat it */
451         }
452
453         try
454         {
455             project = metadataTools.toProjectReference( resource.getPath() );
456             if ( project != null )
457             {
458                 connectors.fetchFromProxies( managedRepository, project );
459                 return true;
460             }
461         }
462         catch ( RepositoryMetadataException e )
463         {
464             /* eat it */
465         }
466
467         return false;
468     }
469
470     /**
471      * A relocation capable client will request the POM prior to the artifact, and will then read meta-data and do
472      * client side relocation. A simplier client (like maven 1) will only request the artifact and not use the
473      * metadatas.
474      * <p>
475      * For such clients, archiva does server-side relocation by reading itself the &lt;relocation&gt; element in
476      * metadatas and serving the expected artifact.
477      */
478     protected void applyServerSideRelocation( ManagedRepositoryContent managedRepository, ArtifactReference artifact )
479         throws ProxyDownloadException
480     {
481         if ( "pom".equals( artifact.getType() ) )
482         {
483             return;
484         }
485
486         // Build the artifact POM reference
487         ArtifactReference pomReference = new ArtifactReference();
488         pomReference.setGroupId( artifact.getGroupId() );
489         pomReference.setArtifactId( artifact.getArtifactId() );
490         pomReference.setVersion( artifact.getVersion() );
491         pomReference.setType( "pom" );
492
493         // Get the artifact POM from proxied repositories if needed
494         connectors.fetchFromProxies( managedRepository, pomReference );
495
496         // Open and read the POM from the managed repo
497         File pom = managedRepository.toFile( pomReference );
498
499         if ( !pom.exists() )
500         {
501             return;
502         }
503
504         try
505         {
506             Model model = new MavenXpp3Reader().read( new FileReader( pom ) );
507             DistributionManagement dist = model.getDistributionManagement();
508             if ( dist != null )
509             {
510                 Relocation relocation = dist.getRelocation();
511                 if ( relocation != null )
512                 {
513                     // artifact is relocated : update the repositoryPath
514                     if ( relocation.getGroupId() != null )
515                     {
516                         artifact.setGroupId( relocation.getGroupId() );
517                     }
518                     if ( relocation.getArtifactId() != null )
519                     {
520                         artifact.setArtifactId( relocation.getArtifactId() );
521                     }
522                     if ( relocation.getVersion() != null )
523                     {
524                         artifact.setVersion( relocation.getVersion() );
525                     }
526                 }
527             }
528         }
529         catch ( FileNotFoundException e )
530         {
531             // Artifact has no POM in repo : ignore
532         }
533         catch ( IOException e )
534         {
535             // Unable to read POM : ignore.
536         }
537         catch ( XmlPullParserException e )
538         {
539             // Invalid POM : ignore
540         }
541     }
542
543     // TODO: remove?
544     private void triggerAuditEvent( String remoteIP, String repositoryId, String resource, String action )
545     {
546         String activePrincipal = ArchivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
547         AuditEvent event = new AuditEvent( repositoryId, activePrincipal, resource, action );
548         event.setRemoteIP( remoteIP );
549
550         for ( AuditListener listener : auditListeners )
551         {
552             listener.auditEvent( event );
553         }
554     }
555
556     public void addAuditListener( AuditListener listener )
557     {
558         this.auditListeners.add( listener );
559     }
560
561     public void clearAuditListeners()
562     {
563         this.auditListeners.clear();
564     }
565
566     public void removeAuditListener( AuditListener listener )
567     {
568         this.auditListeners.remove( listener );
569     }
570
571     private void setHeaders( DavServletResponse response, DavResourceLocator locator, DavResource resource )
572     {
573         // [MRM-503] - Metadata file need Pragma:no-cache response
574         // header.
575         if ( locator.getResourcePath().endsWith( "/maven-metadata.xml" ) )
576         {
577             response.addHeader( "Pragma", "no-cache" );
578             response.addHeader( "Cache-Control", "no-cache" );
579         }
580
581         //We need to specify this so connecting wagons can work correctly
582         response.addDateHeader("last-modified", resource.getModificationTime());
583
584         // TODO: [MRM-524] determine http caching options for other types of files (artifacts, sha1, md5, snapshots)
585     }
586
587     private ManagedRepositoryContent getManagedRepository( String respositoryId )
588         throws DavException
589     {
590         if ( respositoryId != null )
591         {
592             try
593             {
594                 return repositoryFactory.getManagedRepositoryContent( respositoryId );
595             }
596             catch ( RepositoryNotFoundException e )
597             {
598                 throw new DavException( HttpServletResponse.SC_NOT_FOUND, e );
599             }
600             catch ( RepositoryException e )
601             {
602                 throw new DavException( HttpServletResponse.SC_NOT_FOUND, e );
603             }
604         }
605         return null;
606     }
607
608     private void checkLocatorIsInstanceOfRepositoryLocator( DavResourceLocator locator )
609         throws DavException
610     {
611         if ( !( locator instanceof RepositoryLocator ) )
612         {
613             throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
614                                     "Locator does not implement RepositoryLocator" );
615         }
616     }
617
618     class LogicalResource
619     {
620         private String path;
621
622         public LogicalResource( String path )
623         {
624             this.path = path;
625         }
626
627         public String getPath()
628         {
629             return path;
630         }
631
632         public void setPath( String path )
633         {
634             this.path = path;
635         }
636     }
637
638     protected boolean isAuthorized( DavServletRequest request, String repositoryId )
639         throws DavException
640     {
641         try
642         {
643             AuthenticationResult result = httpAuth.getAuthenticationResult( request, null );
644             SecuritySession securitySession = httpAuth.getSecuritySession();
645
646             return servletAuth.isAuthenticated( request, result ) &&
647                 servletAuth.isAuthorized( request, securitySession, repositoryId,
648                                           WebdavMethodUtil.isWriteMethod( request.getMethod() ) );
649         }
650         catch ( AuthenticationException e )
651         {
652             throw new UnauthorizedDavException( repositoryId, "You are not authenticated" );
653         }
654         catch ( MustChangePasswordException e )
655         {
656             throw new UnauthorizedDavException( repositoryId, "You must change your password." );
657         }
658         catch ( AccountLockedException e )
659         {
660             throw new UnauthorizedDavException( repositoryId, "User account is locked." );
661         }
662         catch ( AuthorizationException e )
663         {
664             throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
665                                     "Fatal Authorization Subsystem Error." );
666         }
667         catch ( UnauthorizedException e )
668         {
669             throw new UnauthorizedDavException( repositoryId, e.getMessage() );
670         }
671     }
672
673     private DavResource getResource( DavServletRequest request, List<String> repositories, ArchivaDavResourceLocator locator )
674         throws DavException
675     {
676         List<File> mergedRepositoryContents = new ArrayList<File>();
677         LogicalResource logicalResource =
678             new LogicalResource( RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ) );
679
680         // flow:
681         // if the current user logged in has permission to any of the repositories, allow user to
682         // browse the repo group but displaying only the repositories which the user has permission to access.
683         // otherwise, prompt for authentication.
684
685         // put the current session in the session map which will be passed to ArchivaXworkUser
686         Map<String, Object> sessionMap = new HashMap<String, Object>();
687         if( request.getSession().getAttribute( SecuritySystemConstants.SECURITY_SESSION_KEY ) != null )
688         {
689             sessionMap.put( SecuritySystemConstants.SECURITY_SESSION_KEY,
690                             request.getSession().getAttribute( SecuritySystemConstants.SECURITY_SESSION_KEY ) );
691         }
692
693         String activePrincipal = ArchivaXworkUser.getActivePrincipal( sessionMap );
694         boolean allow = isAllowedToContinue( request, repositories, activePrincipal );
695
696         if( allow )
697         {
698             for( String repository : repositories )
699             {
700                 // for prompted authentication
701                 if( httpAuth.getSecuritySession() != null )
702                 {
703                     try
704                     {
705                         if( isAuthorized( request, repository ) )
706                         {
707                             getResource( locator, mergedRepositoryContents, logicalResource, repository );
708                         }
709                     }
710                     catch ( DavException e )
711                     {
712                         continue;
713                     }
714                 }
715                 else
716                 {
717                     // for the current user logged in
718                     try
719                     {
720                         if( servletAuth.isAuthorizedToAccessVirtualRepository( activePrincipal, repository ) )
721                         {
722                             getResource( locator, mergedRepositoryContents, logicalResource, repository );
723                         }
724                     }
725                     catch ( UnauthorizedException e )
726                     {
727                         continue;
728                     }
729                 }
730             }
731         }
732         else
733         {
734             throw new UnauthorizedDavException( locator.getRepositoryId(), "User not authorized." );
735         }
736
737         ArchivaVirtualDavResource resource =
738             new ArchivaVirtualDavResource( mergedRepositoryContents, logicalResource.getPath(), mimeTypes, locator, this );
739
740         // compatibility with MRM-440 to ensure browsing the repository group works ok
741         if ( resource.isCollection() && !request.getRequestURI().endsWith("/" ) )
742         {
743             throw new BrowserRedirectException( resource.getHref() );
744         }
745
746         return resource;
747     }
748
749     private void getResource( ArchivaDavResourceLocator locator, List<File> mergedRepositoryContents,
750                               LogicalResource logicalResource, String repository )
751         throws DavException
752     {
753         ManagedRepositoryContent managedRepository = null;
754
755         try
756         {
757             managedRepository = getManagedRepository( repository );
758         }
759         catch ( DavException de )
760         {
761             throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Invalid managed repository <" +
762                 repository + ">" );
763         }
764
765         if ( !locator.getResourcePath().startsWith( ArchivaVirtualDavResource.HIDDEN_PATH_PREFIX ) )
766         {
767             if( managedRepository != null )
768             {
769                 File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() );
770                 if( resourceFile.exists() )
771                 {
772                     mergedRepositoryContents.add( resourceFile );
773                 }
774             }
775         }
776     }
777
778     /**
779      * Check if the current user is authorized to access any of the repos
780      *
781      * @param request
782      * @param repositories
783      * @param activePrincipal
784      * @return
785      */
786     private boolean isAllowedToContinue( DavServletRequest request, List<String> repositories, String activePrincipal )
787     {
788         boolean allow = false;
789
790
791         // if securitySession != null, it means that the user was prompted for authentication
792         if( httpAuth.getSecuritySession() != null )
793         {
794             for( String repository : repositories )
795             {
796                 try
797                 {
798                     if( isAuthorized( request, repository ) )
799                     {
800                         allow = true;
801                         break;
802                     }
803                 }
804                 catch( DavException e )
805                 {
806                     continue;
807                 }
808             }
809         }
810         else
811         {
812             for( String repository : repositories )
813             {
814                 try
815                 {
816                     if( servletAuth.isAuthorizedToAccessVirtualRepository( activePrincipal, repository ) )
817                     {
818                         allow = true;
819                         break;
820                     }
821                 }
822                 catch ( UnauthorizedException e )
823                 {
824                     continue;
825                 }
826             }
827         }
828
829         return allow;
830     }
831
832 }