1 package org.apache.maven.archiva.webdav;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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.List;
28
29 import javax.servlet.http.HttpServletResponse;
30
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.common.utils.VersionUtil;
44 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
45 import org.apache.maven.archiva.configuration.RepositoryGroupConfiguration;
46 import org.apache.maven.archiva.database.ArchivaAuditLogsDao;
47 import org.apache.maven.archiva.model.ArchivaRepositoryMetadata;
48 import org.apache.maven.archiva.model.ArtifactReference;
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.metadata.RepositoryMetadataMerge;
63 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataReader;
64 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataWriter;
65 import org.apache.maven.archiva.scheduled.ArchivaTaskScheduler;
66 import org.apache.maven.archiva.security.ServletAuthenticator;
67 import org.apache.maven.archiva.webdav.util.MimeTypes;
68 import org.apache.maven.archiva.webdav.util.RepositoryPathUtil;
69 import org.apache.maven.archiva.webdav.util.WebdavMethodUtil;
70 import org.apache.maven.model.DistributionManagement;
71 import org.apache.maven.model.Model;
72 import org.apache.maven.model.Relocation;
73 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
74 import org.codehaus.plexus.digest.ChecksumFile;
75 import org.codehaus.plexus.digest.Digester;
76 import org.codehaus.plexus.digest.DigesterException;
77 import org.codehaus.plexus.redback.authentication.AuthenticationException;
78 import org.codehaus.plexus.redback.authentication.AuthenticationResult;
79 import org.codehaus.plexus.redback.authorization.AuthorizationException;
80 import org.codehaus.plexus.redback.authorization.UnauthorizedException;
81 import org.codehaus.plexus.redback.policy.AccountLockedException;
82 import org.codehaus.plexus.redback.policy.MustChangePasswordException;
83 import org.codehaus.plexus.redback.system.SecuritySession;
84 import org.codehaus.plexus.redback.users.User;
85 import org.codehaus.plexus.redback.users.UserManager;
86 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
87 import org.codehaus.redback.integration.filter.authentication.HttpAuthenticator;
88 import org.slf4j.Logger;
89 import org.slf4j.LoggerFactory;
90
91 import java.io.File;
92 import java.io.FileNotFoundException;
93 import java.io.FileReader;
94 import java.io.IOException;
95 import java.util.ArrayList;
96 import java.util.List;
97 import javax.servlet.http.HttpServletResponse;
98
99
100
101
102 public class ArchivaDavResourceFactory
103 implements DavResourceFactory, Auditable
104 {
105 private static final String PROXIED_SUFFIX = " (proxied)";
106
107 private static final String HTTP_PUT_METHOD = "PUT";
108
109 private Logger log = LoggerFactory.getLogger( ArchivaDavResourceFactory.class );
110
111
112
113
114 private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
115
116
117
118
119 private RepositoryContentFactory repositoryFactory;
120
121
122
123
124 private RepositoryRequest repositoryRequest;
125
126
127
128
129 private RepositoryProxyConnectors connectors;
130
131
132
133
134 private MetadataTools metadataTools;
135
136
137
138
139 private MimeTypes mimeTypes;
140
141
142
143
144 private ArchivaConfiguration archivaConfiguration;
145
146
147
148
149 private ServletAuthenticator servletAuth;
150
151
152
153
154 private HttpAuthenticator httpAuth;
155
156
157
158
159 private final LockManager lockManager = new SimpleLockManager();
160
161
162
163
164 private ChecksumFile checksum;
165
166
167
168
169 private Digester digestSha1;
170
171
172
173
174 private Digester digestMd5;
175
176
177
178
179 private ArchivaTaskScheduler scheduler;
180
181
182
183
184 private ArchivaAuditLogsDao auditLogsDao;
185
186 public DavResource createResource( final DavResourceLocator locator, final DavServletRequest request,
187 final DavServletResponse response )
188 throws DavException
189 {
190 ArchivaDavResourceLocator archivaLocator = checkLocatorIsInstanceOfRepositoryLocator( locator );
191
192 RepositoryGroupConfiguration repoGroupConfig =
193 archivaConfiguration.getConfiguration().getRepositoryGroupsAsMap().get( archivaLocator.getRepositoryId() );
194
195 String activePrincipal = getActivePrincipal( request );
196
197 List<String> resourcesInAbsolutePath = new ArrayList<String>();
198
199 boolean readMethod = WebdavMethodUtil.isReadMethod( request.getMethod() );
200 DavResource resource;
201 if ( repoGroupConfig != null )
202 {
203 if ( !readMethod )
204 {
205 throw new DavException( HttpServletResponse.SC_METHOD_NOT_ALLOWED,
206 "Write method not allowed for repository groups." );
207 }
208
209 log.debug( "Repository group '" + repoGroupConfig.getId() + "' accessed by '" + activePrincipal + "'" );
210
211
212 if ( RepositoryPathUtil.getLogicalResource( archivaLocator.getOrigResourcePath() ).endsWith( "/" ) )
213 {
214 return getResource( request, repoGroupConfig.getRepositories(), archivaLocator );
215 }
216 else
217 {
218
219
220
221 ArrayList<String> repositories = new ArrayList<String>( repoGroupConfig.getRepositories() );
222 resource = processRepositoryGroup( request, archivaLocator, repositories, activePrincipal,
223 resourcesInAbsolutePath );
224 }
225 }
226 else
227 {
228 ManagedRepositoryContent managedRepository = null;
229
230 try
231 {
232 managedRepository = repositoryFactory.getManagedRepositoryContent( archivaLocator.getRepositoryId() );
233 }
234 catch ( RepositoryNotFoundException e )
235 {
236 throw new DavException( HttpServletResponse.SC_NOT_FOUND,
237 "Invalid repository: " + archivaLocator.getRepositoryId() );
238 }
239 catch ( RepositoryException e )
240 {
241 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e );
242 }
243
244 log.debug( "Managed repository '" + managedRepository.getId() + "' accessed by '" + activePrincipal + "'" );
245
246 resource = processRepository( request, archivaLocator, activePrincipal, managedRepository );
247
248 String logicalResource = RepositoryPathUtil.getLogicalResource( locator.getResourcePath() );
249 resourcesInAbsolutePath.add( new File( managedRepository.getRepoRoot(),
250 logicalResource ).getAbsolutePath() );
251 }
252
253 String requestedResource = request.getRequestURI();
254
255
256
257 if ( ( repositoryRequest.isMetadata( requestedResource ) || repositoryRequest.isMetadataSupportFile(
258 requestedResource ) ) && repoGroupConfig != null )
259 {
260
261 if ( isProjectReference( requestedResource ) )
262 {
263 String artifactId = StringUtils.substringBeforeLast( requestedResource.replace( '\\', '/' ), "/" );
264 artifactId = StringUtils.substringAfterLast( artifactId, "/" );
265
266 ArchivaDavResource res = (ArchivaDavResource) resource;
267 String filePath = StringUtils.substringBeforeLast( res.getLocalResource().getAbsolutePath().replace(
268 '\\', '/' ), "/" );
269 filePath = filePath + "/maven-metadata-" + repoGroupConfig.getId() + ".xml";
270
271
272 if ( repositoryRequest.isSupportFile( requestedResource ) )
273 {
274 File metadataChecksum = new File( filePath + "." + StringUtils.substringAfterLast(
275 requestedResource, "." ) );
276 if ( metadataChecksum.exists() )
277 {
278 LogicalResource logicalResource = new LogicalResource( RepositoryPathUtil.getLogicalResource(
279 locator.getResourcePath() ) );
280
281 resource =
282 new ArchivaDavResource( metadataChecksum.getAbsolutePath(), logicalResource.getPath(),
283 null, request.getRemoteAddr(), activePrincipal,
284 request.getDavSession(), archivaLocator, this, mimeTypes,
285 auditListeners, scheduler, auditLogsDao );
286 }
287 }
288 else
289 {
290 if ( resourcesInAbsolutePath != null && resourcesInAbsolutePath.size() > 1 )
291 {
292
293 ArchivaRepositoryMetadata mergedMetadata = new ArchivaRepositoryMetadata();
294 for ( String resourceAbsPath : resourcesInAbsolutePath )
295 {
296 try
297 {
298 File metadataFile = new File( resourceAbsPath );
299 ArchivaRepositoryMetadata repoMetadata = RepositoryMetadataReader.read( metadataFile );
300 mergedMetadata = RepositoryMetadataMerge.merge( mergedMetadata, repoMetadata );
301 }
302 catch ( RepositoryMetadataException r )
303 {
304 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
305 "Error occurred while reading metadata file." );
306 }
307 }
308
309 try
310 {
311 File resourceFile = writeMergedMetadataToFile( mergedMetadata, filePath );
312
313 LogicalResource logicalResource = new LogicalResource(
314 RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ) );
315
316 resource =
317 new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(),
318 null, request.getRemoteAddr(), activePrincipal,
319 request.getDavSession(), archivaLocator, this, mimeTypes,
320 auditListeners, scheduler, auditLogsDao );
321 }
322 catch ( RepositoryMetadataException r )
323 {
324 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
325 "Error occurred while writing metadata file." );
326 }
327 catch ( IOException ie )
328 {
329 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
330 "Error occurred while generating checksum files." );
331 }
332 catch ( DigesterException de )
333 {
334 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
335 "Error occurred while generating checksum files." );
336 }
337 }
338 }
339 }
340 }
341
342 setHeaders( response, locator, resource );
343
344
345 if ( resource.isCollection() && !request.getRequestURI().endsWith( "/" ) )
346 {
347 throw new BrowserRedirectException( resource.getHref() );
348 }
349 resource.addLockManager( lockManager );
350 return resource;
351 }
352
353 private DavResource processRepositoryGroup( final DavServletRequest request,
354 ArchivaDavResourceLocator archivaLocator, List<String> repositories,
355 String activePrincipal, List<String> resourcesInAbsolutePath )
356 throws DavException
357 {
358 DavResource resource = null;
359 List<DavException> storedExceptions = new ArrayList<DavException>();
360
361 for ( String repositoryId : repositories )
362 {
363 ManagedRepositoryContent managedRepository;
364 try
365 {
366 managedRepository = repositoryFactory.getManagedRepositoryContent( repositoryId );
367 }
368 catch ( RepositoryNotFoundException e )
369 {
370 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e );
371 }
372 catch ( RepositoryException e )
373 {
374 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e );
375 }
376
377 try
378 {
379 DavResource updatedResource = processRepository( request, archivaLocator, activePrincipal,
380 managedRepository );
381 if ( resource == null )
382 {
383 resource = updatedResource;
384 }
385
386 String logicalResource = RepositoryPathUtil.getLogicalResource( archivaLocator.getResourcePath() );
387 if ( logicalResource.endsWith( "/" ) )
388 {
389 logicalResource = logicalResource.substring( 1 );
390 }
391 resourcesInAbsolutePath.add( new File( managedRepository.getRepoRoot(),
392 logicalResource ).getAbsolutePath() );
393 }
394 catch ( DavException e )
395 {
396 storedExceptions.add( e );
397 }
398 }
399
400 if ( resource == null )
401 {
402 if ( !storedExceptions.isEmpty() )
403 {
404
405 for ( DavException e : storedExceptions )
406 {
407 if ( 401 == e.getErrorCode() )
408 {
409 throw e;
410 }
411 }
412
413 throw new DavException( HttpServletResponse.SC_NOT_FOUND );
414 }
415 else
416 {
417 throw new DavException( HttpServletResponse.SC_NOT_FOUND );
418 }
419 }
420 return resource;
421 }
422
423 private DavResource processRepository( final DavServletRequest request, ArchivaDavResourceLocator archivaLocator,
424 String activePrincipal, ManagedRepositoryContent managedRepository )
425 throws DavException
426 {
427 DavResource resource = null;
428 if ( isAuthorized( request, managedRepository.getId() ) )
429 {
430 String path = RepositoryPathUtil.getLogicalResource( archivaLocator.getResourcePath() );
431 if ( path.startsWith( "/" ) )
432 {
433 path = path.substring( 1 );
434 }
435 LogicalResource logicalResource = new LogicalResource( path );
436 File resourceFile = new File( managedRepository.getRepoRoot(), path );
437 resource =
438 new ArchivaDavResource( resourceFile.getAbsolutePath(), path, managedRepository.getRepository(),
439 request.getRemoteAddr(), activePrincipal, request.getDavSession(),
440 archivaLocator, this, mimeTypes, auditListeners, scheduler, auditLogsDao );
441
442 if ( WebdavMethodUtil.isReadMethod( request.getMethod() ) )
443 {
444 if ( archivaLocator.getHref( false ).endsWith( "/" ) && !resourceFile.isDirectory() )
445 {
446
447 throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Resource does not exist" );
448 }
449 else
450 {
451 if ( !resource.isCollection() )
452 {
453 boolean previouslyExisted = resourceFile.exists();
454
455
456 boolean fromProxy = fetchContentFromProxies( managedRepository, request, logicalResource );
457
458
459
460 try
461 {
462
463
464 String localResourcePath = repositoryRequest.toNativePath( logicalResource.getPath(),
465 managedRepository );
466 resourceFile = new File( managedRepository.getRepoRoot(), localResourcePath );
467 resource =
468 new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(),
469 managedRepository.getRepository(), request.getRemoteAddr(),
470 activePrincipal, request.getDavSession(), archivaLocator, this,
471 mimeTypes, auditListeners, scheduler, auditLogsDao );
472 }
473 catch ( LayoutException e )
474 {
475 if ( !resourceFile.exists() )
476 {
477 throw new DavException( HttpServletResponse.SC_NOT_FOUND, e );
478 }
479 }
480
481 if ( fromProxy )
482 {
483 String event = ( previouslyExisted ? AuditEvent.MODIFY_FILE : AuditEvent.CREATE_FILE ) +
484 PROXIED_SUFFIX;
485
486 log.debug( "Proxied artifact '" + resourceFile.getName() + "' in repository '" +
487 managedRepository.getId() + "' (current user '" + activePrincipal + "')" );
488
489 triggerAuditEvent( request.getRemoteAddr(), archivaLocator.getRepositoryId(),
490 logicalResource.getPath(), event, activePrincipal );
491 }
492
493 if ( !resourceFile.exists() )
494 {
495 throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Resource does not exist" );
496 }
497 }
498 }
499 }
500
501 if ( request.getMethod().equals( HTTP_PUT_METHOD ) )
502 {
503 String resourcePath = logicalResource.getPath();
504
505
506
507 if ( managedRepository.getRepository().isReleases() && !repositoryRequest.isMetadata( resourcePath ) &&
508 !repositoryRequest.isSupportFile( resourcePath ) )
509 {
510 ArtifactReference artifact = null;
511 try
512 {
513 artifact = managedRepository.toArtifactReference( resourcePath );
514
515 if ( !VersionUtil.isSnapshot( artifact.getVersion() ) )
516 {
517
518 if ( managedRepository.hasContent( artifact ) &&
519 managedRepository.getRepository().isBlockRedeployments() )
520 {
521 log.warn( "Overwriting released artifacts in repository '" + managedRepository.getId() +
522 "' is not allowed." );
523 throw new DavException( HttpServletResponse.SC_CONFLICT,
524 "Overwriting released artifacts is not allowed." );
525 }
526 }
527 }
528 catch ( LayoutException e )
529 {
530 log.warn( "Artifact path '" + resourcePath + "' is invalid." );
531 }
532 }
533
534
535
536
537
538
539
540
541 File rootDirectory = new File( managedRepository.getRepoRoot() );
542 File destDir = new File( rootDirectory, logicalResource.getPath() ).getParentFile();
543
544 if ( !destDir.exists() )
545 {
546 destDir.mkdirs();
547 String relPath = PathUtil.getRelative( rootDirectory.getAbsolutePath(), destDir );
548
549 log.debug(
550 "Creating destination directory '" + destDir.getName() + "' (current user '" + activePrincipal +
551 "')" );
552
553 triggerAuditEvent( request.getRemoteAddr(), managedRepository.getId(), relPath,
554 AuditEvent.CREATE_DIR, activePrincipal );
555 }
556 }
557 }
558 return resource;
559 }
560
561 public DavResource createResource( final DavResourceLocator locator, final DavSession davSession )
562 throws DavException
563 {
564 ArchivaDavResourceLocator archivaLocator = checkLocatorIsInstanceOfRepositoryLocator( locator );
565
566 ManagedRepositoryContent managedRepository;
567 try
568 {
569 managedRepository = repositoryFactory.getManagedRepositoryContent( archivaLocator.getRepositoryId() );
570 }
571 catch ( RepositoryNotFoundException e )
572 {
573 throw new DavException( HttpServletResponse.SC_NOT_FOUND,
574 "Invalid repository: " + archivaLocator.getRepositoryId() );
575 }
576 catch ( RepositoryException e )
577 {
578 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e );
579 }
580
581 String logicalResource = RepositoryPathUtil.getLogicalResource( locator.getResourcePath() );
582 if ( logicalResource.startsWith( "/" ) )
583 {
584 logicalResource = logicalResource.substring( 1 );
585 }
586 File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource );
587 DavResource resource =
588 new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource, managedRepository.getRepository(),
589 davSession, archivaLocator, this, mimeTypes, auditListeners, scheduler, auditLogsDao );
590
591 resource.addLockManager( lockManager );
592 return resource;
593 }
594
595 private boolean fetchContentFromProxies( ManagedRepositoryContent managedRepository, DavServletRequest request,
596 LogicalResource resource )
597 throws DavException
598 {
599 String path = resource.getPath();
600 if ( repositoryRequest.isSupportFile( path ) )
601 {
602 File proxiedFile = connectors.fetchFromProxies( managedRepository, path );
603
604 return ( proxiedFile != null );
605 }
606
607
608 if ( repositoryRequest.isDefault( path ) && repositoryRequest.isMetadata( path ) )
609 {
610 return connectors.fetchMetatadaFromProxies( managedRepository, path ) != null;
611 }
612
613
614 try
615 {
616
617 ArtifactReference artifact = repositoryRequest.toArtifactReference( path );
618
619 if ( artifact != null )
620 {
621 applyServerSideRelocation( managedRepository, artifact );
622
623 File proxiedFile = connectors.fetchFromProxies( managedRepository, artifact );
624
625 resource.setPath( managedRepository.toPath( artifact ) );
626
627 log.debug( "Proxied artifact '" + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" +
628 artifact.getVersion() + "'" );
629
630 return ( proxiedFile != null );
631 }
632 }
633 catch ( LayoutException e )
634 {
635
636 }
637 catch ( ProxyDownloadException e )
638 {
639 log.error( e.getMessage(), e );
640 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
641 "Unable to fetch artifact resource." );
642 }
643 return false;
644 }
645
646
647
648
649
650
651
652
653
654 protected void applyServerSideRelocation( ManagedRepositoryContent managedRepository, ArtifactReference artifact )
655 throws ProxyDownloadException
656 {
657 if ( "pom".equals( artifact.getType() ) )
658 {
659 return;
660 }
661
662
663 ArtifactReference pomReference = new ArtifactReference();
664 pomReference.setGroupId( artifact.getGroupId() );
665 pomReference.setArtifactId( artifact.getArtifactId() );
666 pomReference.setVersion( artifact.getVersion() );
667 pomReference.setType( "pom" );
668
669
670 connectors.fetchFromProxies( managedRepository, pomReference );
671
672
673 File pom = managedRepository.toFile( pomReference );
674
675 if ( !pom.exists() )
676 {
677 return;
678 }
679
680 try
681 {
682
683 FileReader reader = new FileReader( pom );
684 Model model = null;
685 try
686 {
687 model = new MavenXpp3Reader().read( reader );
688 }
689 finally
690 {
691 if ( reader != null )
692 {
693 reader.close();
694 }
695 }
696
697 DistributionManagement dist = model.getDistributionManagement();
698 if ( dist != null )
699 {
700 Relocation relocation = dist.getRelocation();
701 if ( relocation != null )
702 {
703
704 if ( relocation.getGroupId() != null )
705 {
706 artifact.setGroupId( relocation.getGroupId() );
707 }
708 if ( relocation.getArtifactId() != null )
709 {
710 artifact.setArtifactId( relocation.getArtifactId() );
711 }
712 if ( relocation.getVersion() != null )
713 {
714 artifact.setVersion( relocation.getVersion() );
715 }
716 }
717 }
718 }
719 catch ( FileNotFoundException e )
720 {
721
722 }
723 catch ( IOException e )
724 {
725
726 }
727 catch ( XmlPullParserException e )
728 {
729
730 }
731 }
732
733
734
735 private void triggerAuditEvent( String remoteIP, String repositoryId, String resource, String action,
736 String principal )
737 {
738 AuditEvent event = new AuditEvent( repositoryId, principal, resource, action );
739 event.setRemoteIP( remoteIP );
740
741 for ( AuditListener listener : auditListeners )
742 {
743 listener.auditEvent( event );
744 }
745 }
746
747 public void addAuditListener( AuditListener listener )
748 {
749 this.auditListeners.add( listener );
750 }
751
752 public void clearAuditListeners()
753 {
754 this.auditListeners.clear();
755 }
756
757 public void removeAuditListener( AuditListener listener )
758 {
759 this.auditListeners.remove( listener );
760 }
761
762 private void setHeaders( DavServletResponse response, DavResourceLocator locator, DavResource resource )
763 {
764
765
766 if ( locator.getResourcePath().endsWith( "/maven-metadata.xml" ) )
767 {
768 response.addHeader( "Pragma", "no-cache" );
769 response.addHeader( "Cache-Control", "no-cache" );
770 }
771
772
773 response.addDateHeader( "last-modified", resource.getModificationTime() );
774
775
776 }
777
778 private ArchivaDavResourceLocator checkLocatorIsInstanceOfRepositoryLocator( DavResourceLocator locator )
779 throws DavException
780 {
781 if ( !( locator instanceof ArchivaDavResourceLocator ) )
782 {
783 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
784 "Locator does not implement RepositoryLocator" );
785 }
786
787
788 if ( locator.getResourcePath().startsWith( ArchivaDavResource.HIDDEN_PATH_PREFIX ) )
789 {
790 throw new DavException( HttpServletResponse.SC_NOT_FOUND );
791 }
792
793 ArchivaDavResourceLocator archivaLocator = (ArchivaDavResourceLocator) locator;
794
795
796 if ( StringUtils.isEmpty( archivaLocator.getRepositoryId() ) )
797 {
798 throw new DavException( HttpServletResponse.SC_NO_CONTENT );
799 }
800 return archivaLocator;
801 }
802
803 public ArchivaAuditLogsDao getAuditLogsDao()
804 {
805 return auditLogsDao;
806 }
807
808 private static class LogicalResource
809 {
810 private String path;
811
812 public LogicalResource( String path )
813 {
814 this.path = path;
815 }
816
817 public String getPath()
818 {
819 return path;
820 }
821
822 public void setPath( String path )
823 {
824 this.path = path;
825 }
826 }
827
828 protected boolean isAuthorized( DavServletRequest request, String repositoryId )
829 throws DavException
830 {
831 try
832 {
833 AuthenticationResult result = httpAuth.getAuthenticationResult( request, null );
834 SecuritySession securitySession = httpAuth.getSecuritySession( request.getSession( true ) );
835
836 return servletAuth.isAuthenticated( request, result ) && servletAuth.isAuthorized( request, securitySession,
837 repositoryId,
838 WebdavMethodUtil.getMethodPermission(
839 request.getMethod() ) );
840 }
841 catch ( AuthenticationException e )
842 {
843
844 String guest = UserManager.GUEST_USERNAME;
845 try
846 {
847 if ( servletAuth.isAuthorized( guest,
848 ( (ArchivaDavResourceLocator) request.getRequestLocator() ).getRepositoryId(),
849 WebdavMethodUtil.getMethodPermission( request.getMethod() ) ) )
850 {
851 return true;
852 }
853 }
854 catch ( UnauthorizedException ae )
855 {
856 throw new UnauthorizedDavException( repositoryId,
857 "You are not authenticated and authorized to access any repository." );
858 }
859
860 throw new UnauthorizedDavException( repositoryId, "You are not authenticated" );
861 }
862 catch ( MustChangePasswordException e )
863 {
864 throw new UnauthorizedDavException( repositoryId, "You must change your password." );
865 }
866 catch ( AccountLockedException e )
867 {
868 throw new UnauthorizedDavException( repositoryId, "User account is locked." );
869 }
870 catch ( AuthorizationException e )
871 {
872 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
873 "Fatal Authorization Subsystem Error." );
874 }
875 catch ( UnauthorizedException e )
876 {
877 throw new UnauthorizedDavException( repositoryId, e.getMessage() );
878 }
879 }
880
881 private DavResource getResource( DavServletRequest request, List<String> repositories,
882 ArchivaDavResourceLocator locator )
883 throws DavException
884 {
885 List<File> mergedRepositoryContents = new ArrayList<File>();
886 String path = RepositoryPathUtil.getLogicalResource( locator.getResourcePath() );
887 if ( path.startsWith( "/" ) )
888 {
889 path = path.substring( 1 );
890 }
891 LogicalResource logicalResource = new LogicalResource( path );
892
893
894
895
896
897
898 String activePrincipal = getActivePrincipal( request );
899
900 boolean allow = isAllowedToContinue( request, repositories, activePrincipal );
901
902 if ( allow )
903 {
904 for ( String repository : repositories )
905 {
906 ManagedRepositoryContent managedRepository = null;
907
908 try
909 {
910 managedRepository = repositoryFactory.getManagedRepositoryContent( repository );
911 }
912 catch ( RepositoryNotFoundException e )
913 {
914 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
915 "Invalid managed repository <" + repository + ">: " + e.getMessage() );
916 }
917 catch ( RepositoryException e )
918 {
919 throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
920 "Invalid managed repository <" + repository + ">: " + e.getMessage() );
921 }
922
923 File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() );
924 if ( resourceFile.exists() )
925 {
926
927 if ( httpAuth.getSecuritySession( request.getSession( true ) ) != null )
928 {
929 try
930 {
931 if ( isAuthorized( request, repository ) )
932 {
933 mergedRepositoryContents.add( resourceFile );
934 log.debug( "Repository '" + repository + "' accessed by '" + activePrincipal + "'" );
935 }
936 }
937 catch ( DavException e )
938 {
939
940 log.debug(
941 "Skipping repository '" + managedRepository + "' for user '" + activePrincipal + "': " +
942 e.getMessage() );
943 }
944 }
945 else
946 {
947
948 try
949 {
950 if ( servletAuth.isAuthorized( activePrincipal, repository,
951 WebdavMethodUtil.getMethodPermission(
952 request.getMethod() ) ) )
953 {
954 mergedRepositoryContents.add( resourceFile );
955 log.debug( "Repository '" + repository + "' accessed by '" + activePrincipal + "'" );
956 }
957 }
958 catch ( UnauthorizedException e )
959 {
960
961 log.debug(
962 "Skipping repository '" + managedRepository + "' for user '" + activePrincipal + "': " +
963 e.getMessage() );
964 }
965 }
966 }
967 }
968 }
969 else
970 {
971 throw new UnauthorizedDavException( locator.getRepositoryId(), "User not authorized." );
972 }
973
974 ArchivaVirtualDavResource resource = new ArchivaVirtualDavResource( mergedRepositoryContents,
975 logicalResource.getPath(), mimeTypes,
976 locator, this );
977
978
979 if ( resource.isCollection() && !request.getRequestURI().endsWith( "/" ) )
980 {
981 throw new BrowserRedirectException( resource.getHref() );
982 }
983
984 return resource;
985 }
986
987 protected String getActivePrincipal( DavServletRequest request )
988 {
989 User sessionUser = httpAuth.getSessionUser( request.getSession() );
990 return sessionUser != null ? sessionUser.getUsername() : UserManager.GUEST_USERNAME;
991 }
992
993
994
995
996
997
998
999
1000
1001 private boolean isAllowedToContinue( DavServletRequest request, List<String> repositories, String activePrincipal )
1002 {
1003 boolean allow = false;
1004
1005
1006 if ( httpAuth.getSecuritySession( request.getSession() ) != null )
1007 {
1008 for ( String repository : repositories )
1009 {
1010 try
1011 {
1012 if ( isAuthorized( request, repository ) )
1013 {
1014 allow = true;
1015 break;
1016 }
1017 }
1018 catch ( DavException e )
1019 {
1020 continue;
1021 }
1022 }
1023 }
1024 else
1025 {
1026 for ( String repository : repositories )
1027 {
1028 try
1029 {
1030 if ( servletAuth.isAuthorized( activePrincipal, repository, WebdavMethodUtil.getMethodPermission(
1031 request.getMethod() ) ) )
1032 {
1033 allow = true;
1034 break;
1035 }
1036 }
1037 catch ( UnauthorizedException e )
1038 {
1039 continue;
1040 }
1041 }
1042 }
1043
1044 return allow;
1045 }
1046
1047 private File writeMergedMetadataToFile( ArchivaRepositoryMetadata mergedMetadata, String outputFilename )
1048 throws RepositoryMetadataException, DigesterException, IOException
1049 {
1050 File outputFile = new File( outputFilename );
1051 if ( outputFile.exists() )
1052 {
1053 FileUtils.deleteQuietly( outputFile );
1054 }
1055
1056 outputFile.getParentFile().mkdirs();
1057 RepositoryMetadataWriter.write( mergedMetadata, outputFile );
1058
1059 createChecksumFile( outputFilename, digestSha1 );
1060 createChecksumFile( outputFilename, digestMd5 );
1061
1062 return outputFile;
1063 }
1064
1065 private void createChecksumFile( String path, Digester digester )
1066 throws DigesterException, IOException
1067 {
1068 File checksumFile = new File( path + digester.getFilenameExtension() );
1069 if ( !checksumFile.exists() )
1070 {
1071 FileUtils.deleteQuietly( checksumFile );
1072 checksum.createChecksum( new File( path ), digester );
1073 }
1074 else if ( !checksumFile.isFile() )
1075 {
1076 log.error( "Checksum file is not a file." );
1077 }
1078 }
1079
1080 private boolean isProjectReference( String requestedResource )
1081 {
1082 try
1083 {
1084 metadataTools.toVersionedReference( requestedResource );
1085 return false;
1086 }
1087 catch ( RepositoryMetadataException re )
1088 {
1089 return true;
1090 }
1091 }
1092
1093 public void setServletAuth( ServletAuthenticator servletAuth )
1094 {
1095 this.servletAuth = servletAuth;
1096 }
1097
1098 public void setHttpAuth( HttpAuthenticator httpAuth )
1099 {
1100 this.httpAuth = httpAuth;
1101 }
1102
1103 public void setScheduler( ArchivaTaskScheduler scheduler )
1104 {
1105 this.scheduler = scheduler;
1106 }
1107
1108 public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration )
1109 {
1110 this.archivaConfiguration = archivaConfiguration;
1111 }
1112
1113 public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
1114 {
1115 this.repositoryFactory = repositoryFactory;
1116 }
1117
1118 public void setRepositoryRequest( RepositoryRequest repositoryRequest )
1119 {
1120 this.repositoryRequest = repositoryRequest;
1121 }
1122
1123 public void setConnectors( RepositoryProxyConnectors connectors )
1124 {
1125 this.connectors = connectors;
1126 }
1127
1128 public void setAuditLogsDao( ArchivaAuditLogsDao auditLogsDao )
1129 {
1130 this.auditLogsDao = auditLogsDao;
1131 }
1132 }