JDK HTTP server authentication
authorMathieu Baudier <mbaudier@argeo.org>
Sun, 17 Jul 2022 14:48:24 +0000 (16:48 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Sun, 17 Jul 2022 14:48:24 +0000 (16:48 +0200)
18 files changed:
org.argeo.api.cms/src/org/argeo/api/cms/CmsState.java
org.argeo.cms.ee/src/org/argeo/cms/servlet/httpserver/HttpContextServlet.java
org.argeo.cms.lib.equinox/OSGI-INF/jettyServiceFactory.xml
org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/CmsJettyServer.java
org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/JettyHttpContext.java
org.argeo.cms/OSGI-INF/cmsAcrHttpHandler.xml [new file with mode: 0644]
org.argeo.cms/OSGI-INF/cmsAuthenticator.xml [new file with mode: 0644]
org.argeo.cms/OSGI-INF/cmsDeployment.xml
org.argeo.cms/bnd.bnd
org.argeo.cms/build.properties
org.argeo.cms/src/org/argeo/cms/internal/http/CmsAuthenticator.java
org.argeo.cms/src/org/argeo/cms/internal/http/RemoteAuthHttpExchange.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsAcrHttpHandler.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsDeploymentImpl.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java
org.argeo.util/src/org/argeo/util/dav/DavServerHandler.java
org.argeo.util/src/org/argeo/util/http/HttpMethod.java [new file with mode: 0644]
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/maintenance/DeploymentEntryPoint.java

index 181e4b9c661f716424f0d183bf97514431680b51..9ffba68c12d1560a7447af92ee0b4d5e4319ba3c 100644 (file)
@@ -6,8 +6,6 @@ import java.util.UUID;
 
 /** A running node process. */
 public interface CmsState {
-       String getHostname();
-
        Long getAvailableSince();
 
        UUID getUuid();
index c81bad7bc59c049ac31a9577308f913fa2d7fa4b..b2f73944985e23210f267475f58193683b5829ad 100644 (file)
@@ -7,6 +7,9 @@ import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.argeo.cms.auth.RemoteAuthSession;
+import org.argeo.cms.servlet.ServletHttpSession;
+
 import com.sun.net.httpserver.Authenticator;
 import com.sun.net.httpserver.HttpContext;
 import com.sun.net.httpserver.HttpHandler;
@@ -24,6 +27,8 @@ public class HttpContextServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                try (ServletHttpExchange httpExchange = new ServletHttpExchange(httpContext, req, resp)) {
+                       ServletHttpSession httpSession = new ServletHttpSession(req.getSession());
+                       httpExchange.setAttribute(RemoteAuthSession.class.getName(), httpSession);
                        Authenticator authenticator = httpContext.getAuthenticator();
                        if (authenticator != null) {
                                Authenticator.Result authenticationResult = authenticator.authenticate(httpExchange);
@@ -31,10 +36,14 @@ public class HttpContextServlet extends HttpServlet {
                                        HttpPrincipal httpPrincipal = ((Authenticator.Success) authenticationResult).getPrincipal();
                                        httpExchange.setPrincipal(httpPrincipal);
                                } else if (authenticationResult instanceof Authenticator.Retry) {
-                                       resp.setStatus(((Authenticator.Retry) authenticationResult).getResponseCode());
+                                       httpExchange.sendResponseHeaders((((Authenticator.Retry) authenticationResult).getResponseCode()),
+                                                       -1);
+                                       resp.flushBuffer();
                                        return;
                                } else if (authenticationResult instanceof Authenticator.Failure) {
-                                       resp.setStatus(((Authenticator.Failure) authenticationResult).getResponseCode());
+                                       httpExchange.sendResponseHeaders(((Authenticator.Failure) authenticationResult).getResponseCode(),
+                                                       -1);
+                                       resp.flushBuffer();
                                        return;
                                } else {
                                        throw new UnsupportedOperationException(
@@ -46,5 +55,4 @@ public class HttpContextServlet extends HttpServlet {
                        httpHandler.handle(httpExchange);
                }
        }
-
 }
index 2eec733bc97f7f0e36f4e8c1f7e0a2397baa2fa9..e2c23f85df97a163b05af8fe8a1b0cdb9710857b 100644 (file)
@@ -3,4 +3,8 @@
    <implementation class="org.argeo.cms.equinox.http.jetty.EquinoxJettyServer"/>
    <property name="service.pid" type="String" value="org.argeo.equinox.jetty.config"/>
    <reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
+   <reference bind="setDefaultAuthenticator" cardinality="1..1" interface="com.sun.net.httpserver.Authenticator" policy="static"/>
+   <service>
+      <provide interface="com.sun.net.httpserver.HttpServer"/>
+   </service>
 </scr:component>
index 7f33beeb695d45110be5dd6550fe7a952ad02f7a..3b9783ef5bc016cacdad31dfb5a6a42885a22493 100644 (file)
@@ -9,6 +9,8 @@ import javax.servlet.ServletException;
 import javax.websocket.DeploymentException;
 import javax.websocket.server.ServerContainer;
 import javax.websocket.server.ServerEndpointConfig;
+import com.sun.net.httpserver.Authenticator;
+import com.sun.net.httpserver.HttpContext;
 
 import org.argeo.api.cms.CmsState;
 import org.argeo.cms.CmsDeployProperty;
@@ -38,6 +40,8 @@ public class CmsJettyServer extends JettyHttpServer {
 
        private CmsState cmsState;
 
+       private Authenticator defaultAuthenticator;
+
        protected void addServlets(ServletContextHandler servletContextHandler) throws ServletException {
        }
 
@@ -73,6 +77,13 @@ public class CmsJettyServer extends JettyHttpServer {
 
        }
 
+       @Override
+       public synchronized HttpContext createContext(String path) {
+               HttpContext httpContext = super.createContext(path);
+               httpContext.setAuthenticator(defaultAuthenticator);
+               return httpContext;
+       }
+
        protected void enableWebSocket(ServletContextHandler servletContextHandler) {
                String webSocketEnabled = getDeployProperty(CmsDeployProperty.WEBSOCKET_ENABLED);
                // web socket
@@ -107,4 +118,8 @@ public class CmsJettyServer extends JettyHttpServer {
                this.cmsState = cmsState;
        }
 
+       public void setDefaultAuthenticator(Authenticator defaultAuthenticator) {
+               this.defaultAuthenticator = defaultAuthenticator;
+       }
+
 }
index 2aa4abc43a3662e5325f6e9fec9112ff159ec637..7adb09be32911945fd9fb44f47c95006f5ef748e 100644 (file)
@@ -12,6 +12,7 @@ import java.util.Set;
 import org.argeo.cms.servlet.httpserver.HttpContextServlet;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.session.SessionHandler;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
 
@@ -36,10 +37,15 @@ class JettyHttpContext extends HttpContext {
                this.httpServer = httpServer;
                this.path = path;
 
+               // Jetty context handler
                ServletContextHandler servletContextHandler = new ServletContextHandler();
                servletContextHandler.setContextPath(path);
                HttpContextServlet servlet = new HttpContextServlet(this);
                servletContextHandler.addServlet(new ServletHolder(servlet), "/*");
+               SessionHandler sessionHandler = new SessionHandler();
+               // FIXME find a better default
+               sessionHandler.setMaxInactiveInterval(-1);
+               servletContextHandler.setSessionHandler(sessionHandler);
                contextHandler = servletContextHandler;
 
                attributes = new ContextAttributes();
diff --git a/org.argeo.cms/OSGI-INF/cmsAcrHttpHandler.xml b/org.argeo.cms/OSGI-INF/cmsAcrHttpHandler.xml
new file mode 100644 (file)
index 0000000..0a2684a
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true">
+   <implementation class="org.argeo.cms.internal.runtime.CmsAcrHttpHandler"/>
+   <service>
+      <provide interface="com.sun.net.httpserver.HttpHandler"/>
+      <property name="contextPath" type="String" value="/api/acr" />
+   </service>
+</scr:component>
diff --git a/org.argeo.cms/OSGI-INF/cmsAuthenticator.xml b/org.argeo.cms/OSGI-INF/cmsAuthenticator.xml
new file mode 100644 (file)
index 0000000..9b15214
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.argeo.cms">
+   <implementation class="org.argeo.cms.internal.http.CmsAuthenticator"/>
+   <service>
+      <provide interface="com.sun.net.httpserver.Authenticator"/>
+   </service>
+   <reference cardinality="1..1" interface="org.osgi.service.useradmin.UserAdmin" name="UserAdmin" policy="static"/>
+</scr:component>
index 8495daad73d1ebe3467021fdbe732c258a42d0fe..102ae2adc0886dcbcfd7bb27f95e965cc504b00c 100644 (file)
@@ -2,6 +2,8 @@
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop" immediate="true" name="CMS Deployment">
    <implementation class="org.argeo.cms.internal.runtime.CmsDeploymentImpl"/>
    <reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
+   <reference bind="setHttpServer" cardinality="1..1" interface="com.sun.net.httpserver.HttpServer" policy="static"/>
+   <reference bind="addHttpHandler" unbind="removeHttpHandlerler" cardinality="0..1" interface="com.sun.net.httpserver.HttpHandler" policy="dynamic"/>
    <service>
       <provide interface="org.argeo.api.cms.CmsDeployment"/>
    </service>
index 12114c2a8edbf90375b1fd938f3679640f9966bf..bb8ed76bf9f87b2f3c829f578e3a98f36caae40b 100644 (file)
@@ -11,8 +11,10 @@ OSGI-INF/cmsState.xml,\
 OSGI-INF/simpleTransactionManager.xml,\
 OSGI-INF/nodeUserAdmin.xml,\
 OSGI-INF/cmsUserManager.xml,\
+OSGI-INF/cmsAuthenticator.xml,\
 OSGI-INF/uuidFactory.xml,\
 OSGI-INF/acrContentRepository.xml,\
+OSGI-INF/cmsAcrHttpHandler.xml,\
 OSGI-INF/cmsDeployment.xml,\
 OSGI-INF/cmsContext.xml,\
 
index 67b98f4d0034c2f7752e765fbee687477633e222..11ab9e06e1ae5380241cd333f31c9c122472433f 100644 (file)
@@ -2,5 +2,7 @@ output.. = bin/
 bin.includes = META-INF/,\
                .,\
                bin/,\
-               OSGI-INF/
+               OSGI-INF/,\
+               OSGI-INF/cmsAuthenticator.xml,\
+               OSGI-INF/cmsAcrHttpHandler.xml
 source.. = src/
index 54849fc03912a127a9506bd745979115bcbf708d..04312eca3d8abcb573c446f6be45eb434191a244 100644 (file)
@@ -69,7 +69,7 @@ public class CmsAuthenticator extends Authenticator {
        }
 
        protected boolean authIsRequired(HttpExchange httpExchange) {
-               return false;
+               return true;
        }
 
        protected LoginContext processUnauthorized(HttpExchange httpExchange) {
index 68e0b1e3eada1cae69318cc03f2694c86346d6e6..00f2b8fe1646dac38053a2125743c5bed9ac4f90 100644 (file)
@@ -3,6 +3,7 @@ package org.argeo.cms.internal.http;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 
 import org.argeo.cms.auth.RemoteAuthRequest;
 import org.argeo.cms.auth.RemoteAuthResponse;
@@ -11,10 +12,13 @@ import org.argeo.cms.auth.RemoteAuthSession;
 import com.sun.net.httpserver.HttpExchange;
 
 public class RemoteAuthHttpExchange implements RemoteAuthRequest, RemoteAuthResponse {
-       private HttpExchange httpExchange;
+       private final HttpExchange httpExchange;
+       private RemoteAuthSession remoteAuthSession;
 
        public RemoteAuthHttpExchange(HttpExchange httpExchange) {
                this.httpExchange = httpExchange;
+               this.remoteAuthSession = (RemoteAuthSession) httpExchange.getAttribute(RemoteAuthSession.class.getName());
+               Objects.requireNonNull(this.remoteAuthSession);
        }
 
        @Override
@@ -24,14 +28,12 @@ public class RemoteAuthHttpExchange implements RemoteAuthRequest, RemoteAuthResp
 
        @Override
        public RemoteAuthSession getSession() {
-               // TODO Auto-generated method stub
-               return null;
+               return remoteAuthSession;
        }
 
        @Override
        public RemoteAuthSession createSession() {
-               // TODO Auto-generated method stub
-               return null;
+               throw new UnsupportedOperationException("Cannot create remote session");
        }
 
        @Override
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsAcrHttpHandler.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsAcrHttpHandler.java
new file mode 100644 (file)
index 0000000..d9fa9e7
--- /dev/null
@@ -0,0 +1,7 @@
+package org.argeo.cms.internal.runtime;
+
+import org.argeo.util.dav.DavServerHandler;
+
+public class CmsAcrHttpHandler extends DavServerHandler  {
+
+}
index 1b94bdad12ca880806de1643c37d27fbc6f0cc52..8b0fbbc6862f9b94b3a0ae176d5cb6f81daa7290 100644 (file)
@@ -1,10 +1,15 @@
 package org.argeo.cms.internal.runtime;
 
+import java.util.Map;
+
 import org.argeo.api.cms.CmsDeployment;
 import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.CmsState;
 import org.argeo.cms.CmsDeployProperty;
 
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+
 /** Implementation of a CMS deployment. */
 public class CmsDeploymentImpl implements CmsDeployment {
        private final CmsLog log = CmsLog.getLog(getClass());
@@ -16,6 +21,8 @@ public class CmsDeploymentImpl implements CmsDeployment {
        private CmsState cmsState;
 //     private DeployConfig deployConfig;
 
+       private HttpServer httpServer;
+
        public void start() {
 //             httpExpected = deployConfig.getProps(KernelConstants.JETTY_FACTORY_PID, "default") != null;
 //             if (deployConfig.hasDomain()) {
@@ -69,6 +76,26 @@ public class CmsDeploymentImpl implements CmsDeployment {
                httpExpected = httpPort != null || httpsPort != null;
        }
 
+       public void setHttpServer(HttpServer httpServer) {
+               this.httpServer = httpServer;
+       }
+
+       public void addHttpHandler(HttpHandler httpHandler, Map<String, String> properties) {
+               if (httpServer == null)
+                       return;
+               final String contextPath = properties.get("contextPath");
+               httpServer.createContext(contextPath, httpHandler);
+               log.debug(() -> "Added handler " + contextPath + " : " + httpHandler.getClass().getName());
+
+       }
+
+       public void removeHttpHandler(HttpHandler httpHandler, Map<String, String> properties) {
+               if (httpServer == null)
+                       return;
+               final String contextPath = properties.get("contextPath");
+               httpServer.removeContext(contextPath);
+               log.debug(() -> "Removed handler " + contextPath + " : " + httpHandler.getClass().getName());
+       }
 //     public void setHttpService(HttpService httpService) {
 //             this.httpService = httpService;
 //     }
index dff4d85df8e953f30c2812b7b891fec99a979fb3..7252f425fd6f5544d92d47316bdf1f6596c789f0 100644 (file)
@@ -44,7 +44,7 @@ public class CmsStateImpl implements CmsState {
 
        private UUID uuid;
 //     private final boolean cleanState;
-       private String hostname;
+//     private String hostname;
 
        private UuidFactory uuidFactory;
 
@@ -83,11 +83,11 @@ public class CmsStateImpl implements CmsState {
 //                     this.uuid = UUID.fromString(stateUuidStr);
                        this.uuid = uuidFactory.timeUUID();
 //             this.cleanState = stateUuid.equals(frameworkUuid);
-                       try {
-                               this.hostname = InetAddress.getLocalHost().getHostName();
-                       } catch (UnknownHostException e) {
-                               log.error("Cannot set hostname: " + e);
-                       }
+//                     try {
+//                             this.hostname = InetAddress.getLocalHost().getHostName();
+//                     } catch (UnknownHostException e) {
+//                             log.error("Cannot set hostname: " + e);
+//                     }
 
                        availableSince = System.currentTimeMillis();
                        if (log.isDebugEnabled()) {
@@ -337,10 +337,6 @@ public class CmsStateImpl implements CmsState {
        /*
         * ACCESSORS
         */
-       public String getHostname() {
-               return hostname;
-       }
-
        @Override
        public UUID getUuid() {
                return uuid;
index 4fc73f3ce4778101a5f1d0d721a3276fa6e9d257..f9fba4761c62b26a91616f3afa64a0e69609ef75 100644 (file)
@@ -2,6 +2,8 @@ package org.argeo.util.dav;
 
 import java.io.IOException;
 
+import org.argeo.util.http.HttpMethod;
+
 import com.sun.net.httpserver.HttpExchange;
 import com.sun.net.httpserver.HttpHandler;
 
@@ -12,6 +14,8 @@ public class DavServerHandler implements HttpHandler {
                String method = exchange.getRequestMethod();
                if (DavMethod.PROPFIND.name().equals(method)) {
                        handle(exchange);
+               } else if (HttpMethod.GET.name().equals(method)) {
+                       exchange.getResponseBody().write("Hello Dav!".getBytes());
                } else {
                        throw new IllegalArgumentException("Unsupported method " + method);
                }
diff --git a/org.argeo.util/src/org/argeo/util/http/HttpMethod.java b/org.argeo.util/src/org/argeo/util/http/HttpMethod.java
new file mode 100644 (file)
index 0000000..2116057
--- /dev/null
@@ -0,0 +1,6 @@
+package org.argeo.util.http;
+
+public enum HttpMethod {
+       GET,//
+       ;
+}
index e713f53e1aac9fed254b1f97e0e7a201b4feca28..0a28dc5ee064d2d32ad651cb4a9271574f5ae96f 100644 (file)
@@ -71,15 +71,14 @@ class DeploymentEntryPoint {
                Label label = new Label(composite, SWT.WRAP);
                CmsSwtUtils.markup(label);
                if (nodeDeploymentRef == null) {
-                       label.setText("Not yet deployed on <br>" + nodeState.getHostname() + "</br>, please configure below.");
+                       label.setText("Not yet deployed on, please configure below.");
                } else {
                        Object stateUuid = nodeStateRef.getProperty(CmsConstants.CN);
                        CmsContext nodeDeployment = bc.getService(nodeDeploymentRef);
                        GregorianCalendar calendar = new GregorianCalendar();
                        calendar.setTimeInMillis(nodeDeployment.getAvailableSince());
                        calendar.setTimeZone(TimeZone.getDefault());
-                       label.setText("[" + "<b>" + nodeState.getHostname() + "</b>]# " + "Deployment state " + stateUuid
-                                       + ", available since <b>" + calendar.getTime() + "</b>");
+                       label.setText("Deployment state " + stateUuid + ", available since <b>" + calendar.getTime() + "</b>");
                }
        }