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