This project has retired. For details please refer to its Attic page.
Source code
001package org.apache.archiva.webdav;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.archiva.admin.model.RepositoryAdminException;
023import org.apache.archiva.admin.model.beans.ManagedRepository;
024import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
025import org.apache.archiva.configuration.ArchivaConfiguration;
026import org.apache.archiva.configuration.ConfigurationEvent;
027import org.apache.archiva.configuration.ConfigurationListener;
028import org.apache.archiva.redback.integration.filter.authentication.HttpAuthenticator;
029import org.apache.archiva.security.ServletAuthenticator;
030import org.apache.jackrabbit.webdav.DavException;
031import org.apache.jackrabbit.webdav.DavLocatorFactory;
032import org.apache.jackrabbit.webdav.DavMethods;
033import org.apache.jackrabbit.webdav.DavResource;
034import org.apache.jackrabbit.webdav.DavResourceFactory;
035import org.apache.jackrabbit.webdav.DavServletResponse;
036import org.apache.jackrabbit.webdav.DavSessionProvider;
037import org.apache.jackrabbit.webdav.WebdavRequest;
038import org.apache.jackrabbit.webdav.WebdavRequestImpl;
039import org.apache.jackrabbit.webdav.WebdavResponse;
040import org.apache.jackrabbit.webdav.WebdavResponseImpl;
041import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
042import org.slf4j.Logger;
043import org.slf4j.LoggerFactory;
044import org.springframework.context.ConfigurableApplicationContext;
045import org.springframework.web.context.WebApplicationContext;
046import org.springframework.web.context.support.WebApplicationContextUtils;
047
048import javax.servlet.ServletConfig;
049import javax.servlet.ServletException;
050import javax.servlet.http.HttpServletRequest;
051import javax.servlet.http.HttpServletResponse;
052import java.io.File;
053import java.io.IOException;
054import java.util.Map;
055
056/**
057 * RepositoryServlet
058 */
059public class RepositoryServlet
060    extends AbstractWebdavServlet
061    implements ConfigurationListener
062{
063    private Logger log = LoggerFactory.getLogger( RepositoryServlet.class );
064
065    private ArchivaConfiguration configuration;
066
067    private ManagedRepositoryAdmin managedRepositoryAdmin;
068
069    private Map<String, ManagedRepository> repositoryMap;
070
071    private DavLocatorFactory locatorFactory;
072
073    private DavResourceFactory resourceFactory;
074
075    private DavSessionProvider sessionProvider;
076
077    private final Object reloadLock = new Object();
078
079    @Override
080    public void init( ServletConfig servletConfig )
081        throws ServletException
082    {
083        super.init( servletConfig );
084        try
085        {
086            initServers( servletConfig );
087        }
088        catch ( RepositoryAdminException e )
089        {
090            log.error( e.getMessage(), e );
091            throw new ServletException( e.getMessage(), e );
092        }
093    }
094
095    /**
096     * Service the given request. This method has been overridden and copy/pasted to allow better exception handling and
097     * to support different realms
098     *
099     * @param request
100     * @param response
101     * @throws ServletException
102     * @throws java.io.IOException
103     */
104    @Override
105    protected void service( HttpServletRequest request, HttpServletResponse response )
106        throws ServletException, IOException
107    {
108        WebdavRequest webdavRequest = new WebdavRequestImpl( request, getLocatorFactory() );
109        // DeltaV requires 'Cache-Control' header for all methods except 'VERSION-CONTROL' and 'REPORT'.
110        int methodCode = DavMethods.getMethodCode( request.getMethod() );
111        boolean noCache = DavMethods.isDeltaVMethod( webdavRequest ) && !( DavMethods.DAV_VERSION_CONTROL == methodCode
112            || DavMethods.DAV_REPORT == methodCode );
113        WebdavResponse webdavResponse = new WebdavResponseImpl( response, noCache );
114        DavResource resource = null;
115
116        try
117        {
118            // make sure there is a authenticated user
119            if ( !getDavSessionProvider().attachSession( webdavRequest ) )
120            {
121                return;
122            }
123
124            // check matching if=header for lock-token relevant operations
125            resource =
126                getResourceFactory().createResource( webdavRequest.getRequestLocator(), webdavRequest, webdavResponse );
127
128            if ( !isPreconditionValid( webdavRequest, resource ) )
129            {
130                webdavResponse.sendError( DavServletResponse.SC_PRECONDITION_FAILED );
131                return;
132            }
133            if ( !execute( webdavRequest, webdavResponse, methodCode, resource ) )
134            {
135                super.service( request, response );
136            }
137
138        }
139        catch ( UnauthorizedDavException e )
140        {
141            webdavResponse.setHeader( "WWW-Authenticate", getAuthenticateHeaderValue( e.getRepositoryName() ) );
142            webdavResponse.sendError( e.getErrorCode(), e.getStatusPhrase() );
143        }
144        catch ( BrowserRedirectException e )
145        {
146            response.sendRedirect( e.getLocation() );
147        }
148        catch ( DavException e )
149        {
150            if ( e.getErrorCode() == HttpServletResponse.SC_UNAUTHORIZED )
151            {
152                final String msg = "Should throw " + UnauthorizedDavException.class.getName();
153                log.error( msg );
154                webdavResponse.sendError( e.getErrorCode(), msg );
155            }
156            else if ( e.getCause() != null )
157            {
158                webdavResponse.sendError( e.getErrorCode(), e.getCause().getMessage() );
159            }
160            else
161            {
162                webdavResponse.sendError( e.getErrorCode(), e.getMessage() );
163            }
164        }
165        finally
166        {
167            getDavSessionProvider().releaseSession( webdavRequest );
168        }
169    }
170
171    public synchronized void initServers( ServletConfig servletConfig )
172        throws RepositoryAdminException
173    {
174
175        long start = System.currentTimeMillis();
176
177        WebApplicationContext wac =
178            WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
179
180        configuration = wac.getBean( "archivaConfiguration#default", ArchivaConfiguration.class );
181        configuration.addListener( this );
182
183        managedRepositoryAdmin = wac.getBean( ManagedRepositoryAdmin.class );
184
185        repositoryMap = managedRepositoryAdmin.getManagedRepositoriesAsMap();
186
187        for ( ManagedRepository repo : repositoryMap.values() )
188        {
189            File repoDir = new File( repo.getLocation() );
190
191            if ( !repoDir.exists() )
192            {
193                if ( !repoDir.mkdirs() )
194                {
195                    // Skip invalid directories.
196                    log.info( "Unable to create missing directory for {}", repo.getLocation() );
197                    continue;
198                }
199            }
200        }
201
202        resourceFactory = wac.getBean( "davResourceFactory#archiva", DavResourceFactory.class );
203        locatorFactory = new ArchivaDavLocatorFactory();
204
205        ServletAuthenticator servletAuth = wac.getBean( ServletAuthenticator.class );
206        HttpAuthenticator httpAuth = wac.getBean( "httpAuthenticator#basic", HttpAuthenticator.class );
207
208        sessionProvider = new ArchivaDavSessionProvider( servletAuth, httpAuth );
209
210        long end = System.currentTimeMillis();
211
212        log.info( "initServers done in {} ms", (end - start) );
213    }
214
215    @Override
216    public void configurationEvent( ConfigurationEvent event )
217    {
218        if ( event.getType() == ConfigurationEvent.SAVED )
219        {
220            try
221            {
222                initRepositories();
223            }
224            catch ( RepositoryAdminException e )
225            {
226                log.error( e.getMessage(), e );
227                throw new RuntimeException( e.getMessage(), e );
228            }
229        }
230    }
231
232    private void initRepositories()
233        throws RepositoryAdminException
234    {
235        synchronized ( repositoryMap )
236        {
237            repositoryMap.clear();
238            repositoryMap.putAll( managedRepositoryAdmin.getManagedRepositoriesAsMap() );
239        }
240
241        synchronized ( reloadLock )
242        {
243            initServers( getServletConfig() );
244        }
245    }
246
247    public synchronized ManagedRepository getRepository( String prefix )
248        throws RepositoryAdminException
249    {
250        if ( repositoryMap.isEmpty() )
251        {
252            repositoryMap.putAll( managedRepositoryAdmin.getManagedRepositoriesAsMap() );
253        }
254        return repositoryMap.get( prefix );
255    }
256
257    ArchivaConfiguration getConfiguration()
258    {
259        return configuration;
260    }
261
262    @Override
263    protected boolean isPreconditionValid( final WebdavRequest request, final DavResource davResource )
264    {
265        // check for read or write access to the resource when resource-based permission is implemented
266
267        return true;
268    }
269
270    @Override
271    public DavSessionProvider getDavSessionProvider()
272    {
273        return sessionProvider;
274    }
275
276    @Override
277    public void setDavSessionProvider( final DavSessionProvider davSessionProvider )
278    {
279        this.sessionProvider = davSessionProvider;
280    }
281
282    @Override
283    public DavLocatorFactory getLocatorFactory()
284    {
285        return locatorFactory;
286    }
287
288    @Override
289    public void setLocatorFactory( final DavLocatorFactory davLocatorFactory )
290    {
291        locatorFactory = davLocatorFactory;
292    }
293
294    @Override
295    public DavResourceFactory getResourceFactory()
296    {
297        return resourceFactory;
298    }
299
300    @Override
301    public void setResourceFactory( final DavResourceFactory davResourceFactory )
302    {
303        resourceFactory = davResourceFactory;
304    }
305
306    @Override
307    public String getAuthenticateHeaderValue()
308    {
309        throw new UnsupportedOperationException();
310    }
311
312    public String getAuthenticateHeaderValue( String repository )
313    {
314        return "Basic realm=\"Repository Archiva Managed " + repository + " Repository\"";
315    }
316
317    @Override
318    public void destroy()
319    {
320        configuration.removeListener( this );
321
322        resourceFactory = null;
323        configuration = null;
324        locatorFactory = null;
325        sessionProvider = null;
326        repositoryMap.clear();
327        repositoryMap = null;
328
329        WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext( getServletContext() );
330
331        if ( wac instanceof ConfigurableApplicationContext )
332        {
333            ( (ConfigurableApplicationContext) wac ).close();
334        }
335        super.destroy();
336    }
337}