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