X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Finternal%2Fkernel%2FDataHttp.java;h=a1507a5910aaf2392c76a04d317380d266e70cbf;hb=0243aa5633af84d8608ba912483dbaaaefac42f1;hp=9f9864d7705a0e304438e4bce5c0dc5b9075740e;hpb=ce9977184198a5428ef98e5e8174e7f57c0988e0;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DataHttp.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DataHttp.java index 9f9864d77..a1507a591 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DataHttp.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DataHttp.java @@ -1,7 +1,5 @@ package org.argeo.cms.internal.kernel; -import static org.argeo.cms.auth.AuthConstants.LOGIN_CONTEXT_USER; - import java.io.IOException; import java.io.Serializable; import java.net.URL; @@ -32,29 +30,36 @@ import org.apache.jackrabbit.server.SessionProvider; import org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet; import org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet; import org.argeo.cms.CmsException; -import org.argeo.cms.auth.AuthConstants; -import org.argeo.cms.auth.CurrentUser; import org.argeo.cms.auth.HttpRequestCallback; import org.argeo.cms.auth.HttpRequestCallbackHandler; -import org.argeo.jcr.ArgeoJcrConstants; import org.argeo.jcr.JcrUtils; +import org.argeo.node.NodeConstants; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; import org.osgi.service.http.HttpContext; import org.osgi.service.http.HttpService; import org.osgi.service.http.NamespaceException; import org.osgi.service.useradmin.Authorization; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; /** * Intercepts and enriches http access, mainly focusing on security and * transactionality. */ -class DataHttp implements KernelConstants, ArgeoJcrConstants { +class DataHttp implements KernelConstants { private final static Log log = LogFactory.getLog(DataHttp.class); // private final static String ATTR_AUTH = "auth"; private final static String HEADER_AUTHORIZATION = "Authorization"; private final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate"; + private final static String DEFAULT_PROTECTED_HANDLERS = "/org/argeo/cms/internal/kernel/protectedHandlers.xml"; + + private final BundleContext bc; private final HttpService httpService; + private final ServiceTracker repositories; // FIXME Make it more unique private String httpAuthRealm = "Argeo"; @@ -63,13 +68,15 @@ class DataHttp implements KernelConstants, ArgeoJcrConstants { private OpenInViewSessionProvider sessionProvider; DataHttp(HttpService httpService) { - this.httpService = httpService; + this.bc = FrameworkUtil.getBundle(getClass()).getBundleContext(); sessionProvider = new OpenInViewSessionProvider(); - // registerRepositoryServlets(ALIAS_NODE, node); + this.httpService = httpService; + repositories = new ServiceTracker<>(bc, Repository.class, new RepositoriesStc()); + repositories.open(); } public void destroy() { - // unregisterRepositoryServlets(ALIAS_NODE); + repositories.close(); } void registerRepositoryServlets(String alias, Repository repository) { @@ -78,20 +85,30 @@ class DataHttp implements KernelConstants, ArgeoJcrConstants { registerWebdavServlet(alias, repository, false); registerRemotingServlet(alias, repository, true); registerRemotingServlet(alias, repository, false); + if (log.isDebugEnabled()) + log.debug("Registered servlets for repository '" + alias + "'"); } catch (Exception e) { - throw new CmsException("Could not register servlets for repository " + alias, e); + throw new CmsException("Could not register servlets for repository '" + alias + "'", e); } } void unregisterRepositoryServlets(String alias) { - // FIXME unregister servlets + try { + httpService.unregister(webdavPath(alias, true)); + httpService.unregister(webdavPath(alias, false)); + httpService.unregister(remotingPath(alias, true)); + httpService.unregister(remotingPath(alias, false)); + if (log.isDebugEnabled()) + log.debug("Unregistered servlets for repository '" + alias + "'"); + } catch (Exception e) { + log.error("Could not unregister servlets for repository '" + alias + "'", e); + } } void registerWebdavServlet(String alias, Repository repository, boolean anonymous) throws NamespaceException, ServletException { WebdavServlet webdavServlet = new WebdavServlet(repository, sessionProvider); - String pathPrefix = anonymous ? WEBDAV_PUBLIC : WEBDAV_PRIVATE; - String path = pathPrefix + "/" + alias; + String path = webdavPath(alias, anonymous); Properties ip = new Properties(); ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_CONFIG, WEBDAV_CONFIG); ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path); @@ -100,26 +117,34 @@ class DataHttp implements KernelConstants, ArgeoJcrConstants { void registerRemotingServlet(String alias, Repository repository, boolean anonymous) throws NamespaceException, ServletException { - String pathPrefix = anonymous ? REMOTING_PUBLIC : REMOTING_PRIVATE; RemotingServlet remotingServlet = new RemotingServlet(repository, sessionProvider); - String path = pathPrefix + "/" + alias; + String path = remotingPath(alias, anonymous); Properties ip = new Properties(); ip.setProperty(JcrRemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path); // Looks like a bug in Jackrabbit remoting init ip.setProperty(RemotingServlet.INIT_PARAM_HOME, KernelUtils.getOsgiInstanceDir() + "/tmp/jackrabbit"); ip.setProperty(RemotingServlet.INIT_PARAM_TMP_DIRECTORY, "remoting"); - // in order to avoid annoying warning. - ip.setProperty(RemotingServlet.INIT_PARAM_PROTECTED_HANDLERS_CONFIG, ""); + ip.setProperty(RemotingServlet.INIT_PARAM_PROTECTED_HANDLERS_CONFIG, DEFAULT_PROTECTED_HANDLERS); httpService.registerServlet(path, remotingServlet, ip, new DataHttpContext(anonymous)); } + private String webdavPath(String alias, boolean anonymous) { + String pathPrefix = anonymous ? WEBDAV_PUBLIC : WEBDAV_PRIVATE; + return pathPrefix + "/" + alias; + } + + private String remotingPath(String alias, boolean anonymous) { + String pathPrefix = anonymous ? REMOTING_PUBLIC : REMOTING_PRIVATE; + return pathPrefix + "/" + alias; + } + private Subject subjectFromRequest(HttpServletRequest request) { Authorization authorization = (Authorization) request.getAttribute(HttpContext.AUTHORIZATION); if (authorization == null) throw new CmsException("Not authenticated"); try { - LoginContext lc = new LoginContext(AuthConstants.LOGIN_CONTEXT_USER, + LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request)); lc.login(); return lc.getSubject(); @@ -128,6 +153,33 @@ class DataHttp implements KernelConstants, ArgeoJcrConstants { } } + private class RepositoriesStc implements ServiceTrackerCustomizer { + + @Override + public Repository addingService(ServiceReference reference) { + Repository repository = bc.getService(reference); + Object jcrRepoAlias = reference.getProperty(NodeConstants.CN); + if (jcrRepoAlias != null) { + String alias = jcrRepoAlias.toString(); + registerRepositoryServlets(alias, repository); + } + return repository; + } + + @Override + public void modifiedService(ServiceReference reference, Repository service) { + } + + @Override + public void removedService(ServiceReference reference, Repository service) { + Object jcrRepoAlias = reference.getProperty(NodeConstants.CN); + if (jcrRepoAlias != null) { + String alias = jcrRepoAlias.toString(); + unregisterRepositoryServlets(alias); + } + } + } + private class DataHttpContext implements HttpContext { private final boolean anonymous; @@ -142,7 +194,7 @@ class DataHttp implements KernelConstants, ArgeoJcrConstants { if (anonymous) { Subject subject = KernelUtils.anonymousLogin(); Authorization authorization = subject.getPrivateCredentials(Authorization.class).iterator().next(); - request.setAttribute(REMOTE_USER, AuthConstants.ROLE_ANONYMOUS); + request.setAttribute(REMOTE_USER, NodeConstants.ROLE_ANONYMOUS); request.setAttribute(AUTHORIZATION, authorization); return true; } @@ -150,13 +202,13 @@ class DataHttp implements KernelConstants, ArgeoJcrConstants { if (log.isTraceEnabled()) KernelUtils.logRequestHeaders(log, request); try { - new LoginContext(LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request)).login(); + new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request)).login(); return true; } catch (CredentialNotFoundException e) { CallbackHandler token = basicAuth(request); if (token != null) { try { - LoginContext lc = new LoginContext(LOGIN_CONTEXT_USER, token); + LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, token); lc.login(); // Note: this is impossible to reliably clear the // authorization header when access from a browser. @@ -177,7 +229,7 @@ class DataHttp implements KernelConstants, ArgeoJcrConstants { @Override public URL getResource(String name) { - return Activator.getBundleContext().getBundle().getResource(name); + return KernelUtils.getBundleContext(DataHttp.class).getBundle().getResource(name); } @Override @@ -277,9 +329,12 @@ class DataHttp implements KernelConstants, ArgeoJcrConstants { throws ServletException, IOException { try { Subject subject = subjectFromRequest(request); - if (CurrentUser.isAnonymous(subject) && request.getMethod().equals("GET")) { - response.setHeader("Cache-Control", "no-transform, public, max-age=300, s-maxage=900"); - } + // TODO make it stronger, with eTags. + // if (CurrentUser.isAnonymous(subject) && + // request.getMethod().equals("GET")) { + // response.setHeader("Cache-Control", "no-transform, public, + // max-age=300, s-maxage=900"); + // } Subject.doAs(subject, new PrivilegedExceptionAction() { @Override