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