From 7064547ae5d85225546f1b8f15d6b5c82f30fe22 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Sat, 1 Jan 2022 09:58:34 +0100 Subject: [PATCH] Introduce CMS Servlet. --- dep/org.argeo.dep.cms.node/pom.xml | 5 ++ org.argeo.cms.servlet/.classpath | 7 ++ org.argeo.cms.servlet/.project | 28 +++++++ .../OSGI-INF/pkgServlet.xml | 0 .../OSGI-INF/pkgServletContext.xml | 0 org.argeo.cms.servlet/bnd.bnd | 10 +++ org.argeo.cms.servlet/build.properties | 4 + org.argeo.cms.servlet/pom.xml | 23 +++++ .../argeo/cms/servlet/CmsServletContext.java | 11 +-- .../servlet/PrivateWwwAuthServletContext.java | 7 +- .../argeo/cms/servlet/ServletAuthUtils.java | 0 .../argeo/cms/servlet/ServletHttpRequest.java | 83 +++++++++++++++++++ .../cms/servlet/ServletHttpResponse.java | 22 +++++ .../cms/servlet/internal}/HttpUtils.java | 2 +- .../cms/servlet/internal}/PkgServlet.java | 2 +- .../cms/servlet/internal}/RobotServlet.java | 2 +- org.argeo.cms.swt/pom.xml | 5 ++ .../src/org/argeo/cms/swt/auth/CmsLogin.java | 8 +- .../argeo/cms/web/AbstractCmsEntryPoint.java | 11 ++- .../org/argeo/cms/web/CmsWebEntryPoint.java | 5 +- org.argeo.cms/bnd.bnd | 9 +- .../argeo/cms/auth/AnonymousLoginModule.java | 3 +- .../src/org/argeo/cms/auth/CmsAuthUtils.java | 6 +- .../src/org/argeo/cms/auth/HttpRequest.java | 25 ++++++ .../argeo/cms/auth/HttpRequestCallback.java | 15 ++-- .../cms/auth/HttpRequestCallbackHandler.java | 11 +-- .../src/org/argeo/cms/auth/HttpResponse.java | 7 ++ .../src/org/argeo/cms/auth/HttpSession.java | 8 ++ .../cms/auth/HttpSessionLoginModule.java | 23 +++-- .../org/argeo/cms/auth/IdentLoginModule.java | 3 +- .../argeo/cms/auth/SingleUserLoginModule.java | 3 +- .../org/argeo/cms/auth/SpnegoLoginModule.java | 4 + .../argeo/cms/auth/UserAdminLoginModule.java | 3 +- .../cms/internal/auth/CmsUserManagerImpl.java | 6 +- .../cms/internal/http/WebCmsSessionImpl.java | 21 ++--- .../cms/internal/kernel/NodeUserAdmin.java | 23 ++++- pom.xml | 1 + 37 files changed, 322 insertions(+), 84 deletions(-) create mode 100644 org.argeo.cms.servlet/.classpath create mode 100644 org.argeo.cms.servlet/.project rename {org.argeo.cms => org.argeo.cms.servlet}/OSGI-INF/pkgServlet.xml (100%) rename {org.argeo.cms => org.argeo.cms.servlet}/OSGI-INF/pkgServletContext.xml (100%) create mode 100644 org.argeo.cms.servlet/bnd.bnd create mode 100644 org.argeo.cms.servlet/build.properties create mode 100644 org.argeo.cms.servlet/pom.xml rename {org.argeo.cms => org.argeo.cms.servlet}/src/org/argeo/cms/servlet/CmsServletContext.java (86%) rename {org.argeo.cms => org.argeo.cms.servlet}/src/org/argeo/cms/servlet/PrivateWwwAuthServletContext.java (85%) rename {org.argeo.cms => org.argeo.cms.servlet}/src/org/argeo/cms/servlet/ServletAuthUtils.java (100%) create mode 100644 org.argeo.cms.servlet/src/org/argeo/cms/servlet/ServletHttpRequest.java create mode 100644 org.argeo.cms.servlet/src/org/argeo/cms/servlet/ServletHttpResponse.java rename {org.argeo.cms/src/org/argeo/cms/internal/http => org.argeo.cms.servlet/src/org/argeo/cms/servlet/internal}/HttpUtils.java (98%) rename {org.argeo.cms/src/org/argeo/cms/internal/http => org.argeo.cms.servlet/src/org/argeo/cms/servlet/internal}/PkgServlet.java (99%) rename {org.argeo.cms/src/org/argeo/cms/internal/http => org.argeo.cms.servlet/src/org/argeo/cms/servlet/internal}/RobotServlet.java (94%) create mode 100644 org.argeo.cms/src/org/argeo/cms/auth/HttpRequest.java create mode 100644 org.argeo.cms/src/org/argeo/cms/auth/HttpResponse.java create mode 100644 org.argeo.cms/src/org/argeo/cms/auth/HttpSession.java diff --git a/dep/org.argeo.dep.cms.node/pom.xml b/dep/org.argeo.dep.cms.node/pom.xml index 3348ecd70..7f1ca14ce 100644 --- a/dep/org.argeo.dep.cms.node/pom.xml +++ b/dep/org.argeo.dep.cms.node/pom.xml @@ -23,6 +23,11 @@ + + org.argeo.commons + org.argeo.cms.servlet + 2.3-SNAPSHOT + org.argeo.commons org.argeo.cms.jcr diff --git a/org.argeo.cms.servlet/.classpath b/org.argeo.cms.servlet/.classpath new file mode 100644 index 000000000..e801ebfb4 --- /dev/null +++ b/org.argeo.cms.servlet/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.argeo.cms.servlet/.project b/org.argeo.cms.servlet/.project new file mode 100644 index 000000000..b1a25fcc8 --- /dev/null +++ b/org.argeo.cms.servlet/.project @@ -0,0 +1,28 @@ + + + org.argeo.cms.servlet + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.argeo.cms/OSGI-INF/pkgServlet.xml b/org.argeo.cms.servlet/OSGI-INF/pkgServlet.xml similarity index 100% rename from org.argeo.cms/OSGI-INF/pkgServlet.xml rename to org.argeo.cms.servlet/OSGI-INF/pkgServlet.xml diff --git a/org.argeo.cms/OSGI-INF/pkgServletContext.xml b/org.argeo.cms.servlet/OSGI-INF/pkgServletContext.xml similarity index 100% rename from org.argeo.cms/OSGI-INF/pkgServletContext.xml rename to org.argeo.cms.servlet/OSGI-INF/pkgServletContext.xml diff --git a/org.argeo.cms.servlet/bnd.bnd b/org.argeo.cms.servlet/bnd.bnd new file mode 100644 index 000000000..c8251a7fe --- /dev/null +++ b/org.argeo.cms.servlet/bnd.bnd @@ -0,0 +1,10 @@ +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 diff --git a/org.argeo.cms.servlet/build.properties b/org.argeo.cms.servlet/build.properties new file mode 100644 index 000000000..34d2e4d2d --- /dev/null +++ b/org.argeo.cms.servlet/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.argeo.cms.servlet/pom.xml b/org.argeo.cms.servlet/pom.xml new file mode 100644 index 000000000..a60b42d04 --- /dev/null +++ b/org.argeo.cms.servlet/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + org.argeo.commons + 2.3-SNAPSHOT + argeo-commons + .. + + org.argeo.cms.servlet + jar + CMS Servlet + CMS components depending on the Servlet APIs + + + org.argeo.commons + org.argeo.cms + 2.3-SNAPSHOT + + + \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/servlet/CmsServletContext.java b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/CmsServletContext.java similarity index 86% rename from org.argeo.cms/src/org/argeo/cms/servlet/CmsServletContext.java rename to org.argeo.cms.servlet/src/org/argeo/cms/servlet/CmsServletContext.java index c88ee7f93..ff341a25a 100644 --- a/org.argeo.cms/src/org/argeo/cms/servlet/CmsServletContext.java +++ b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/CmsServletContext.java @@ -15,7 +15,7 @@ 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.argeo.cms.servlet.internal.HttpUtils; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; import org.osgi.service.http.context.ServletContextHelper; @@ -43,7 +43,8 @@ public class CmsServletContext extends ServletContextHelper { HttpUtils.logRequestHeaders(log, request); LoginContext lc; try { - lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request, response)); + lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, + new HttpRequestCallbackHandler(new ServletHttpRequest(request), new ServletHttpResponse(response))); lc.login(); } catch (LoginException e) { lc = processUnauthorized(request, response); @@ -52,9 +53,9 @@ public class CmsServletContext extends ServletContextHelper { if (lc == null) return false; } - + Subject subject = lc.getSubject(); - //log.debug("SERVLET CONTEXT: "+subject); + // log.debug("SERVLET CONTEXT: "+subject); Subject.doAs(subject, new PrivilegedAction() { @Override @@ -77,7 +78,7 @@ public class CmsServletContext extends ServletContextHelper { // anonymous try { LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS, - new HttpRequestCallbackHandler(request, response)); + new HttpRequestCallbackHandler(new ServletHttpRequest(request), new ServletHttpResponse(response))); lc.login(); return lc; } catch (LoginException e1) { diff --git a/org.argeo.cms/src/org/argeo/cms/servlet/PrivateWwwAuthServletContext.java b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/PrivateWwwAuthServletContext.java similarity index 85% rename from org.argeo.cms/src/org/argeo/cms/servlet/PrivateWwwAuthServletContext.java rename to org.argeo.cms.servlet/src/org/argeo/cms/servlet/PrivateWwwAuthServletContext.java index e4547507a..3bea0b4de 100644 --- a/org.argeo.cms/src/org/argeo/cms/servlet/PrivateWwwAuthServletContext.java +++ b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/PrivateWwwAuthServletContext.java @@ -4,7 +4,8 @@ import javax.security.auth.login.LoginContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.argeo.cms.internal.http.HttpUtils; +import org.argeo.cms.auth.SpnegoLoginModule; +import org.argeo.cms.servlet.internal.HttpUtils; /** Servlet context forcing authentication. */ public class PrivateWwwAuthServletContext extends CmsServletContext { @@ -21,7 +22,7 @@ public class PrivateWwwAuthServletContext extends CmsServletContext { 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 + if (SpnegoLoginModule.hasAcceptorCredentials() && !forceBasic)// SPNEGO response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "Negotiate"); else response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "Basic realm=\"" + httpAuthRealm + "\""); @@ -32,7 +33,7 @@ public class PrivateWwwAuthServletContext extends CmsServletContext { // 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.setContentType("text/html; charset=UTF-8"); response.setStatus(401); } } diff --git a/org.argeo.cms/src/org/argeo/cms/servlet/ServletAuthUtils.java b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/ServletAuthUtils.java similarity index 100% rename from org.argeo.cms/src/org/argeo/cms/servlet/ServletAuthUtils.java rename to org.argeo.cms.servlet/src/org/argeo/cms/servlet/ServletAuthUtils.java diff --git a/org.argeo.cms.servlet/src/org/argeo/cms/servlet/ServletHttpRequest.java b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/ServletHttpRequest.java new file mode 100644 index 000000000..523f7b757 --- /dev/null +++ b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/ServletHttpRequest.java @@ -0,0 +1,83 @@ +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(); + } + + } +} diff --git a/org.argeo.cms.servlet/src/org/argeo/cms/servlet/ServletHttpResponse.java b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/ServletHttpResponse.java new file mode 100644 index 000000000..6cbe2c44e --- /dev/null +++ b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/ServletHttpResponse.java @@ -0,0 +1,22 @@ +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); + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/http/HttpUtils.java b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/internal/HttpUtils.java similarity index 98% rename from org.argeo.cms/src/org/argeo/cms/internal/http/HttpUtils.java rename to org.argeo.cms.servlet/src/org/argeo/cms/servlet/internal/HttpUtils.java index b5d355387..5f8c8c560 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/http/HttpUtils.java +++ b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/internal/HttpUtils.java @@ -1,4 +1,4 @@ -package org.argeo.cms.internal.http; +package org.argeo.cms.servlet.internal; import java.util.Enumeration; diff --git a/org.argeo.cms/src/org/argeo/cms/internal/http/PkgServlet.java b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/internal/PkgServlet.java similarity index 99% rename from org.argeo.cms/src/org/argeo/cms/internal/http/PkgServlet.java rename to org.argeo.cms.servlet/src/org/argeo/cms/servlet/internal/PkgServlet.java index 26046b246..c762b67ec 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/http/PkgServlet.java +++ b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/internal/PkgServlet.java @@ -1,4 +1,4 @@ -package org.argeo.cms.internal.http; +package org.argeo.cms.servlet.internal; import java.io.IOException; import java.io.InputStream; diff --git a/org.argeo.cms/src/org/argeo/cms/internal/http/RobotServlet.java b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/internal/RobotServlet.java similarity index 94% rename from org.argeo.cms/src/org/argeo/cms/internal/http/RobotServlet.java rename to org.argeo.cms.servlet/src/org/argeo/cms/servlet/internal/RobotServlet.java index 6d3d302b7..288ee268c 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/http/RobotServlet.java +++ b/org.argeo.cms.servlet/src/org/argeo/cms/servlet/internal/RobotServlet.java @@ -1,4 +1,4 @@ -package org.argeo.cms.internal.http; +package org.argeo.cms.servlet.internal; import java.io.IOException; import java.io.PrintWriter; diff --git a/org.argeo.cms.swt/pom.xml b/org.argeo.cms.swt/pom.xml index c6e772c89..b969259e7 100644 --- a/org.argeo.cms.swt/pom.xml +++ b/org.argeo.cms.swt/pom.xml @@ -20,6 +20,11 @@ org.argeo.cms 2.3-SNAPSHOT + + org.argeo.commons + org.argeo.cms.servlet + 2.3-SNAPSHOT + diff --git a/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/CmsLogin.java b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/CmsLogin.java index 8e12a8986..e4d08d728 100644 --- a/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/CmsLogin.java +++ b/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/CmsLogin.java @@ -16,7 +16,7 @@ import javax.security.auth.callback.PasswordCallback; 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; @@ -25,6 +25,8 @@ import org.argeo.api.cms.CmsView; 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; @@ -309,8 +311,8 @@ public class CmsLogin implements CmsStyles, CallbackHandler { 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) diff --git a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/AbstractCmsEntryPoint.java b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/AbstractCmsEntryPoint.java index 504ed4978..c20068fa7 100644 --- a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/AbstractCmsEntryPoint.java +++ b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/AbstractCmsEntryPoint.java @@ -29,6 +29,8 @@ import org.argeo.cms.CmsException; 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; @@ -84,7 +86,8 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implement 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 { @@ -291,8 +294,10 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implement // 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())); } } } diff --git a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsWebEntryPoint.java b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsWebEntryPoint.java index 4bdc5a0aa..d7050e954 100644 --- a/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsWebEntryPoint.java +++ b/org.argeo.cms.ui.rap/src/org/argeo/cms/web/CmsWebEntryPoint.java @@ -25,6 +25,8 @@ import org.argeo.cms.LocaleUtils; 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; @@ -84,7 +86,8 @@ public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationL 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 { diff --git a/org.argeo.cms/bnd.bnd b/org.argeo.cms/bnd.bnd index dc2cca306..61cb6cbab 100644 --- a/org.argeo.cms/bnd.bnd +++ b/org.argeo.cms/bnd.bnd @@ -3,13 +3,8 @@ Bundle-Activator: org.argeo.cms.internal.kernel.Activator 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,\ diff --git a/org.argeo.cms/src/org/argeo/cms/auth/AnonymousLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/AnonymousLoginModule.java index 1d24be7ad..c5d067c08 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/AnonymousLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/AnonymousLoginModule.java @@ -7,7 +7,6 @@ import javax.security.auth.Subject; 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; @@ -49,7 +48,7 @@ public class AnonymousLoginModule implements LoginModule { 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(); diff --git a/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java b/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java index e854f5adf..62888b153 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java @@ -10,8 +10,6 @@ import javax.naming.InvalidNameException; 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; @@ -124,12 +122,12 @@ class CmsAuthUtils { } @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; diff --git a/org.argeo.cms/src/org/argeo/cms/auth/HttpRequest.java b/org.argeo.cms/src/org/argeo/cms/auth/HttpRequest.java new file mode 100644 index 000000000..447225515 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/auth/HttpRequest.java @@ -0,0 +1,25 @@ +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(); + +} diff --git a/org.argeo.cms/src/org/argeo/cms/auth/HttpRequestCallback.java b/org.argeo.cms/src/org/argeo/cms/auth/HttpRequestCallback.java index 920f04e34..38e12c0c6 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/HttpRequestCallback.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/HttpRequestCallback.java @@ -1,29 +1,26 @@ 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; } diff --git a/org.argeo.cms/src/org/argeo/cms/auth/HttpRequestCallbackHandler.java b/org.argeo.cms/src/org/argeo/cms/auth/HttpRequestCallbackHandler.java index df971e687..934fdd96b 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/HttpRequestCallbackHandler.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/HttpRequestCallbackHandler.java @@ -6,22 +6,19 @@ import javax.security.auth.callback.Callback; 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; } diff --git a/org.argeo.cms/src/org/argeo/cms/auth/HttpResponse.java b/org.argeo.cms/src/org/argeo/cms/auth/HttpResponse.java new file mode 100644 index 000000000..67bad55c4 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/auth/HttpResponse.java @@ -0,0 +1,7 @@ +package org.argeo.cms.auth; + +/** Transitional interface to decouple from the Servlet API. */ +public interface HttpResponse { + void setHeader(String keys, String value); + +} diff --git a/org.argeo.cms/src/org/argeo/cms/auth/HttpSession.java b/org.argeo.cms/src/org/argeo/cms/auth/HttpSession.java new file mode 100644 index 000000000..c7e52c128 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/auth/HttpSession.java @@ -0,0 +1,8 @@ +package org.argeo.cms.auth; + +/** Transitional interface to decouple from the Servlet API. */ +public interface HttpSession { + boolean isValid(); + + String getId(); +} diff --git a/org.argeo.cms/src/org/argeo/cms/auth/HttpSessionLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/HttpSessionLoginModule.java index c2dfead78..8cc3941bc 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/HttpSessionLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/HttpSessionLoginModule.java @@ -13,9 +13,6 @@ import javax.security.auth.callback.CallbackHandler; 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; @@ -34,8 +31,8 @@ public class HttpSessionLoginModule implements LoginModule { private CallbackHandler callbackHandler = null; private Map sharedState = null; - private HttpServletRequest request = null; - private HttpServletResponse response = null; + private HttpRequest request = null; + private HttpResponse response = null; private BundleContext bc; @@ -72,8 +69,8 @@ public class HttpSessionLoginModule implements LoginModule { 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(); @@ -84,16 +81,16 @@ public class HttpSessionLoginModule implements LoginModule { } 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(); @@ -159,7 +156,7 @@ public class HttpSessionLoginModule implements LoginModule { return true; } - private void extractHttpAuth(final HttpServletRequest httpRequest) { + private void extractHttpAuth(final HttpRequest httpRequest) { String authHeader = httpRequest.getHeader(CmsAuthUtils.HEADER_AUTHORIZATION); extractHttpAuth(authHeader); } @@ -206,7 +203,7 @@ public class HttpSessionLoginModule implements LoginModule { // } } - 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(); diff --git a/org.argeo.cms/src/org/argeo/cms/auth/IdentLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/IdentLoginModule.java index ec6b5a30c..f5e4085c3 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/IdentLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/IdentLoginModule.java @@ -9,7 +9,6 @@ import javax.security.auth.callback.CallbackHandler; 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; @@ -43,7 +42,7 @@ public class IdentLoginModule implements LoginModule { } catch (UnsupportedCallbackException e) { return false; } - HttpServletRequest request = httpCallback.getRequest(); + HttpRequest request = httpCallback.getRequest(); if (request == null) return false; IdentClient identClient = Activator.getIdentClient(request.getRemoteAddr()); diff --git a/org.argeo.cms/src/org/argeo/cms/auth/SingleUserLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/SingleUserLoginModule.java index 240564f9e..5d46839e0 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/SingleUserLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/SingleUserLoginModule.java @@ -12,7 +12,6 @@ import javax.security.auth.kerberos.KerberosPrincipal; 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; @@ -68,7 +67,7 @@ public class SingleUserLoginModule implements LoginModule { 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(); diff --git a/org.argeo.cms/src/org/argeo/cms/auth/SpnegoLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/SpnegoLoginModule.java index 27de54be3..568e2f6e0 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/SpnegoLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/SpnegoLoginModule.java @@ -132,4 +132,8 @@ public class SpnegoLoginModule implements LoginModule { return null; } + + public static boolean hasAcceptorCredentials() { + return Activator.getAcceptorCredentials() != null; + } } diff --git a/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java index 092a06b77..d526f4fc2 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java @@ -23,7 +23,6 @@ import javax.security.auth.kerberos.KerberosPrincipal; 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; @@ -253,7 +252,7 @@ public class UserAdminLoginModule implements LoginModule { } // 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) diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java index 5753decf9..5485fc5ee 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java @@ -62,7 +62,7 @@ public class CmsUserManagerImpl implements CmsUserManager { // private Map serviceProperties; private WorkTransaction userTransaction; - private Map> userDirectories = Collections + private Map> userDirectories = Collections .synchronizedMap(new LinkedHashMap<>()); @Override @@ -481,11 +481,11 @@ public class CmsUserManagerImpl implements CmsUserManager { this.userTransaction = userTransaction; } - public void addUserDirectory(UserDirectory userDirectory, Map properties) { + public void addUserDirectory(UserDirectory userDirectory, Map properties) { userDirectories.put(userDirectory, new Hashtable<>(properties)); } - public void removeUserDirectory(UserDirectory userDirectory, Map properties) { + public void removeUserDirectory(UserDirectory userDirectory, Map properties) { userDirectories.remove(userDirectory); } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/http/WebCmsSessionImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/http/WebCmsSessionImpl.java index ce8190518..03fb82faa 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/http/WebCmsSessionImpl.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/http/WebCmsSessionImpl.java @@ -3,9 +3,9 @@ package org.argeo.cms.internal.http; 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; @@ -15,24 +15,19 @@ public class WebCmsSessionImpl extends CmsSessionImpl { 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()); } } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java index 86c6c9c31..11efa9e0f 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java @@ -34,10 +34,13 @@ import org.apache.commons.httpclient.params.HttpParams; 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; @@ -52,6 +55,7 @@ import org.ietf.jgss.GSSName; 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; @@ -82,11 +86,25 @@ class NodeUserAdmin extends AggregatingUserAdmin implements ManagedServiceFactor 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 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; @@ -128,7 +146,7 @@ class NodeUserAdmin extends AggregatingUserAdmin implements ManagedServiceFactor // OSGi LdapName baseDn = userDirectory.getBaseDn(); - Dictionary regProps = new Hashtable<>(); + Hashtable regProps = new Hashtable<>(); regProps.put(Constants.SERVICE_PID, pid); if (isSystemRolesBaseDn(baseDn)) regProps.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE); @@ -136,6 +154,7 @@ class NodeUserAdmin extends AggregatingUserAdmin implements ManagedServiceFactor // ServiceRegistration 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); diff --git a/pom.xml b/pom.xml index bb8807177..123fb1c9c 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ org.argeo.transition org.argeo.cms + org.argeo.cms.servlet org.argeo.cms.swt org.argeo.cms.jcr -- 2.30.2