]> source.dussan.org Git - archiva.git/blob
27a90360f048835a24865b071dfa3047d1953b08
[archiva.git] /
1 package org.apache.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 org.apache.archiva.admin.model.RepositoryAdminException;
23 import org.apache.archiva.admin.model.beans.ManagedRepository;
24 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
25 import org.apache.archiva.configuration.ArchivaConfiguration;
26 import org.apache.archiva.configuration.ConfigurationEvent;
27 import org.apache.archiva.configuration.ConfigurationListener;
28 import org.apache.archiva.redback.integration.filter.authentication.HttpAuthenticator;
29 import org.apache.archiva.security.ServletAuthenticator;
30 import org.apache.jackrabbit.webdav.*;
31 import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34 import org.springframework.context.ConfigurableApplicationContext;
35 import org.springframework.web.context.WebApplicationContext;
36 import org.springframework.web.context.support.WebApplicationContextUtils;
37
38 import javax.servlet.ServletConfig;
39 import javax.servlet.ServletException;
40 import javax.servlet.http.HttpServletRequest;
41 import javax.servlet.http.HttpServletResponse;
42 import java.io.IOException;
43 import java.nio.file.Files;
44 import java.nio.file.Path;
45 import java.nio.file.Paths;
46 import java.util.Map;
47
48 /**
49  * RepositoryServlet
50  */
51 public class RepositoryServlet
52     extends AbstractWebdavServlet
53     implements ConfigurationListener
54 {
55     private Logger log = LoggerFactory.getLogger( RepositoryServlet.class );
56
57     private ArchivaConfiguration configuration;
58
59     private ManagedRepositoryAdmin managedRepositoryAdmin;
60
61     private Map<String, ManagedRepository> repositoryMap;
62
63     private DavLocatorFactory locatorFactory;
64
65     private DavResourceFactory resourceFactory;
66
67     private DavSessionProvider sessionProvider;
68
69     private final Object reloadLock = new Object();
70
71     @Override
72     public void init( ServletConfig servletConfig )
73         throws ServletException
74     {
75         super.init( servletConfig );
76         try
77         {
78             initServers( servletConfig );
79         }
80         catch ( RepositoryAdminException e )
81         {
82             log.error( e.getMessage(), e );
83             throw new ServletException( e.getMessage(), e );
84         }
85     }
86
87     /**
88      * Service the given request. This method has been overridden and copy/pasted to allow better exception handling and
89      * to support different realms
90      *
91      * @param request
92      * @param response
93      * @throws ServletException
94      * @throws java.io.IOException
95      */
96     @Override
97     protected void service( HttpServletRequest request, HttpServletResponse response )
98         throws ServletException, IOException
99     {
100         WebdavRequest webdavRequest = new WebdavRequestImpl( request, getLocatorFactory() );
101         // DeltaV requires 'Cache-Control' header for all methods except 'VERSION-CONTROL' and 'REPORT'.
102         int methodCode = DavMethods.getMethodCode( request.getMethod() );
103         boolean noCache = DavMethods.isDeltaVMethod( webdavRequest ) && !( DavMethods.DAV_VERSION_CONTROL == methodCode
104             || DavMethods.DAV_REPORT == methodCode );
105         WebdavResponse webdavResponse = new WebdavResponseImpl( response, noCache );
106         DavResource resource = null;
107
108         try
109         {
110             // make sure there is a authenticated user
111             if ( !getDavSessionProvider().attachSession( webdavRequest ) )
112             {
113                 return;
114             }
115
116             // check matching if=header for lock-token relevant operations
117             resource =
118                 getResourceFactory().createResource( webdavRequest.getRequestLocator(), webdavRequest, webdavResponse );
119
120             if ( !isPreconditionValid( webdavRequest, resource ) )
121             {
122                 webdavResponse.sendError( DavServletResponse.SC_PRECONDITION_FAILED );
123                 return;
124             }
125             if ( !execute( webdavRequest, webdavResponse, methodCode, resource ) )
126             {
127                 super.service( request, response );
128             }
129
130         }
131         catch ( UnauthorizedDavException e )
132         {
133             webdavResponse.setHeader( "WWW-Authenticate", getAuthenticateHeaderValue( e.getRepositoryName() ) );
134             webdavResponse.sendError( e.getErrorCode(), e.getStatusPhrase() );
135         }
136         catch ( BrowserRedirectException e )
137         {
138             response.sendRedirect( e.getLocation() );
139         }
140         catch ( DavException e )
141         {
142             if ( e.getErrorCode() == HttpServletResponse.SC_UNAUTHORIZED )
143             {
144                 final String msg = "Should throw " + UnauthorizedDavException.class.getName();
145                 log.error( msg );
146                 webdavResponse.sendError( e.getErrorCode(), msg );
147             }
148             else if ( e.getCause() != null )
149             {
150                 webdavResponse.sendError( e.getErrorCode(), e.getCause().getMessage() );
151             }
152             else
153             {
154                 webdavResponse.sendError( e.getErrorCode(), e.getMessage() );
155             }
156         }
157         finally
158         {
159             getDavSessionProvider().releaseSession( webdavRequest );
160         }
161     }
162
163     public synchronized void initServers( ServletConfig servletConfig )
164         throws RepositoryAdminException
165     {
166
167         long start = System.currentTimeMillis();
168
169         WebApplicationContext wac =
170             WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
171
172         configuration = wac.getBean( "archivaConfiguration#default", ArchivaConfiguration.class );
173         configuration.addListener( this );
174
175         managedRepositoryAdmin = wac.getBean( ManagedRepositoryAdmin.class );
176
177         repositoryMap = managedRepositoryAdmin.getManagedRepositoriesAsMap();
178
179         for ( ManagedRepository repo : repositoryMap.values() )
180         {
181             Path repoDir = Paths.get( repo.getLocation() );
182
183             if ( !Files.exists(repoDir) )
184             {
185                 try
186                 {
187                     Files.createDirectories( repoDir );
188                 }
189                 catch ( IOException e )
190                 {
191                     log.info( "Unable to create missing directory for {}", repo.getLocation() );
192                     continue;
193                 }
194             }
195         }
196
197         resourceFactory = wac.getBean( "davResourceFactory#archiva", DavResourceFactory.class );
198         locatorFactory = new ArchivaDavLocatorFactory();
199
200         ServletAuthenticator servletAuth = wac.getBean( ServletAuthenticator.class );
201         HttpAuthenticator httpAuth = wac.getBean( "httpAuthenticator#basic", HttpAuthenticator.class );
202
203         sessionProvider = new ArchivaDavSessionProvider( servletAuth, httpAuth );
204
205         long end = System.currentTimeMillis();
206
207         log.info( "initServers done in {} ms", (end - start) );
208     }
209
210     @Override
211     public void configurationEvent( ConfigurationEvent event )
212     {
213         if ( event.getType() == ConfigurationEvent.SAVED )
214         {
215             try
216             {
217                 initRepositories();
218             }
219             catch ( RepositoryAdminException e )
220             {
221                 log.error( e.getMessage(), e );
222                 throw new RuntimeException( e.getMessage(), e );
223             }
224         }
225     }
226
227     private void initRepositories()
228         throws RepositoryAdminException
229     {
230         synchronized ( repositoryMap )
231         {
232             repositoryMap.clear();
233             repositoryMap.putAll( managedRepositoryAdmin.getManagedRepositoriesAsMap() );
234         }
235
236         synchronized ( reloadLock )
237         {
238             initServers( getServletConfig() );
239         }
240     }
241
242     public synchronized ManagedRepository getRepository( String prefix )
243         throws RepositoryAdminException
244     {
245         if ( repositoryMap.isEmpty() )
246         {
247             repositoryMap.putAll( managedRepositoryAdmin.getManagedRepositoriesAsMap() );
248         }
249         return repositoryMap.get( prefix );
250     }
251
252     ArchivaConfiguration getConfiguration()
253     {
254         return configuration;
255     }
256
257     @Override
258     protected boolean isPreconditionValid( final WebdavRequest request, final DavResource davResource )
259     {
260         // check for read or write access to the resource when resource-based permission is implemented
261
262         return true;
263     }
264
265     @Override
266     public DavSessionProvider getDavSessionProvider()
267     {
268         return sessionProvider;
269     }
270
271     @Override
272     public void setDavSessionProvider( final DavSessionProvider davSessionProvider )
273     {
274         this.sessionProvider = davSessionProvider;
275     }
276
277     @Override
278     public DavLocatorFactory getLocatorFactory()
279     {
280         return locatorFactory;
281     }
282
283     @Override
284     public void setLocatorFactory( final DavLocatorFactory davLocatorFactory )
285     {
286         locatorFactory = davLocatorFactory;
287     }
288
289     @Override
290     public DavResourceFactory getResourceFactory()
291     {
292         return resourceFactory;
293     }
294
295     @Override
296     public void setResourceFactory( final DavResourceFactory davResourceFactory )
297     {
298         resourceFactory = davResourceFactory;
299     }
300
301     @Override
302     public String getAuthenticateHeaderValue()
303     {
304         throw new UnsupportedOperationException();
305     }
306
307     public String getAuthenticateHeaderValue( String repository )
308     {
309         return "Basic realm=\"Repository Archiva Managed " + repository + " Repository\"";
310     }
311
312     @Override
313     public void destroy()
314     {
315         configuration.removeListener( this );
316
317         resourceFactory = null;
318         configuration = null;
319         locatorFactory = null;
320         sessionProvider = null;
321         repositoryMap.clear();
322         repositoryMap = null;
323
324         WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext( getServletContext() );
325
326         if ( wac instanceof ConfigurableApplicationContext )
327         {
328             ( (ConfigurableApplicationContext) wac ).close();
329         }
330         super.destroy();
331     }
332 }