</dependency>
<!-- Argeo Commons -->
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.cms.servlet</artifactId>
+ <version>2.3-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.argeo.commons</groupId>
<artifactId>org.argeo.cms.jcr</artifactId>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.cms.servlet</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.argeo.cms.pkgServlet">
+ <implementation class="org.argeo.cms.internal.http.PkgServlet"/>
+ <service>
+ <provide interface="javax.servlet.Servlet"/>
+ </service>
+ <property name="osgi.http.whiteboard.servlet.pattern" type="String" value="/*"/>
+ <property name="osgi.http.whiteboard.context.select" type="String" value="(osgi.http.whiteboard.context.name=pkgServletContext)"/>
+</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.pkgServletContext">
+ <implementation class="org.argeo.cms.servlet.CmsServletContext"/>
+ <service>
+ <provide interface="org.osgi.service.http.context.ServletContextHelper"/>
+ </service>
+ <property name="osgi.http.whiteboard.context.name" type="String" value="pkgServletContext"/>
+ <property name="osgi.http.whiteboard.context.path" type="String" value="/pkg"/>
+</scr:component>
--- /dev/null
+Import-Package:\
+org.osgi.service.http;version=0.0.0,\
+org.osgi.service.http.whiteboard;version=0.0.0,\
+org.osgi.framework.namespace;version=0.0.0,\
+org.argeo.api,\
+*
+
+Service-Component:\
+OSGI-INF/pkgServletContext.xml,\
+OSGI-INF/pkgServlet.xml
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.argeo.commons</groupId>
+ <version>2.3-SNAPSHOT</version>
+ <artifactId>argeo-commons</artifactId>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>org.argeo.cms.servlet</artifactId>
+ <packaging>jar</packaging>
+ <name>CMS Servlet</name>
+ <description>CMS components depending on the Servlet APIs</description>
+ <dependencies>
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.cms</artifactId>
+ <version>2.3-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.servlet;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.PrivilegedAction;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+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.argeo.cms.servlet.internal.HttpUtils;
+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 session is not
+ * pre-authenticated.
+ */
+public class CmsServletContext extends ServletContextHelper {
+ private final static Log log = LogFactory.getLog(CmsServletContext.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(new ServletHttpRequest(request), new ServletHttpResponse(response)));
+ lc.login();
+ } catch (LoginException e) {
+ lc = processUnauthorized(request, response);
+ if (log.isTraceEnabled())
+ HttpUtils.logResponseHeaders(log, response);
+ if (lc == null)
+ return false;
+ }
+
+ Subject subject = lc.getSubject();
+ // log.debug("SERVLET CONTEXT: "+subject);
+ Subject.doAs(subject, new PrivilegedAction<Void>() {
+
+ @Override
+ public Void run() {
+ // TODO also set login context in order to log out ?
+ ServletAuthUtils.configureRequestSecurity(request);
+ return null;
+ }
+
+ });
+ return true;
+ }
+
+ @Override
+ public void finishSecurity(HttpServletRequest request, HttpServletResponse response) {
+ ServletAuthUtils.clearRequestSecurity(request);
+ }
+
+ protected LoginContext processUnauthorized(HttpServletRequest request, HttpServletResponse response) {
+ // anonymous
+ try {
+ LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS,
+ new HttpRequestCallbackHandler(new ServletHttpRequest(request), new ServletHttpResponse(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);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.servlet;
+
+import javax.security.auth.login.LoginContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.argeo.cms.auth.SpnegoLoginModule;
+import org.argeo.cms.servlet.internal.HttpUtils;
+
+/** Servlet context forcing authentication. */
+public class PrivateWwwAuthServletContext extends CmsServletContext {
+ // TODO make it configurable
+ private final String httpAuthRealm = "Argeo";
+ private final boolean forceBasic = false;
+
+ @Override
+ protected LoginContext processUnauthorized(HttpServletRequest request, HttpServletResponse response) {
+ askForWwwAuth(request, response);
+ return null;
+ }
+
+ protected void askForWwwAuth(HttpServletRequest request, HttpServletResponse response) {
+ // response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "basic
+ // realm=\"" + httpAuthRealm + "\"");
+ if (SpnegoLoginModule.hasAcceptorCredentials() && !forceBasic)// SPNEGO
+ response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "Negotiate");
+ else
+ response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "Basic realm=\"" + httpAuthRealm + "\"");
+
+ // response.setDateHeader("Date", System.currentTimeMillis());
+ // response.setDateHeader("Expires", System.currentTimeMillis() + (24 *
+ // 60 * 60 * 1000));
+ // response.setHeader("Accept-Ranges", "bytes");
+ // response.setHeader("Connection", "Keep-Alive");
+ // response.setHeader("Keep-Alive", "timeout=5, max=97");
+ // response.setContentType("text/html; charset=UTF-8");
+ response.setStatus(401);
+ }
+}
--- /dev/null
+package org.argeo.cms.servlet;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.function.Supplier;
+
+import javax.security.auth.Subject;
+import javax.servlet.http.HttpServletRequest;
+
+import org.argeo.api.cms.CmsSession;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.osgi.CmsOsgiUtils;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.service.http.HttpContext;
+
+/** Authentications utilities when using servlets. */
+public class ServletAuthUtils {
+ private static BundleContext bundleContext = FrameworkUtil.getBundle(ServletAuthUtils.class).getBundleContext();
+
+ /**
+ * Execute this supplier, using the CMS class loader as context classloader.
+ * Useful to log in to JCR.
+ */
+ public final static <T> T doAs(Supplier<T> supplier, HttpServletRequest req) {
+ ClassLoader currentContextCl = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(ServletAuthUtils.class.getClassLoader());
+ try {
+ return Subject.doAs(
+ Subject.getSubject((AccessControlContext) req.getAttribute(AccessControlContext.class.getName())),
+ new PrivilegedAction<T>() {
+
+ @Override
+ public T run() {
+ return supplier.get();
+ }
+
+ });
+ } finally {
+ Thread.currentThread().setContextClassLoader(currentContextCl);
+ }
+ }
+
+ public final static void configureRequestSecurity(HttpServletRequest req) {
+ if (req.getAttribute(AccessControlContext.class.getName()) != null)
+ throw new IllegalStateException("Request already authenticated.");
+ AccessControlContext acc = AccessController.getContext();
+ req.setAttribute(HttpContext.REMOTE_USER, CurrentUser.getUsername());
+ req.setAttribute(AccessControlContext.class.getName(), acc);
+ }
+
+ public final static void clearRequestSecurity(HttpServletRequest req) {
+ if (req.getAttribute(AccessControlContext.class.getName()) == null)
+ throw new IllegalStateException("Cannot clear non-authenticated request.");
+ req.setAttribute(HttpContext.REMOTE_USER, null);
+ req.setAttribute(AccessControlContext.class.getName(), null);
+ }
+
+ public static CmsSession getCmsSession(HttpServletRequest req) {
+ Subject subject = Subject
+ .getSubject((AccessControlContext) req.getAttribute(AccessControlContext.class.getName()));
+ CmsSession cmsSession = CmsOsgiUtils.getCmsSession(bundleContext, subject);
+ return cmsSession;
+ }
+}
--- /dev/null
+package org.argeo.cms.servlet;
+
+import java.util.Locale;
+import java.util.Objects;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.argeo.cms.auth.HttpRequest;
+import org.argeo.cms.auth.HttpSession;
+
+public class ServletHttpRequest implements HttpRequest {
+ private final HttpServletRequest request;
+
+ public ServletHttpRequest(HttpServletRequest request) {
+ Objects.requireNonNull(request);
+ this.request = request;
+ }
+
+ @Override
+ public HttpSession getSession() {
+ return new ServletHttpSession();
+ }
+
+ @Override
+ public HttpSession createSession() {
+ request.getSession(true);
+ return new ServletHttpSession();
+ }
+
+ @Override
+ public Locale getLocale() {
+ return request.getLocale();
+ }
+
+ @Override
+ public Object getAttribute(String key) {
+ return request.getAttribute(key);
+ }
+
+ @Override
+ public void setAttribute(String key, Object object) {
+ request.setAttribute(key, object);
+ }
+
+ @Override
+ public String getHeader(String key) {
+ return request.getHeader(key);
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ return request.getRemoteAddr();
+ }
+
+ @Override
+ public int getLocalPort() {
+ return request.getLocalPort();
+ }
+
+ @Override
+ public int getRemotePort() {
+ return request.getRemotePort();
+ }
+
+ private class ServletHttpSession implements HttpSession {
+
+ @Override
+ public boolean isValid() {
+ try {// test http session
+ request.getSession(false).getCreationTime();
+ return true;
+ } catch (IllegalStateException ise) {
+ return false;
+ }
+ }
+
+ @Override
+ public String getId() {
+ return request.getSession(false).getId();
+ }
+
+ }
+}
--- /dev/null
+package org.argeo.cms.servlet;
+
+import java.util.Objects;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.argeo.cms.auth.HttpResponse;
+
+public class ServletHttpResponse implements HttpResponse {
+ private final HttpServletResponse response;
+
+ public ServletHttpResponse(HttpServletResponse response) {
+ Objects.requireNonNull(response);
+ this.response = response;
+ }
+
+ @Override
+ public void setHeader(String keys, String value) {
+ response.setHeader(keys, value);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.servlet.internal;
+
+import java.util.Enumeration;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+
+public class HttpUtils {
+ public final static String HEADER_AUTHORIZATION = "Authorization";
+ public final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
+
+ static boolean isBrowser(String userAgent) {
+ return userAgent.contains("webkit") || userAgent.contains("gecko") || userAgent.contains("firefox")
+ || userAgent.contains("msie") || userAgent.contains("chrome") || userAgent.contains("chromium")
+ || userAgent.contains("opera") || userAgent.contains("browser");
+ }
+
+ public static void logResponseHeaders(Log log, HttpServletResponse response) {
+ if (!log.isDebugEnabled())
+ return;
+ for (String headerName : response.getHeaderNames()) {
+ Object headerValue = response.getHeader(headerName);
+ log.debug(headerName + ": " + headerValue);
+ }
+ }
+
+ public static void logRequestHeaders(Log log, HttpServletRequest request) {
+ if (!log.isDebugEnabled())
+ return;
+ for (Enumeration<String> headerNames = request.getHeaderNames(); headerNames.hasMoreElements();) {
+ String headerName = headerNames.nextElement();
+ Object headerValue = request.getHeader(headerName);
+ log.debug(headerName + ": " + headerValue);
+ }
+ log.debug(request.getRequestURI() + "\n");
+ }
+
+ public static void logRequest(Log log, HttpServletRequest request) {
+ log.debug("contextPath=" + request.getContextPath());
+ log.debug("servletPath=" + request.getServletPath());
+ log.debug("requestURI=" + request.getRequestURI());
+ log.debug("queryString=" + request.getQueryString());
+ StringBuilder buf = new StringBuilder();
+ // headers
+ Enumeration<String> en = request.getHeaderNames();
+ while (en.hasMoreElements()) {
+ String header = en.nextElement();
+ Enumeration<String> values = request.getHeaders(header);
+ while (values.hasMoreElements())
+ buf.append(" " + header + ": " + values.nextElement());
+ buf.append('\n');
+ }
+
+ // attributed
+ Enumeration<String> an = request.getAttributeNames();
+ while (an.hasMoreElements()) {
+ String attr = an.nextElement();
+ Object value = request.getAttribute(attr);
+ buf.append(" " + attr + ": " + value);
+ buf.append('\n');
+ }
+ log.debug("\n" + buf);
+ }
+
+ private HttpUtils() {
+
+ }
+}
--- /dev/null
+package org.argeo.cms.servlet.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collection;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.cms.osgi.PublishNamespace;
+import org.argeo.osgi.util.FilterRequirement;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.Version;
+import org.osgi.framework.VersionRange;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.framework.wiring.FrameworkWiring;
+import org.osgi.resource.Requirement;
+
+public class PkgServlet extends HttpServlet {
+ private static final long serialVersionUID = 7660824185145214324L;
+
+ private BundleContext bundleContext = FrameworkUtil.getBundle(PkgServlet.class).getBundleContext();
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String pathInfo = req.getPathInfo();
+
+ String pkg, versionStr, file;
+ String[] parts = pathInfo.split("/");
+ // first is always empty
+ if (parts.length == 4) {
+ pkg = parts[1];
+ versionStr = parts[2];
+ file = parts[3];
+ } else if (parts.length == 3) {
+ pkg = parts[1];
+ versionStr = null;
+ file = parts[2];
+ } else {
+ throw new IllegalArgumentException("Unsupported path length " + pathInfo);
+ }
+
+ FrameworkWiring frameworkWiring = bundleContext.getBundle(0).adapt(FrameworkWiring.class);
+ String filter;
+ if (versionStr == null) {
+ filter = "(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + pkg + ")";
+ } else {
+ if (versionStr.startsWith("[") || versionStr.startsWith("(")) {// range
+ VersionRange versionRange = new VersionRange(versionStr);
+ filter = "(&(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + pkg + ")"
+ + versionRange.toFilterString(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE) + ")";
+
+ } else {
+ Version version = new Version(versionStr);
+ filter = "(&(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + pkg + ")("
+ + PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE + "=" + version + "))";
+ }
+ }
+ Requirement requirement = new FilterRequirement(PackageNamespace.PACKAGE_NAMESPACE, filter);
+ Collection<BundleCapability> packages = frameworkWiring.findProviders(requirement);
+ if (packages.isEmpty()) {
+ resp.sendError(404);
+ return;
+ }
+
+ // TODO verify that it works with multiple versions
+ SortedMap<Version, BundleCapability> sorted = new TreeMap<>();
+ for (BundleCapability capability : packages) {
+ sorted.put(capability.getRevision().getVersion(), capability);
+ }
+
+ Bundle bundle = sorted.get(sorted.firstKey()).getRevision().getBundle();
+ String entryPath = '/' + pkg.replace('.', '/') + '/' + file;
+ URL internalURL = bundle.getResource(entryPath);
+ if (internalURL == null) {
+ resp.sendError(404);
+ return;
+ }
+
+ // Resource found, we now check whether it can be published
+ boolean publish = false;
+ BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
+ capabilities: for (BundleCapability bundleCapability : bundleWiring
+ .getCapabilities(PublishNamespace.CMS_PUBLISH_NAMESPACE)) {
+ Object publishedPkg = bundleCapability.getAttributes().get(PublishNamespace.PKG);
+ if (publishedPkg != null) {
+ if (publishedPkg.equals("*") || publishedPkg.equals(pkg)) {
+ Object publishedFile = bundleCapability.getAttributes().get(PublishNamespace.FILE);
+ if (publishedFile == null) {
+ publish = true;
+ break capabilities;
+ } else {
+ String[] publishedFiles = publishedFile.toString().split(",");
+ for (String pattern : publishedFiles) {
+ if (pattern.startsWith("*.")) {
+ String ext = pattern.substring(1);
+ if (file.endsWith(ext)) {
+ publish = true;
+ break capabilities;
+ }
+ } else {
+ if (publishedFile.equals(file)) {
+ publish = true;
+ break capabilities;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!publish) {
+ resp.sendError(404);
+ return;
+ }
+
+ try (InputStream in = internalURL.openStream()) {
+ IOUtils.copy(in, resp.getOutputStream());
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.cms.servlet.internal;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class RobotServlet extends HttpServlet {
+ private static final long serialVersionUID = 7935661175336419089L;
+
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ PrintWriter writer = response.getWriter();
+ writer.append("User-agent: *\n");
+ writer.append("Disallow:\n");
+ response.setHeader("Content-Type", "text/plain");
+ writer.flush();
+ }
+
+}
<artifactId>org.argeo.cms</artifactId>
<version>2.3-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.cms.servlet</artifactId>
+ <version>2.3-SNAPSHOT</version>
+ </dependency>
<!-- Specific -->
<dependency>
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
-import javax.servlet.http.HttpServletRequest;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsMsg;
import org.argeo.cms.LocaleUtils;
import org.argeo.cms.auth.HttpRequestCallback;
+import org.argeo.cms.servlet.ServletHttpRequest;
+import org.argeo.cms.servlet.ServletHttpResponse;
import org.argeo.cms.swt.CmsStyles;
import org.argeo.cms.swt.CmsSwtUtils;
import org.argeo.eclipse.ui.specific.UiContext;
else if (callback instanceof PasswordCallback && passwordT != null)
((PasswordCallback) callback).setPassword(passwordT.getTextChars());
else if (callback instanceof HttpRequestCallback) {
- ((HttpRequestCallback) callback).setRequest(UiContext.getHttpRequest());
- ((HttpRequestCallback) callback).setResponse(UiContext.getHttpResponse());
+ ((HttpRequestCallback) callback).setRequest(new ServletHttpRequest(UiContext.getHttpRequest()));
+ ((HttpRequestCallback) callback).setResponse(new ServletHttpResponse(UiContext.getHttpResponse()));
} else if (callback instanceof LanguageCallback) {
Locale toUse = null;
if (localeChoice != null)
import org.argeo.cms.auth.CurrentUser;
import org.argeo.cms.auth.HttpRequestCallback;
import org.argeo.cms.auth.HttpRequestCallbackHandler;
+import org.argeo.cms.servlet.ServletHttpRequest;
+import org.argeo.cms.servlet.ServletHttpResponse;
import org.argeo.cms.swt.CmsStyles;
import org.argeo.cms.swt.CmsSwtUtils;
import org.argeo.eclipse.ui.specific.UiContext;
LoginContext lc;
try {
lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
- new HttpRequestCallbackHandler(UiContext.getHttpRequest(), UiContext.getHttpResponse()));
+ new HttpRequestCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
+ new ServletHttpResponse(UiContext.getHttpResponse())));
lc.login();
} catch (LoginException e) {
try {
// handle HTTP context
for (Callback callback : callbacks) {
if (callback instanceof HttpRequestCallback) {
- ((HttpRequestCallback) callback).setRequest(UiContext.getHttpRequest());
- ((HttpRequestCallback) callback).setResponse(UiContext.getHttpResponse());
+ ((HttpRequestCallback) callback)
+ .setRequest(new ServletHttpRequest(UiContext.getHttpRequest()));
+ ((HttpRequestCallback) callback)
+ .setResponse(new ServletHttpResponse(UiContext.getHttpResponse()));
}
}
}
import org.argeo.cms.auth.CurrentUser;
import org.argeo.cms.auth.HttpRequestCallbackHandler;
import org.argeo.cms.osgi.CmsOsgiUtils;
+import org.argeo.cms.servlet.ServletHttpRequest;
+import org.argeo.cms.servlet.ServletHttpResponse;
import org.argeo.cms.swt.CmsSwtUtils;
import org.argeo.cms.swt.SimpleSwtUxContext;
import org.argeo.cms.swt.dialogs.CmsFeedback;
LoginContext lc;
try {
lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
- new HttpRequestCallbackHandler(UiContext.getHttpRequest(), UiContext.getHttpResponse()));
+ new HttpRequestCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
+ new ServletHttpResponse(UiContext.getHttpResponse())));
lc.login();
} catch (LoginException e) {
try {
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.argeo.cms.pkgServlet">
- <implementation class="org.argeo.cms.internal.http.PkgServlet"/>
- <service>
- <provide interface="javax.servlet.Servlet"/>
- </service>
- <property name="osgi.http.whiteboard.servlet.pattern" type="String" value="/*"/>
- <property name="osgi.http.whiteboard.context.select" type="String" value="(osgi.http.whiteboard.context.name=pkgServletContext)"/>
-</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.pkgServletContext">
- <implementation class="org.argeo.cms.servlet.CmsServletContext"/>
- <service>
- <provide interface="org.osgi.service.http.context.ServletContextHelper"/>
- </service>
- <property name="osgi.http.whiteboard.context.name" type="String" value="pkgServletContext"/>
- <property name="osgi.http.whiteboard.context.path" type="String" value="/pkg"/>
-</scr:component>
Import-Package: org.apache.commons.httpclient.cookie;resolution:=optional,\
!com.sun.security.jgss,\
org.osgi.*;version=0.0.0,\
-org.osgi.service.http.whiteboard;version=0.0.0,\
-org.osgi.framework.namespace;version=0.0.0,\
-org.apache.log4j.*;resolution:=optional,\
*
-Service-Component:\
-OSGI-INF/cmsUserManager.xml,\
-OSGI-INF/pkgServletContext.xml,\
-OSGI-INF/pkgServlet.xml
+#Service-Component:\
+#OSGI-INF/cmsUserManager.xml,\
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
-import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public boolean commit() throws LoginException {
UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class));
Authorization authorization = userAdmin.getAuthorization(null);
- HttpServletRequest request = (HttpServletRequest) sharedState.get(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST);
+ HttpRequest request = (HttpRequest) sharedState.get(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST);
Locale locale = Locale.getDefault();
if (request != null)
locale = request.getLocale();
import javax.naming.ldap.LdapName;
import javax.security.auth.Subject;
import javax.security.auth.x500.X500Principal;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
import org.argeo.api.NodeConstants;
import org.argeo.api.cms.CmsSession;
}
@SuppressWarnings("unused")
- synchronized static void registerSessionAuthorization(HttpServletRequest request, Subject subject,
+ synchronized static void registerSessionAuthorization(HttpRequest request, Subject subject,
Authorization authorization, Locale locale) {
// synchronized in order to avoid multiple registrations
// TODO move it to a service in order to avoid static synchronization
if (request != null) {
- HttpSession httpSession = request.getSession(false);
+ HttpSession httpSession = request.getSession();
assert httpSession != null;
String httpSessId = httpSession.getId();
boolean anonymous = authorization.getName() == null;
--- /dev/null
+package org.argeo.cms.auth;
+
+import java.util.Locale;
+
+/** Transitional interface to decouple from the Servlet API. */
+public interface HttpRequest {
+ HttpSession getSession();
+
+ HttpSession createSession();
+
+ Locale getLocale();
+
+ Object getAttribute(String key);
+
+ void setAttribute(String key, Object object);
+
+ String getHeader(String key);
+
+ String getRemoteAddr();
+
+ int getLocalPort();
+
+ int getRemotePort();
+
+}
package org.argeo.cms.auth;
import javax.security.auth.callback.Callback;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
/** Retrieves credentials from an HTTP request. */
public class HttpRequestCallback implements Callback {
- private HttpServletRequest request;
- private HttpServletResponse response;
+ private HttpRequest request;
+ private HttpResponse response;
private HttpSession httpSession;
- public HttpServletRequest getRequest() {
+ public HttpRequest getRequest() {
return request;
}
- public void setRequest(HttpServletRequest request) {
+ public void setRequest(HttpRequest request) {
this.request = request;
}
- public HttpServletResponse getResponse() {
+ public HttpResponse getResponse() {
return response;
}
- public void setResponse(HttpServletResponse response) {
+ public void setResponse(HttpResponse response) {
this.response = response;
}
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.LanguageCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
/**
* Callback handler populating {@link HttpRequestCallback}s with the provided
* {@link HttpServletRequest}, and ignoring any other callback.
*/
public class HttpRequestCallbackHandler implements CallbackHandler {
- final private HttpServletRequest request;
- final private HttpServletResponse response;
+ final private HttpRequest request;
+ final private HttpResponse response;
final private HttpSession httpSession;
- public HttpRequestCallbackHandler(HttpServletRequest request, HttpServletResponse response) {
+ public HttpRequestCallbackHandler(HttpRequest request, HttpResponse response) {
this.request = request;
- this.httpSession = request.getSession(false);
+ this.httpSession = request.getSession();
this.response = response;
}
--- /dev/null
+package org.argeo.cms.auth;
+
+/** Transitional interface to decouple from the Servlet API. */
+public interface HttpResponse {
+ void setHeader(String keys, String value);
+
+}
--- /dev/null
+package org.argeo.cms.auth;
+
+/** Transitional interface to decouple from the Servlet API. */
+public interface HttpSession {
+ boolean isValid();
+
+ String getId();
+}
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
private CallbackHandler callbackHandler = null;
private Map<String, Object> sharedState = null;
- private HttpServletRequest request = null;
- private HttpServletResponse response = null;
+ private HttpRequest request = null;
+ private HttpResponse response = null;
private BundleContext bc;
return false;
// TODO factorize with below
String httpSessionId = httpSession.getId();
- if (log.isTraceEnabled())
- log.trace("HTTP login: " + request.getPathInfo() + " #" + httpSessionId);
+// if (log.isTraceEnabled())
+// log.trace("HTTP login: " + request.getPathInfo() + " #" + httpSessionId);
CmsSessionImpl cmsSession = CmsAuthUtils.cmsSessionFromHttpSession(bc, httpSessionId);
if (cmsSession != null) {
authorization = cmsSession.getAuthorization();
} else {
authorization = (Authorization) request.getAttribute(HttpContext.AUTHORIZATION);
if (authorization == null) {// search by session ID
- HttpSession httpSession = request.getSession(false);
+ HttpSession httpSession = request.getSession();
if (httpSession == null) {
// TODO make sure this is always safe
if (log.isTraceEnabled())
log.trace("Create http session");
- httpSession = request.getSession(true);
+ httpSession = request.createSession();
}
String httpSessionId = httpSession.getId();
- if (log.isTraceEnabled())
- log.trace("HTTP login: " + request.getPathInfo() + " #" + httpSessionId);
+// if (log.isTraceEnabled())
+// log.trace("HTTP login: " + request.getPathInfo() + " #" + httpSessionId);
CmsSessionImpl cmsSession = CmsAuthUtils.cmsSessionFromHttpSession(bc, httpSessionId);
if (cmsSession != null) {
authorization = cmsSession.getAuthorization();
return true;
}
- private void extractHttpAuth(final HttpServletRequest httpRequest) {
+ private void extractHttpAuth(final HttpRequest httpRequest) {
String authHeader = httpRequest.getHeader(CmsAuthUtils.HEADER_AUTHORIZATION);
extractHttpAuth(authHeader);
}
// }
}
- private void extractClientCertificate(HttpServletRequest req) {
+ private void extractClientCertificate(HttpRequest req) {
X509Certificate[] certs = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
if (null != certs && certs.length > 0) {// Servlet container verified the client certificate
String certDn = certs[0].getSubjectX500Principal().getName();
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
-import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
} catch (UnsupportedCallbackException e) {
return false;
}
- HttpServletRequest request = httpCallback.getRequest();
+ HttpRequest request = httpCallback.getRequest();
if (request == null)
return false;
IdentClient identClient = Activator.getIdentClient(request.getRemoteAddr());
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import javax.security.auth.x500.X500Principal;
-import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
authorizationName = principal.getName();
}
- HttpServletRequest request = (HttpServletRequest) sharedState.get(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST);
+ HttpRequest request = (HttpRequest) sharedState.get(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST);
Locale locale = Locale.getDefault();
if (request != null)
locale = request.getLocale();
return null;
}
+
+ public static boolean hasAcceptorCredentials() {
+ return Activator.getAcceptorCredentials() != null;
+ }
}
import javax.security.auth.login.CredentialNotFoundException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
-import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
}
// Log and monitor new login
- HttpServletRequest request = (HttpServletRequest) sharedState.get(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST);
+ HttpRequest request = (HttpRequest) sharedState.get(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST);
CmsAuthUtils.addAuthorization(subject, authorization);
// Unlock keyring (underlying login to the JCR repository)
// private Map<String, String> serviceProperties;
private WorkTransaction userTransaction;
- private Map<UserDirectory, Hashtable<String, String>> userDirectories = Collections
+ private Map<UserDirectory, Hashtable<String, Object>> userDirectories = Collections
.synchronizedMap(new LinkedHashMap<>());
@Override
this.userTransaction = userTransaction;
}
- public void addUserDirectory(UserDirectory userDirectory, Map<String, String> properties) {
+ public void addUserDirectory(UserDirectory userDirectory, Map<String, Object> properties) {
userDirectories.put(userDirectory, new Hashtable<>(properties));
}
- public void removeUserDirectory(UserDirectory userDirectory, Map<String, String> properties) {
+ public void removeUserDirectory(UserDirectory userDirectory, Map<String, Object> properties) {
userDirectories.remove(userDirectory);
}
+++ /dev/null
-package org.argeo.cms.internal.http;
-
-import java.util.Enumeration;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.logging.Log;
-
-public class HttpUtils {
- public final static String HEADER_AUTHORIZATION = "Authorization";
- public final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
-
- static boolean isBrowser(String userAgent) {
- return userAgent.contains("webkit") || userAgent.contains("gecko") || userAgent.contains("firefox")
- || userAgent.contains("msie") || userAgent.contains("chrome") || userAgent.contains("chromium")
- || userAgent.contains("opera") || userAgent.contains("browser");
- }
-
- public static void logResponseHeaders(Log log, HttpServletResponse response) {
- if (!log.isDebugEnabled())
- return;
- for (String headerName : response.getHeaderNames()) {
- Object headerValue = response.getHeader(headerName);
- log.debug(headerName + ": " + headerValue);
- }
- }
-
- public static void logRequestHeaders(Log log, HttpServletRequest request) {
- if (!log.isDebugEnabled())
- return;
- for (Enumeration<String> headerNames = request.getHeaderNames(); headerNames.hasMoreElements();) {
- String headerName = headerNames.nextElement();
- Object headerValue = request.getHeader(headerName);
- log.debug(headerName + ": " + headerValue);
- }
- log.debug(request.getRequestURI() + "\n");
- }
-
- public static void logRequest(Log log, HttpServletRequest request) {
- log.debug("contextPath=" + request.getContextPath());
- log.debug("servletPath=" + request.getServletPath());
- log.debug("requestURI=" + request.getRequestURI());
- log.debug("queryString=" + request.getQueryString());
- StringBuilder buf = new StringBuilder();
- // headers
- Enumeration<String> en = request.getHeaderNames();
- while (en.hasMoreElements()) {
- String header = en.nextElement();
- Enumeration<String> values = request.getHeaders(header);
- while (values.hasMoreElements())
- buf.append(" " + header + ": " + values.nextElement());
- buf.append('\n');
- }
-
- // attributed
- Enumeration<String> an = request.getAttributeNames();
- while (an.hasMoreElements()) {
- String attr = an.nextElement();
- Object value = request.getAttribute(attr);
- buf.append(" " + attr + ": " + value);
- buf.append('\n');
- }
- log.debug("\n" + buf);
- }
-
- private HttpUtils() {
-
- }
-}
+++ /dev/null
-package org.argeo.cms.internal.http;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Collection;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.cms.osgi.PublishNamespace;
-import org.argeo.osgi.util.FilterRequirement;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.Version;
-import org.osgi.framework.VersionRange;
-import org.osgi.framework.namespace.PackageNamespace;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleWiring;
-import org.osgi.framework.wiring.FrameworkWiring;
-import org.osgi.resource.Requirement;
-
-public class PkgServlet extends HttpServlet {
- private static final long serialVersionUID = 7660824185145214324L;
-
- private BundleContext bundleContext = FrameworkUtil.getBundle(PkgServlet.class).getBundleContext();
-
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- String pathInfo = req.getPathInfo();
-
- String pkg, versionStr, file;
- String[] parts = pathInfo.split("/");
- // first is always empty
- if (parts.length == 4) {
- pkg = parts[1];
- versionStr = parts[2];
- file = parts[3];
- } else if (parts.length == 3) {
- pkg = parts[1];
- versionStr = null;
- file = parts[2];
- } else {
- throw new IllegalArgumentException("Unsupported path length " + pathInfo);
- }
-
- FrameworkWiring frameworkWiring = bundleContext.getBundle(0).adapt(FrameworkWiring.class);
- String filter;
- if (versionStr == null) {
- filter = "(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + pkg + ")";
- } else {
- if (versionStr.startsWith("[") || versionStr.startsWith("(")) {// range
- VersionRange versionRange = new VersionRange(versionStr);
- filter = "(&(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + pkg + ")"
- + versionRange.toFilterString(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE) + ")";
-
- } else {
- Version version = new Version(versionStr);
- filter = "(&(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + pkg + ")("
- + PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE + "=" + version + "))";
- }
- }
- Requirement requirement = new FilterRequirement(PackageNamespace.PACKAGE_NAMESPACE, filter);
- Collection<BundleCapability> packages = frameworkWiring.findProviders(requirement);
- if (packages.isEmpty()) {
- resp.sendError(404);
- return;
- }
-
- // TODO verify that it works with multiple versions
- SortedMap<Version, BundleCapability> sorted = new TreeMap<>();
- for (BundleCapability capability : packages) {
- sorted.put(capability.getRevision().getVersion(), capability);
- }
-
- Bundle bundle = sorted.get(sorted.firstKey()).getRevision().getBundle();
- String entryPath = '/' + pkg.replace('.', '/') + '/' + file;
- URL internalURL = bundle.getResource(entryPath);
- if (internalURL == null) {
- resp.sendError(404);
- return;
- }
-
- // Resource found, we now check whether it can be published
- boolean publish = false;
- BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
- capabilities: for (BundleCapability bundleCapability : bundleWiring
- .getCapabilities(PublishNamespace.CMS_PUBLISH_NAMESPACE)) {
- Object publishedPkg = bundleCapability.getAttributes().get(PublishNamespace.PKG);
- if (publishedPkg != null) {
- if (publishedPkg.equals("*") || publishedPkg.equals(pkg)) {
- Object publishedFile = bundleCapability.getAttributes().get(PublishNamespace.FILE);
- if (publishedFile == null) {
- publish = true;
- break capabilities;
- } else {
- String[] publishedFiles = publishedFile.toString().split(",");
- for (String pattern : publishedFiles) {
- if (pattern.startsWith("*.")) {
- String ext = pattern.substring(1);
- if (file.endsWith(ext)) {
- publish = true;
- break capabilities;
- }
- } else {
- if (publishedFile.equals(file)) {
- publish = true;
- break capabilities;
- }
- }
- }
- }
- }
- }
- }
-
- if (!publish) {
- resp.sendError(404);
- return;
- }
-
- try (InputStream in = internalURL.openStream()) {
- IOUtils.copy(in, resp.getOutputStream());
- }
- }
-
-}
+++ /dev/null
-package org.argeo.cms.internal.http;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-public class RobotServlet extends HttpServlet {
- private static final long serialVersionUID = 7935661175336419089L;
-
- @Override
- protected void service(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- PrintWriter writer = response.getWriter();
- writer.append("User-agent: *\n");
- writer.append("Disallow:\n");
- response.setHeader("Content-Type", "text/plain");
- writer.flush();
- }
-
-}
import java.util.Locale;
import javax.security.auth.Subject;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
+import org.argeo.cms.auth.HttpRequest;
+import org.argeo.cms.auth.HttpSession;
import org.argeo.cms.internal.auth.CmsSessionImpl;
import org.osgi.service.useradmin.Authorization;
private HttpSession httpSession;
public WebCmsSessionImpl(Subject initialSubject, Authorization authorization, Locale locale,
- HttpServletRequest request) {
- super(initialSubject, authorization, locale, request.getSession(false).getId());
- httpSession = request.getSession(false);
+ HttpRequest request) {
+ super(initialSubject, authorization, locale, request.getSession().getId());
+ httpSession = request.getSession();
}
@Override
public boolean isValid() {
if (isClosed())
return false;
- try {// test http session
- httpSession.getCreationTime();
- return true;
- } catch (IllegalStateException ise) {
- return false;
- }
+ return httpSession.isValid();
}
- public static CmsSessionImpl getCmsSession(HttpServletRequest request) {
- return CmsSessionImpl.getByLocalId(request.getSession(false).getId());
+ public static CmsSessionImpl getCmsSession(HttpRequest request) {
+ return CmsSessionImpl.getByLocalId(request.getSession().getId());
}
}
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.api.NodeConstants;
+import org.argeo.cms.CmsUserManager;
+import org.argeo.cms.internal.auth.CmsUserManagerImpl;
import org.argeo.cms.internal.http.client.HttpCredentialProvider;
import org.argeo.cms.internal.http.client.SpnegoAuthScheme;
import org.argeo.naming.DnsBrowser;
import org.argeo.osgi.transaction.WorkControl;
+import org.argeo.osgi.transaction.WorkTransaction;
import org.argeo.osgi.useradmin.AbstractUserDirectory;
import org.argeo.osgi.useradmin.AggregatingUserAdmin;
import org.argeo.osgi.useradmin.LdapUserAdmin;
import org.ietf.jgss.Oid;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
import org.osgi.service.useradmin.Authorization;
private boolean singleUser = false;
// private boolean systemRolesAvailable = false;
+ CmsUserManagerImpl userManager;
+
public NodeUserAdmin(String systemRolesBaseDn, String tokensBaseDn) {
super(systemRolesBaseDn, tokensBaseDn);
BundleContext bc = Activator.getBundleContext();
if (bc != null) {
- tmTracker = new ServiceTracker<>(bc, WorkControl.class, null);
+ tmTracker = new ServiceTracker<>(bc, WorkControl.class, null) {
+
+ @Override
+ public WorkControl addingService(ServiceReference<WorkControl> reference) {
+ WorkControl workControl = super.addingService(reference);
+ userManager = new CmsUserManagerImpl();
+ userManager.setUserAdmin(NodeUserAdmin.this);
+ // FIXME make it more robust
+ userManager.setUserTransaction((WorkTransaction) workControl);
+ bc.registerService(CmsUserManager.class, userManager, null);
+ return workControl;
+ }
+ };
tmTracker.open();
} else {
tmTracker = null;
// OSGi
LdapName baseDn = userDirectory.getBaseDn();
- Dictionary<String, Object> regProps = new Hashtable<>();
+ Hashtable<String, Object> regProps = new Hashtable<>();
regProps.put(Constants.SERVICE_PID, pid);
if (isSystemRolesBaseDn(baseDn))
regProps.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE);
// ServiceRegistration<UserDirectory> reg =
// bc.registerService(UserDirectory.class, userDirectory, regProps);
Activator.registerService(UserDirectory.class, userDirectory, regProps);
+ userManager.addUserDirectory(userDirectory, regProps);
pidToBaseDn.put(pid, baseDn);
// pidToServiceRegs.put(pid, reg);
+++ /dev/null
-package org.argeo.cms.servlet;
-
-import java.io.IOException;
-import java.net.URL;
-import java.security.PrivilegedAction;
-import java.util.Map;
-
-import javax.security.auth.Subject;
-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.argeo.cms.internal.http.HttpUtils;
-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 session is not
- * pre-authenticated.
- */
-public class CmsServletContext extends ServletContextHelper {
- private final static Log log = LogFactory.getLog(CmsServletContext.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 (log.isTraceEnabled())
- HttpUtils.logResponseHeaders(log, response);
- if (lc == null)
- return false;
- }
-
- Subject subject = lc.getSubject();
- //log.debug("SERVLET CONTEXT: "+subject);
- Subject.doAs(subject, new PrivilegedAction<Void>() {
-
- @Override
- public Void run() {
- // TODO also set login context in order to log out ?
- ServletAuthUtils.configureRequestSecurity(request);
- return null;
- }
-
- });
- return true;
- }
-
- @Override
- public void finishSecurity(HttpServletRequest request, HttpServletResponse response) {
- ServletAuthUtils.clearRequestSecurity(request);
- }
-
- 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);
- }
-
-}
+++ /dev/null
-package org.argeo.cms.servlet;
-
-import javax.security.auth.login.LoginContext;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.argeo.cms.internal.http.HttpUtils;
-
-/** Servlet context forcing authentication. */
-public class PrivateWwwAuthServletContext extends CmsServletContext {
- // TODO make it configurable
- private final String httpAuthRealm = "Argeo";
- private final boolean forceBasic = false;
-
- @Override
- protected LoginContext processUnauthorized(HttpServletRequest request, HttpServletResponse response) {
- askForWwwAuth(request, response);
- return null;
- }
-
- protected void askForWwwAuth(HttpServletRequest request, HttpServletResponse response) {
- // response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "basic
- // realm=\"" + httpAuthRealm + "\"");
- if (org.argeo.cms.internal.kernel.Activator.getAcceptorCredentials() != null && !forceBasic)// SPNEGO
- response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "Negotiate");
- else
- response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "Basic realm=\"" + httpAuthRealm + "\"");
-
- // response.setDateHeader("Date", System.currentTimeMillis());
- // response.setDateHeader("Expires", System.currentTimeMillis() + (24 *
- // 60 * 60 * 1000));
- // response.setHeader("Accept-Ranges", "bytes");
- // response.setHeader("Connection", "Keep-Alive");
- // response.setHeader("Keep-Alive", "timeout=5, max=97");
- // response.setContentType("text/html; charset=UTF-8");
- response.setStatus(401);
- }
-}
+++ /dev/null
-package org.argeo.cms.servlet;
-
-import java.security.AccessControlContext;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.function.Supplier;
-
-import javax.security.auth.Subject;
-import javax.servlet.http.HttpServletRequest;
-
-import org.argeo.api.cms.CmsSession;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.osgi.CmsOsgiUtils;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.service.http.HttpContext;
-
-/** Authentications utilities when using servlets. */
-public class ServletAuthUtils {
- private static BundleContext bundleContext = FrameworkUtil.getBundle(ServletAuthUtils.class).getBundleContext();
-
- /**
- * Execute this supplier, using the CMS class loader as context classloader.
- * Useful to log in to JCR.
- */
- public final static <T> T doAs(Supplier<T> supplier, HttpServletRequest req) {
- ClassLoader currentContextCl = Thread.currentThread().getContextClassLoader();
- Thread.currentThread().setContextClassLoader(ServletAuthUtils.class.getClassLoader());
- try {
- return Subject.doAs(
- Subject.getSubject((AccessControlContext) req.getAttribute(AccessControlContext.class.getName())),
- new PrivilegedAction<T>() {
-
- @Override
- public T run() {
- return supplier.get();
- }
-
- });
- } finally {
- Thread.currentThread().setContextClassLoader(currentContextCl);
- }
- }
-
- public final static void configureRequestSecurity(HttpServletRequest req) {
- if (req.getAttribute(AccessControlContext.class.getName()) != null)
- throw new IllegalStateException("Request already authenticated.");
- AccessControlContext acc = AccessController.getContext();
- req.setAttribute(HttpContext.REMOTE_USER, CurrentUser.getUsername());
- req.setAttribute(AccessControlContext.class.getName(), acc);
- }
-
- public final static void clearRequestSecurity(HttpServletRequest req) {
- if (req.getAttribute(AccessControlContext.class.getName()) == null)
- throw new IllegalStateException("Cannot clear non-authenticated request.");
- req.setAttribute(HttpContext.REMOTE_USER, null);
- req.setAttribute(AccessControlContext.class.getName(), null);
- }
-
- public static CmsSession getCmsSession(HttpServletRequest req) {
- Subject subject = Subject
- .getSubject((AccessControlContext) req.getAttribute(AccessControlContext.class.getName()));
- CmsSession cmsSession = CmsOsgiUtils.getCmsSession(bundleContext, subject);
- return cmsSession;
- }
-}
<module>org.argeo.transition</module>
<!-- <module>org.argeo.maintenance</module> -->
<module>org.argeo.cms</module>
+ <module>org.argeo.cms.servlet</module>
<module>org.argeo.cms.swt</module>
<module>org.argeo.cms.jcr</module>
<!-- <module>org.argeo.cms.ui.theme</module> -->