You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RepositoryServlet.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. package org.apache.maven.archiva.webdav;
  2. /*
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing,
  14. * software distributed under the License is distributed on an
  15. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  16. * KIND, either express or implied. See the License for the
  17. * specific language governing permissions and limitations
  18. * under the License.
  19. */
  20. import org.apache.archiva.admin.repository.RepositoryAdminException;
  21. import org.apache.archiva.admin.repository.managed.ManagedRepository;
  22. import org.apache.archiva.admin.repository.managed.ManagedRepositoryAdmin;
  23. import org.apache.archiva.security.ServletAuthenticator;
  24. import org.apache.jackrabbit.webdav.DavException;
  25. import org.apache.jackrabbit.webdav.DavLocatorFactory;
  26. import org.apache.jackrabbit.webdav.DavMethods;
  27. import org.apache.jackrabbit.webdav.DavResource;
  28. import org.apache.jackrabbit.webdav.DavResourceFactory;
  29. import org.apache.jackrabbit.webdav.DavServletResponse;
  30. import org.apache.jackrabbit.webdav.DavSessionProvider;
  31. import org.apache.jackrabbit.webdav.WebdavRequest;
  32. import org.apache.jackrabbit.webdav.WebdavRequestImpl;
  33. import org.apache.jackrabbit.webdav.WebdavResponse;
  34. import org.apache.jackrabbit.webdav.WebdavResponseImpl;
  35. import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
  36. import org.apache.maven.archiva.configuration.ArchivaConfiguration;
  37. import org.apache.maven.archiva.configuration.ConfigurationEvent;
  38. import org.apache.maven.archiva.configuration.ConfigurationListener;
  39. import org.codehaus.redback.integration.filter.authentication.HttpAuthenticator;
  40. import org.slf4j.Logger;
  41. import org.slf4j.LoggerFactory;
  42. import org.springframework.context.ConfigurableApplicationContext;
  43. import org.springframework.web.context.WebApplicationContext;
  44. import org.springframework.web.context.support.WebApplicationContextUtils;
  45. import javax.servlet.ServletConfig;
  46. import javax.servlet.ServletException;
  47. import javax.servlet.http.HttpServletRequest;
  48. import javax.servlet.http.HttpServletResponse;
  49. import java.io.File;
  50. import java.io.IOException;
  51. import java.util.Map;
  52. /**
  53. * RepositoryServlet
  54. */
  55. public class RepositoryServlet
  56. extends AbstractWebdavServlet
  57. implements ConfigurationListener
  58. {
  59. private Logger log = LoggerFactory.getLogger( RepositoryServlet.class );
  60. private ArchivaConfiguration configuration;
  61. private ManagedRepositoryAdmin managedRepositoryAdmin;
  62. private Map<String, ManagedRepository> repositoryMap;
  63. private DavLocatorFactory locatorFactory;
  64. private DavResourceFactory resourceFactory;
  65. private DavSessionProvider sessionProvider;
  66. private final Object reloadLock = new Object();
  67. public void init( javax.servlet.ServletConfig servletConfig )
  68. throws ServletException
  69. {
  70. super.init( servletConfig );
  71. try
  72. {
  73. initServers( servletConfig );
  74. }
  75. catch ( RepositoryAdminException e )
  76. {
  77. log.error( e.getMessage(), e );
  78. throw new ServletException( e.getMessage(), e );
  79. }
  80. }
  81. /**
  82. * Service the given request. This method has been overridden and copy/pasted to allow better exception handling and
  83. * to support different realms
  84. *
  85. * @param request
  86. * @param response
  87. * @throws ServletException
  88. * @throws java.io.IOException
  89. */
  90. @Override
  91. protected void service( HttpServletRequest request, HttpServletResponse response )
  92. throws ServletException, IOException
  93. {
  94. WebdavRequest webdavRequest = new WebdavRequestImpl( request, getLocatorFactory() );
  95. // DeltaV requires 'Cache-Control' header for all methods except 'VERSION-CONTROL' and 'REPORT'.
  96. int methodCode = DavMethods.getMethodCode( request.getMethod() );
  97. boolean noCache = DavMethods.isDeltaVMethod( webdavRequest ) && !( DavMethods.DAV_VERSION_CONTROL == methodCode
  98. || DavMethods.DAV_REPORT == methodCode );
  99. WebdavResponse webdavResponse = new WebdavResponseImpl( response, noCache );
  100. DavResource resource = null;
  101. try
  102. {
  103. // make sure there is a authenticated user
  104. if ( !getDavSessionProvider().attachSession( webdavRequest ) )
  105. {
  106. return;
  107. }
  108. // check matching if=header for lock-token relevant operations
  109. resource =
  110. getResourceFactory().createResource( webdavRequest.getRequestLocator(), webdavRequest, webdavResponse );
  111. if ( !isPreconditionValid( webdavRequest, resource ) )
  112. {
  113. webdavResponse.sendError( DavServletResponse.SC_PRECONDITION_FAILED );
  114. return;
  115. }
  116. if ( !execute( webdavRequest, webdavResponse, methodCode, resource ) )
  117. {
  118. super.service( request, response );
  119. }
  120. }
  121. catch ( UnauthorizedDavException e )
  122. {
  123. webdavResponse.setHeader( "WWW-Authenticate", getAuthenticateHeaderValue( e.getRepositoryName() ) );
  124. webdavResponse.sendError( e.getErrorCode(), e.getStatusPhrase() );
  125. }
  126. catch ( BrowserRedirectException e )
  127. {
  128. response.sendRedirect( e.getLocation() );
  129. }
  130. catch ( DavException e )
  131. {
  132. if ( e.getErrorCode() == HttpServletResponse.SC_UNAUTHORIZED )
  133. {
  134. final String msg = "Should throw " + UnauthorizedDavException.class.getName();
  135. log.error( msg );
  136. webdavResponse.sendError( e.getErrorCode(), msg );
  137. }
  138. else if ( e.getCause() != null )
  139. {
  140. webdavResponse.sendError( e.getErrorCode(), e.getCause().getMessage() );
  141. }
  142. else
  143. {
  144. webdavResponse.sendError( e.getErrorCode(), e.getMessage() );
  145. }
  146. }
  147. finally
  148. {
  149. getDavSessionProvider().releaseSession( webdavRequest );
  150. }
  151. }
  152. public synchronized void initServers( ServletConfig servletConfig )
  153. throws RepositoryAdminException
  154. {
  155. WebApplicationContext wac =
  156. WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
  157. configuration = wac.getBean( "archivaConfiguration#default", ArchivaConfiguration.class );
  158. configuration.addListener( this );
  159. managedRepositoryAdmin = wac.getBean( ManagedRepositoryAdmin.class );
  160. repositoryMap = managedRepositoryAdmin.getManagedRepositoriesAsMap();
  161. for ( ManagedRepository repo : repositoryMap.values() )
  162. {
  163. File repoDir = new File( repo.getLocation() );
  164. if ( !repoDir.exists() )
  165. {
  166. if ( !repoDir.mkdirs() )
  167. {
  168. // Skip invalid directories.
  169. log( "Unable to create missing directory for " + repo.getLocation() );
  170. continue;
  171. }
  172. }
  173. }
  174. resourceFactory = wac.getBean( "davResourceFactory#archiva", DavResourceFactory.class );
  175. locatorFactory = new ArchivaDavLocatorFactory();
  176. ServletAuthenticator servletAuth = wac.getBean( ServletAuthenticator.class );
  177. HttpAuthenticator httpAuth = wac.getBean( "httpAuthenticator#basic", HttpAuthenticator.class );
  178. sessionProvider = new ArchivaDavSessionProvider( servletAuth, httpAuth );
  179. log.info( "initServers done" );
  180. }
  181. public void configurationEvent( ConfigurationEvent event )
  182. {
  183. if ( event.getType() == ConfigurationEvent.SAVED )
  184. {
  185. try
  186. {
  187. initRepositories();
  188. }
  189. catch ( RepositoryAdminException e )
  190. {
  191. log.error( e.getMessage(), e );
  192. throw new RuntimeException( e.getMessage(), e );
  193. }
  194. }
  195. }
  196. private void initRepositories()
  197. throws RepositoryAdminException
  198. {
  199. synchronized ( repositoryMap )
  200. {
  201. repositoryMap.clear();
  202. repositoryMap.putAll( managedRepositoryAdmin.getManagedRepositoriesAsMap() );
  203. }
  204. synchronized ( reloadLock )
  205. {
  206. initServers( getServletConfig() );
  207. }
  208. }
  209. public synchronized ManagedRepository getRepository( String prefix )
  210. throws RepositoryAdminException
  211. {
  212. if ( repositoryMap.isEmpty() )
  213. {
  214. repositoryMap.putAll( managedRepositoryAdmin.getManagedRepositoriesAsMap() );
  215. }
  216. return repositoryMap.get( prefix );
  217. }
  218. ArchivaConfiguration getConfiguration()
  219. {
  220. return configuration;
  221. }
  222. protected boolean isPreconditionValid( final WebdavRequest request, final DavResource davResource )
  223. {
  224. // check for read or write access to the resource when resource-based permission is implemented
  225. return true;
  226. }
  227. public DavSessionProvider getDavSessionProvider()
  228. {
  229. return sessionProvider;
  230. }
  231. public void setDavSessionProvider( final DavSessionProvider davSessionProvider )
  232. {
  233. this.sessionProvider = davSessionProvider;
  234. }
  235. public DavLocatorFactory getLocatorFactory()
  236. {
  237. return locatorFactory;
  238. }
  239. public void setLocatorFactory( final DavLocatorFactory davLocatorFactory )
  240. {
  241. locatorFactory = davLocatorFactory;
  242. }
  243. public DavResourceFactory getResourceFactory()
  244. {
  245. return resourceFactory;
  246. }
  247. public void setResourceFactory( final DavResourceFactory davResourceFactory )
  248. {
  249. resourceFactory = davResourceFactory;
  250. }
  251. public String getAuthenticateHeaderValue()
  252. {
  253. throw new UnsupportedOperationException();
  254. }
  255. public String getAuthenticateHeaderValue( String repository )
  256. {
  257. return "Basic realm=\"Repository Archiva Managed " + repository + " Repository\"";
  258. }
  259. @Override
  260. public void destroy()
  261. {
  262. configuration.removeListener( this );
  263. resourceFactory = null;
  264. configuration = null;
  265. locatorFactory = null;
  266. sessionProvider = null;
  267. repositoryMap.clear();
  268. repositoryMap = null;
  269. WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext( getServletContext() );
  270. if ( wac instanceof ConfigurableApplicationContext )
  271. {
  272. ( (ConfigurableApplicationContext) wac ).close();
  273. }
  274. super.destroy();
  275. }
  276. }