org.apache.archiva.webdav.RepositoryServlet Maven / Gradle / Ivy
The newest version!
package org.apache.archiva.webdav;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.admin.model.RepositoryAdminException;
import org.apache.archiva.admin.model.beans.ManagedRepository;
import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
import org.apache.archiva.configuration.ArchivaConfiguration;
import org.apache.archiva.configuration.ConfigurationEvent;
import org.apache.archiva.configuration.ConfigurationListener;
import org.apache.archiva.redback.integration.filter.authentication.HttpAuthenticator;
import org.apache.archiva.security.ServletAuthenticator;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.DavLocatorFactory;
import org.apache.jackrabbit.webdav.DavMethods;
import org.apache.jackrabbit.webdav.DavResource;
import org.apache.jackrabbit.webdav.DavResourceFactory;
import org.apache.jackrabbit.webdav.DavServletResponse;
import org.apache.jackrabbit.webdav.DavSessionProvider;
import org.apache.jackrabbit.webdav.WebdavRequest;
import org.apache.jackrabbit.webdav.WebdavRequestImpl;
import org.apache.jackrabbit.webdav.WebdavResponse;
import org.apache.jackrabbit.webdav.WebdavResponseImpl;
import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.Map;
/**
* RepositoryServlet
*/
public class RepositoryServlet
extends AbstractWebdavServlet
implements ConfigurationListener
{
private Logger log = LoggerFactory.getLogger( RepositoryServlet.class );
private ArchivaConfiguration configuration;
private ManagedRepositoryAdmin managedRepositoryAdmin;
private Map repositoryMap;
private DavLocatorFactory locatorFactory;
private DavResourceFactory resourceFactory;
private DavSessionProvider sessionProvider;
private final Object reloadLock = new Object();
@Override
public void init( ServletConfig servletConfig )
throws ServletException
{
super.init( servletConfig );
try
{
initServers( servletConfig );
}
catch ( RepositoryAdminException e )
{
log.error( e.getMessage(), e );
throw new ServletException( e.getMessage(), e );
}
}
/**
* Service the given request. This method has been overridden and copy/pasted to allow better exception handling and
* to support different realms
*
* @param request
* @param response
* @throws ServletException
* @throws java.io.IOException
*/
@Override
protected void service( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException
{
WebdavRequest webdavRequest = new WebdavRequestImpl( request, getLocatorFactory() );
// DeltaV requires 'Cache-Control' header for all methods except 'VERSION-CONTROL' and 'REPORT'.
int methodCode = DavMethods.getMethodCode( request.getMethod() );
boolean noCache = DavMethods.isDeltaVMethod( webdavRequest ) && !( DavMethods.DAV_VERSION_CONTROL == methodCode
|| DavMethods.DAV_REPORT == methodCode );
WebdavResponse webdavResponse = new WebdavResponseImpl( response, noCache );
DavResource resource = null;
try
{
// make sure there is a authenticated user
if ( !getDavSessionProvider().attachSession( webdavRequest ) )
{
return;
}
// check matching if=header for lock-token relevant operations
resource =
getResourceFactory().createResource( webdavRequest.getRequestLocator(), webdavRequest, webdavResponse );
if ( !isPreconditionValid( webdavRequest, resource ) )
{
webdavResponse.sendError( DavServletResponse.SC_PRECONDITION_FAILED );
return;
}
if ( !execute( webdavRequest, webdavResponse, methodCode, resource ) )
{
super.service( request, response );
}
}
catch ( UnauthorizedDavException e )
{
webdavResponse.setHeader( "WWW-Authenticate", getAuthenticateHeaderValue( e.getRepositoryName() ) );
webdavResponse.sendError( e.getErrorCode(), e.getStatusPhrase() );
}
catch ( BrowserRedirectException e )
{
response.sendRedirect( e.getLocation() );
}
catch ( DavException e )
{
if ( e.getErrorCode() == HttpServletResponse.SC_UNAUTHORIZED )
{
final String msg = "Should throw " + UnauthorizedDavException.class.getName();
log.error( msg );
webdavResponse.sendError( e.getErrorCode(), msg );
}
else if ( e.getCause() != null )
{
webdavResponse.sendError( e.getErrorCode(), e.getCause().getMessage() );
}
else
{
webdavResponse.sendError( e.getErrorCode(), e.getMessage() );
}
}
finally
{
getDavSessionProvider().releaseSession( webdavRequest );
}
}
public synchronized void initServers( ServletConfig servletConfig )
throws RepositoryAdminException
{
long start = System.currentTimeMillis();
WebApplicationContext wac =
WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
configuration = wac.getBean( "archivaConfiguration#default", ArchivaConfiguration.class );
configuration.addListener( this );
managedRepositoryAdmin = wac.getBean( ManagedRepositoryAdmin.class );
repositoryMap = managedRepositoryAdmin.getManagedRepositoriesAsMap();
for ( ManagedRepository repo : repositoryMap.values() )
{
File repoDir = new File( repo.getLocation() );
if ( !repoDir.exists() )
{
if ( !repoDir.mkdirs() )
{
// Skip invalid directories.
log.info( "Unable to create missing directory for {}", repo.getLocation() );
continue;
}
}
}
resourceFactory = wac.getBean( "davResourceFactory#archiva", DavResourceFactory.class );
locatorFactory = new ArchivaDavLocatorFactory();
ServletAuthenticator servletAuth = wac.getBean( ServletAuthenticator.class );
HttpAuthenticator httpAuth = wac.getBean( "httpAuthenticator#basic", HttpAuthenticator.class );
sessionProvider = new ArchivaDavSessionProvider( servletAuth, httpAuth );
long end = System.currentTimeMillis();
log.info( "initServers done in {} ms", (end - start) );
}
@Override
public void configurationEvent( ConfigurationEvent event )
{
if ( event.getType() == ConfigurationEvent.SAVED )
{
try
{
initRepositories();
}
catch ( RepositoryAdminException e )
{
log.error( e.getMessage(), e );
throw new RuntimeException( e.getMessage(), e );
}
}
}
private void initRepositories()
throws RepositoryAdminException
{
synchronized ( repositoryMap )
{
repositoryMap.clear();
repositoryMap.putAll( managedRepositoryAdmin.getManagedRepositoriesAsMap() );
}
synchronized ( reloadLock )
{
initServers( getServletConfig() );
}
}
public synchronized ManagedRepository getRepository( String prefix )
throws RepositoryAdminException
{
if ( repositoryMap.isEmpty() )
{
repositoryMap.putAll( managedRepositoryAdmin.getManagedRepositoriesAsMap() );
}
return repositoryMap.get( prefix );
}
ArchivaConfiguration getConfiguration()
{
return configuration;
}
@Override
protected boolean isPreconditionValid( final WebdavRequest request, final DavResource davResource )
{
// check for read or write access to the resource when resource-based permission is implemented
return true;
}
@Override
public DavSessionProvider getDavSessionProvider()
{
return sessionProvider;
}
@Override
public void setDavSessionProvider( final DavSessionProvider davSessionProvider )
{
this.sessionProvider = davSessionProvider;
}
@Override
public DavLocatorFactory getLocatorFactory()
{
return locatorFactory;
}
@Override
public void setLocatorFactory( final DavLocatorFactory davLocatorFactory )
{
locatorFactory = davLocatorFactory;
}
@Override
public DavResourceFactory getResourceFactory()
{
return resourceFactory;
}
@Override
public void setResourceFactory( final DavResourceFactory davResourceFactory )
{
resourceFactory = davResourceFactory;
}
@Override
public String getAuthenticateHeaderValue()
{
throw new UnsupportedOperationException();
}
public String getAuthenticateHeaderValue( String repository )
{
return "Basic realm=\"Repository Archiva Managed " + repository + " Repository\"";
}
@Override
public void destroy()
{
configuration.removeListener( this );
resourceFactory = null;
configuration = null;
locatorFactory = null;
sessionProvider = null;
repositoryMap.clear();
repositoryMap = null;
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext( getServletContext() );
if ( wac instanceof ConfigurableApplicationContext )
{
( (ConfigurableApplicationContext) wac ).close();
}
super.destroy();
}
}