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