--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="org.argeo.cms.dataServletContext">
+ <implementation class="org.argeo.cms.internal.http.CmsServletContextHelper"/>
+ <service>
+ <provide interface="org.osgi.service.http.context.ServletContextHelper"/>
+ </service>
+ <property name="osgi.http.whiteboard.context.name" type="String" value="dataServletContext"/>
+ <property name="osgi.http.whiteboard.context.path" type="String" value="/data"/>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="org.argeo.cms.jcrServletContext">
+ <implementation class="org.argeo.cms.internal.http.PrivateServletContextHelper"/>
+ <service>
+ <provide interface="org.osgi.service.http.context.ServletContextHelper"/>
+ </service>
+ <property name="osgi.http.whiteboard.context.name" type="String" value="jcrServletContext"/>
+ <property name="osgi.http.whiteboard.context.path" type="String" value="/jcr"/>
+</scr:component>
*
Service-Component: OSGI-INF/cmsUserManager.xml,\
+OSGI-INF/jcrServletContext.xml,\
+OSGI-INF/dataServletContext.xml,\
OSGI-INF/filesServletContext.xml,\
OSGI-INF/filesServlet.xml
--- /dev/null
+package org.argeo.cms.internal.http;
+
+import java.util.Map;
+
+import javax.jcr.Repository;
+
+import org.apache.jackrabbit.server.SessionProvider;
+import org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet;
+import org.argeo.api.NodeConstants;
+
+/** A {@link JcrRemotingServlet} based on {@link CmsSessionProvider}. */
+public class CmsRemotingServlet extends JcrRemotingServlet {
+ private static final long serialVersionUID = 6459455509684213633L;
+ private Repository repository;
+ private SessionProvider sessionProvider;
+
+ public CmsRemotingServlet() {
+ }
+
+ public CmsRemotingServlet(String alias, Repository repository) {
+ this.repository = repository;
+ this.sessionProvider = new CmsSessionProvider(alias);
+ }
+
+ @Override
+ public Repository getRepository() {
+ return repository;
+ }
+
+ public void setRepository(Repository repository, Map<String, String> properties) {
+ this.repository = repository;
+ String alias = properties.get(NodeConstants.CN);
+ if (alias != null)
+ sessionProvider = new CmsSessionProvider(alias);
+ else
+ throw new IllegalArgumentException("Only aliased repositories are supported");
+ }
+
+ @Override
+ protected SessionProvider getSessionProvider() {
+ return sessionProvider;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.internal.http;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Map;
+
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.cms.auth.HttpRequestCallbackHandler;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.service.http.context.ServletContextHelper;
+
+/**
+ * Default servlet context degrading to anonymous if the the sesison is not
+ * pre-authenticated.
+ */
+public class CmsServletContextHelper extends ServletContextHelper {
+ private final static Log log = LogFactory.getLog(CmsServletContextHelper.class);
+ // use CMS bundle for resources
+ private Bundle bundle = FrameworkUtil.getBundle(getClass());
+
+ public void init(Map<String, String> properties) {
+
+ }
+
+ public void destroy() {
+
+ }
+
+ @Override
+ public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ if (log.isTraceEnabled())
+ HttpUtils.logRequestHeaders(log, request);
+ LoginContext lc;
+ try {
+ lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request, response));
+ lc.login();
+ } catch (LoginException e) {
+ lc = processUnauthorized(request, response);
+ if (lc == null)
+ return false;
+ }
+ return true;
+ }
+
+ protected LoginContext processUnauthorized(HttpServletRequest request, HttpServletResponse response) {
+ // anonymous
+ try {
+ LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS,
+ new HttpRequestCallbackHandler(request, response));
+ lc.login();
+ return lc;
+ } catch (LoginException e1) {
+ if (log.isDebugEnabled())
+ log.error("Cannot log in as anonymous", e1);
+ return null;
+ }
+ }
+
+ @Override
+ public URL getResource(String name) {
+ return bundle.getResource(name);
+ }
+
+}
if (log.isTraceEnabled()) {
log.trace("Get JCR session from " + cmsSession);
}
+ if (cmsSession == null)
+ throw new IllegalStateException("Cannot find a session for request " + request.getRequestURI());
Session session = cmsSession.getDataSession(alias, workspace, rep);
cmsSessions.put(session, cmsSession);
return session;
import org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet;
import org.argeo.api.NodeConstants;
+/** A {@link SimpleWebdavServlet} based on {@link CmsSessionProvider}. */
public class CmsWebDavServlet extends SimpleWebdavServlet {
private static final long serialVersionUID = 7485800288686328063L;
private Repository repository;
+ public CmsWebDavServlet() {
+ }
+
+ public CmsWebDavServlet(String alias, Repository repository) {
+ this.repository = repository;
+ setSessionProvider(new CmsSessionProvider(alias));
+ }
+
@Override
public Repository getRepository() {
return repository;
String alias = properties.get(NodeConstants.CN);
if (alias != null)
setSessionProvider(new CmsSessionProvider(alias));
+ else
+ throw new IllegalArgumentException("Only aliased repositories are supported");
}
}
import org.osgi.framework.FrameworkUtil;
import org.osgi.service.http.HttpContext;
+@Deprecated
public class DataHttpContext implements HttpContext {
private final static Log log = LogFactory.getLog(DataHttpContext.class);
import javax.servlet.http.HttpServletResponse;
/** Requests authorisation */
+@Deprecated
public class PrivateHttpContext extends DataHttpContext {
public PrivateHttpContext(String httpAuthrealm, boolean forceBasic) {
package org.argeo.cms.internal.http;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Map;
-
import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.api.NodeConstants;
-import org.argeo.cms.auth.HttpRequestCallbackHandler;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.service.http.context.ServletContextHelper;
-
-public class PrivateServletContextHelper extends ServletContextHelper {
- private final static Log log = LogFactory.getLog(PrivateServletContextHelper.class);
-
+/** Servlet context forcing authentication. */
+public class PrivateServletContextHelper extends CmsServletContextHelper {
// TODO make it configurable
private final String httpAuthRealm = "Argeo";
private final boolean forceBasic = false;
- // use CMS bundle for resources
- private Bundle bundle = FrameworkUtil.getBundle(getClass());
-
- public void init(Map<String, String> properties) {
-
- }
-
- public void destroy() {
-
- }
-
@Override
- public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
- if (log.isTraceEnabled())
- HttpUtils.logRequestHeaders(log, request);
- LoginContext lc;
- try {
- lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request, response));
- lc.login();
- } catch (LoginException e) {
- askForWwwAuth(request, response);
- return false;
- }
- return true;
+ protected LoginContext processUnauthorized(HttpServletRequest request, HttpServletResponse response) {
+ askForWwwAuth(request, response);
+ return null;
}
protected void askForWwwAuth(HttpServletRequest request, HttpServletResponse response) {
// response.setContentType("text/html; charset=UTF-8");
}
-
- @Override
- public URL getResource(String name) {
- return bundle.getResource(name);
- }
-
}
package org.argeo.cms.internal.kernel;
import static org.argeo.api.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.lang.management.ManagementFactory;
import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.security.auth.callback.CallbackHandler;
+import javax.servlet.Servlet;
import javax.transaction.UserTransaction;
import org.apache.commons.logging.Log;
import org.argeo.api.security.Keyring;
import org.argeo.cms.ArgeoNames;
import org.argeo.cms.CmsException;
+import org.argeo.cms.internal.http.CmsRemotingServlet;
+import org.argeo.cms.internal.http.CmsWebDavServlet;
+import org.argeo.cms.internal.http.HttpUtils;
import org.argeo.jcr.JcrUtils;
import org.argeo.osgi.useradmin.UserAdminConf;
import org.argeo.util.LangUtils;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.cm.ManagedService;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
import org.osgi.service.useradmin.Group;
import org.osgi.service.useradmin.Role;
import org.osgi.service.useradmin.UserAdmin;
// private final boolean cleanState;
- private NodeHttp nodeHttp;
+// private NodeHttp nodeHttp;
+ private String webDavConfig = HttpUtils.WEBDAV_CONFIG;
private boolean argeoDataModelExtensionsAvailable = false;
// NodeState nodeState = bc.getService(nodeStateSr);
// cleanState = nodeState.isClean();
- nodeHttp = new NodeHttp();
+// nodeHttp = new NodeHttp();
dataModels = new DataModels(bc);
initTrackers();
}
private void initTrackers() {
- ServiceTracker<?, ?> httpSt = new ServiceTracker<NodeHttp, NodeHttp>(bc, NodeHttp.class, null) {
+ ServiceTracker<?, ?> httpSt = new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, null) {
@Override
- public NodeHttp addingService(ServiceReference<NodeHttp> reference) {
+ public HttpService addingService(ServiceReference<HttpService> sr) {
httpAvailable = true;
+ Object httpPort = sr.getProperty("http.port");
+ Object httpsPort = sr.getProperty("https.port");
+ log.info(httpPortsMsg(httpPort, httpsPort));
checkReadiness();
- return super.addingService(reference);
+ return super.addingService(sr);
}
};
// httpSt.open();
KernelUtils.asyncOpen(confAdminSt);
}
+ private String httpPortsMsg(Object httpPort, Object httpsPort) {
+ return (httpPort != null ? "HTTP " + httpPort + " " : " ") + (httpsPort != null ? "HTTPS " + httpsPort : "");
+ }
+
private void addStandardSystemRoles(UserAdmin userAdmin) {
// we assume UserTransaction is already available (TODO make it more robust)
UserTransaction userTransaction = bc.getService(bc.getServiceReference(UserTransaction.class));
}
public void shutdown() {
- if (nodeHttp != null)
- nodeHttp.destroy();
+// if (nodeHttp != null)
+// nodeHttp.destroy();
try {
for (ServiceReference<JackrabbitLocalRepository> sr : bc
classes = new String[] { Repository.class.getName(), LocalRepository.class.getName() };
}
bc.registerService(classes, localRepository, properties);
+
+ // TODO make it configurable
+ registerRepositoryServlets(dataModelName, localRepository);
if (log.isTraceEnabled())
log.trace("Published data model " + dataModelName);
}
return availableSince != null;
}
+ protected void registerRepositoryServlets(String alias, Repository repository) {
+ registerRemotingServlet(alias, repository);
+ registerWebdavServlet(alias, repository);
+ }
+
+ protected void registerWebdavServlet(String alias, Repository repository) {
+ CmsWebDavServlet webdavServlet = new CmsWebDavServlet(alias, repository);
+ Hashtable<String, String> ip = new Hashtable<>();
+ ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsWebDavServlet.INIT_PARAM_RESOURCE_CONFIG, webDavConfig);
+ ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsWebDavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX,
+ "/" + alias);
+
+ ip.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/" + alias + "/*");
+ ip.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT,
+ "(" + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH + "=" + NodeConstants.PATH_DATA + ")");
+ bc.registerService(Servlet.class, webdavServlet, ip);
+ }
+
+ protected void registerRemotingServlet(String alias, Repository repository) {
+ CmsRemotingServlet remotingServlet = new CmsRemotingServlet(alias, repository);
+ Hashtable<String, String> ip = new Hashtable<>();
+ ip.put(NodeConstants.CN, alias);
+ // Properties ip = new Properties();
+ ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsRemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX,
+ "/" + alias);
+ ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsRemotingServlet.INIT_PARAM_AUTHENTICATE_HEADER,
+ "Negotiate");
+
+ // Looks like a bug in Jackrabbit remoting init
+ Path tmpDir;
+ try {
+ tmpDir = Files.createTempDirectory("remoting_" + alias);
+ } catch (IOException e) {
+ throw new CmsException("Cannot create temp directory for remoting servlet", e);
+ }
+ ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsRemotingServlet.INIT_PARAM_HOME, tmpDir.toString());
+ ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsRemotingServlet.INIT_PARAM_TMP_DIRECTORY,
+ "remoting_" + alias);
+ ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsRemotingServlet.INIT_PARAM_PROTECTED_HANDLERS_CONFIG,
+ HttpUtils.DEFAULT_PROTECTED_HANDLERS);
+ ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsRemotingServlet.INIT_PARAM_CREATE_ABSOLUTE_URI, "false");
+
+ ip.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/" + alias + "/*");
+ ip.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT,
+ "(" + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH + "=" + NodeConstants.PATH_JCR + ")");
+ bc.registerService(Servlet.class, remotingServlet, ip);
+ }
+
private class RepositoryContextStc extends ServiceTracker<RepositoryContext, RepositoryContext> {
public RepositoryContextStc() {
prepareNodeRepository(repoContext.getRepository());
// TODO separate home repository
prepareHomeRepository(repoContext.getRepository());
+ registerRepositoryServlets(cn, repoContext.getRepository());
nodeAvailable = true;
checkReadiness();
} else {
* Intercepts and enriches http access, mainly focusing on security and
* transactionality.
*/
+@Deprecated
public class NodeHttp implements KernelConstants {
private final static Log log = LogFactory.getLog(NodeHttp.class);
package org.argeo.cms.internal.kernel;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX;
+
+import java.io.IOException;
import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Dictionary;
import java.util.HashMap;
+import java.util.Hashtable;
import java.util.Map;
import javax.jcr.Repository;
import javax.jcr.RepositoryFactory;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.core.RepositoryContext;
+import org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet;
import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
+import org.argeo.cms.internal.http.CmsRemotingServlet;
+import org.argeo.cms.internal.http.HttpUtils;
import org.argeo.cms.internal.jcr.RepoConf;
import org.argeo.cms.internal.jcr.RepositoryBuilder;
import org.argeo.util.LangUtils;
import org.osgi.framework.FrameworkUtil;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.http.NamespaceException;
+import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
+/** A {@link ManagedServiceFactory} creating or referencing JCR repositories. */
class RepositoryServiceFactory implements ManagedServiceFactory {
private final static Log log = LogFactory.getLog(RepositoryServiceFactory.class);
private final BundleContext bc = FrameworkUtil.getBundle(RepositoryServiceFactory.class).getBundleContext();
// home
if (cn.equals(NodeConstants.NODE_REPOSITORY)) {
- Dictionary<String, Object> homeProps = LangUtils.dico(NodeConstants.CN, NodeConstants.EGO_REPOSITORY);
+ Dictionary<String, Object> homeProps = LangUtils.dico(NodeConstants.CN,
+ NodeConstants.EGO_REPOSITORY);
EgoRepository homeRepository = new EgoRepository(repository, true);
bc.registerService(Repository.class, homeRepository, homeProps);
}
}
}
}
+
}