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.configuration.ArchivaConfiguration;
024import org.apache.archiva.configuration.ConfigurationEvent;
025import org.apache.archiva.configuration.ConfigurationListener;
026import org.apache.archiva.redback.integration.filter.authentication.HttpAuthenticator;
027import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
028import org.apache.archiva.repository.ManagedRepository;
029import org.apache.archiva.repository.RepositoryRegistry;
030import org.apache.archiva.security.ServletAuthenticator;
031import org.apache.jackrabbit.webdav.DavException;
032import org.apache.jackrabbit.webdav.DavLocatorFactory;
033import org.apache.jackrabbit.webdav.DavMethods;
034import org.apache.jackrabbit.webdav.DavResource;
035import org.apache.jackrabbit.webdav.DavResourceFactory;
036import org.apache.jackrabbit.webdav.DavServletResponse;
037import org.apache.jackrabbit.webdav.DavSessionProvider;
038import org.apache.jackrabbit.webdav.WebdavRequest;
039import org.apache.jackrabbit.webdav.WebdavRequestImpl;
040import org.apache.jackrabbit.webdav.WebdavResponse;
041import org.apache.jackrabbit.webdav.WebdavResponseImpl;
042import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
043import org.slf4j.Logger;
044import org.slf4j.LoggerFactory;
045import org.springframework.context.ConfigurableApplicationContext;
046import org.springframework.web.context.WebApplicationContext;
047import org.springframework.web.context.support.WebApplicationContextUtils;
048
049import javax.servlet.ServletConfig;
050import javax.servlet.ServletException;
051import javax.servlet.http.HttpServletRequest;
052import javax.servlet.http.HttpServletResponse;
053import java.io.IOException;
054import java.util.concurrent.locks.ReentrantReadWriteLock;
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    RepositoryRegistry repositoryRegistry;
068
069    private DavLocatorFactory locatorFactory;
070
071    private DavResourceFactory resourceFactory;
072
073    private DavSessionProvider sessionProvider;
074
075    protected final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
076
077    @Override
078    public void init( ServletConfig servletConfig )
079        throws ServletException
080    {
081        super.init( servletConfig );
082        initServers( servletConfig );
083    }
084
085    /**
086     * Service the given request. This method has been overridden and copy/pasted to allow better exception handling and
087     * to support different realms
088     *
089     * @param request
090     * @param response
091     * @throws ServletException
092     * @throws java.io.IOException
093     */
094    @Override
095    protected void service( HttpServletRequest request, HttpServletResponse response )
096        throws ServletException, IOException
097    {
098        WebdavRequest webdavRequest = new WebdavRequestImpl( request, getLocatorFactory() );
099        // DeltaV requires 'Cache-Control' header for all methods except 'VERSION-CONTROL' and 'REPORT'.
100        int methodCode = DavMethods.getMethodCode( request.getMethod() );
101        boolean noCache = DavMethods.isDeltaVMethod( webdavRequest ) && !( DavMethods.DAV_VERSION_CONTROL == methodCode
102            || DavMethods.DAV_REPORT == methodCode );
103        WebdavResponse webdavResponse = new WebdavResponseImpl( response, noCache );
104        DavResource resource = null;
105
106        try
107        {
108            // make sure there is a authenticated user
109            if ( !getDavSessionProvider().attachSession( webdavRequest ) )
110            {
111                return;
112            }
113
114            // check matching if=header for lock-token relevant operations
115            resource =
116                getResourceFactory().createResource( webdavRequest.getRequestLocator(), webdavRequest, webdavResponse );
117
118            if ( !isPreconditionValid( webdavRequest, resource ) )
119            {
120                webdavResponse.sendError( DavServletResponse.SC_PRECONDITION_FAILED );
121                return;
122            }
123            if ( !execute( webdavRequest, webdavResponse, methodCode, resource ) )
124            {
125                super.service( request, response );
126            }
127
128        }
129        catch ( UnauthorizedDavException e )
130        {
131            webdavResponse.setHeader( "WWW-Authenticate", getAuthenticateHeaderValue( e.getRepositoryName() ) );
132            webdavResponse.sendError( e.getErrorCode(), e.getStatusPhrase() );
133        }
134        catch ( BrowserRedirectException e )
135        {
136            response.sendRedirect( e.getLocation() );
137        }
138        catch ( DavException e )
139        {
140            if ( e.getErrorCode() == HttpServletResponse.SC_UNAUTHORIZED )
141            {
142                final String msg = "Should throw " + UnauthorizedDavException.class.getName();
143                log.error( msg );
144                webdavResponse.sendError( e.getErrorCode(), msg );
145            }
146            else if ( e.getCause() != null )
147            {
148                webdavResponse.sendError( e.getErrorCode(), e.getCause().getMessage() );
149            }
150            else
151            {
152                webdavResponse.sendError( e.getErrorCode(), e.getMessage() );
153            }
154        }
155        finally
156        {
157            getDavSessionProvider().releaseSession( webdavRequest );
158        }
159    }
160
161    public void initServers( ServletConfig servletConfig ) {
162
163        long start = System.currentTimeMillis();
164
165        WebApplicationContext wac =
166            WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
167
168        rwLock.writeLock().lock();
169        try {
170            configuration = wac.getBean("archivaConfiguration#default", ArchivaConfiguration.class);
171            configuration.addListener(this);
172
173            repositoryRegistry = wac.getBean( ArchivaRepositoryRegistry.class);
174            resourceFactory = wac.getBean("davResourceFactory#archiva", DavResourceFactory.class);
175            locatorFactory = new ArchivaDavLocatorFactory();
176
177            ServletAuthenticator servletAuth = wac.getBean(ServletAuthenticator.class);
178            HttpAuthenticator httpAuth = wac.getBean("httpAuthenticator#basic", HttpAuthenticator.class);
179
180            sessionProvider = new ArchivaDavSessionProvider(servletAuth, httpAuth);
181        } finally {
182            rwLock.writeLock().unlock();
183        }
184        long end = System.currentTimeMillis();
185
186        log.debug( "initServers done in {} ms", (end - start) );
187    }
188
189    @Override
190    public void configurationEvent( ConfigurationEvent event )
191    {
192        if ( event.getType() == ConfigurationEvent.SAVED )
193        {
194            try
195            {
196                initRepositories();
197            }
198            catch ( RepositoryAdminException e )
199            {
200                log.error( e.getMessage(), e );
201                throw new RuntimeException( e.getMessage(), e );
202            }
203        }
204    }
205
206    private void initRepositories()
207        throws RepositoryAdminException
208    {
209            initServers( getServletConfig() );
210    }
211
212    public ManagedRepository getRepository( String prefix )
213        throws RepositoryAdminException
214    {
215        return repositoryRegistry.getManagedRepository( prefix );
216    }
217
218    ArchivaConfiguration getConfiguration()
219    {
220        return configuration;
221    }
222
223    @Override
224    protected boolean isPreconditionValid( final WebdavRequest request, final DavResource davResource )
225    {
226        // check for read or write access to the resource when resource-based permission is implemented
227
228        return true;
229    }
230
231    @Override
232    public DavSessionProvider getDavSessionProvider()
233    {
234        return sessionProvider;
235    }
236
237    @Override
238    public void setDavSessionProvider( final DavSessionProvider davSessionProvider )
239    {
240        this.sessionProvider = davSessionProvider;
241    }
242
243    @Override
244    public DavLocatorFactory getLocatorFactory()
245    {
246        return locatorFactory;
247    }
248
249    @Override
250    public void setLocatorFactory( final DavLocatorFactory davLocatorFactory )
251    {
252        locatorFactory = davLocatorFactory;
253    }
254
255    @Override
256    public DavResourceFactory getResourceFactory()
257    {
258        return resourceFactory;
259    }
260
261    @Override
262    public void setResourceFactory( final DavResourceFactory davResourceFactory )
263    {
264        resourceFactory = davResourceFactory;
265    }
266
267    @Override
268    public String getAuthenticateHeaderValue()
269    {
270        throw new UnsupportedOperationException();
271    }
272
273    public String getAuthenticateHeaderValue( String repository )
274    {
275        return "Basic realm=\"Repository Archiva Managed " + repository + " Repository\"";
276    }
277
278    @Override
279    public void destroy()
280    {
281        rwLock.writeLock().lock();
282        try {
283            configuration.removeListener(this);
284
285            resourceFactory = null;
286            configuration = null;
287            locatorFactory = null;
288            sessionProvider = null;
289
290            WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
291
292            if (wac instanceof ConfigurableApplicationContext) {
293                ((ConfigurableApplicationContext) wac).close();
294            }
295            super.destroy();
296        } finally {
297            rwLock.writeLock().unlock();
298        }
299    }
300}