Improve CMS session.
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 8 Apr 2017 11:21:37 +0000 (13:21 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 8 Apr 2017 11:21:37 +0000 (13:21 +0200)
Introduce CMS sessions monitoring view.

25 files changed:
demo/log4j.properties
org.argeo.cms.ui.workbench.rap/src/org/argeo/cms/ui/workbench/rap/RapWorkbenchLogin.java
org.argeo.cms.ui.workbench.rap/src/org/argeo/cms/ui/workbench/rap/SpnegoWorkbenchLogin.java
org.argeo.cms.ui.workbench/plugin.xml
org.argeo.cms.ui.workbench/src/org/argeo/cms/ui/workbench/osgi/CmsSessionsView.java [new file with mode: 0644]
org.argeo.cms.ui/src/org/argeo/cms/ui/AbstractCmsEntryPoint.java
org.argeo.cms.ui/src/org/argeo/cms/ui/CmsView.java
org.argeo.cms.ui/src/org/argeo/cms/util/CmsUtils.java
org.argeo.cms.ui/src/org/argeo/cms/util/LoginEntryPoint.java
org.argeo.cms.ui/src/org/argeo/cms/widgets/auth/CmsLogin.java
org.argeo.cms/src/org/argeo/cms/auth/AnonymousLoginModule.java
org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java
org.argeo.cms/src/org/argeo/cms/auth/CmsAuthenticated.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/auth/CmsSession.java
org.argeo.cms/src/org/argeo/cms/auth/CurrentUser.java
org.argeo.cms/src/org/argeo/cms/auth/HttpSessionLoginModule.java
org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java
org.argeo.cms/src/org/argeo/cms/internal/auth/CmsSessionImpl.java
org.argeo.cms/src/org/argeo/cms/internal/http/CmsSessionProvider.java
org.argeo.cms/src/org/argeo/cms/internal/http/HttpFilter.java [deleted file]
org.argeo.cms/src/org/argeo/cms/internal/http/WebCmsSessionImpl.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelThread.java
org.argeo.jcr/src/org/argeo/jcr/proxy/ResourceProxyServlet.java
org.argeo.node.api/src/org/argeo/node/security/NodeAuthenticated.java [deleted file]
org.argeo.util/src/org/argeo/util/LangUtils.java

index 2fd64cd2a1508e7bd15003a333c84dc5c2d7df69..01027a532f4d3a49220b141bd45c352229de8301 100644 (file)
@@ -1,4 +1,4 @@
-log4j.rootLogger=WARN, console
+log4j.rootLogger=WARN, development
 
 log4j.logger.org.argeo=DEBUG
 log4j.logger.org.argeo.cms.internal=TRACE
index a023013a8d4704bd796b948863257f36fccf2989..73aac8282b55e80aa572dcfdf81937e3f53367a6 100644 (file)
@@ -44,7 +44,7 @@ public class RapWorkbenchLogin extends LoginEntryPoint {
 
        @Override
        protected int postLogin() {
-               Subject subject = getLoginContext().getSubject();
+               Subject subject = getSubject();
                final Display display = Display.getCurrent();
                if (subject.getPrincipals(X500Principal.class).isEmpty()) {
                        RWT.getClient().getService(JavaScriptExecutor.class).execute("location.reload()");
index efb2518280f31324168c46a323981928a4e799f0..2f4ef095b401761157e522df7905516cadfd6905 100644 (file)
@@ -53,7 +53,7 @@ public class SpnegoWorkbenchLogin extends LoginEntryPoint {
 
        @Override
        protected int postLogin() {
-               Subject subject = getLoginContext().getSubject();
+               Subject subject = getSubject();
                final Display display = Display.getCurrent();
                if (subject.getPrincipals(X500Principal.class).isEmpty()) {
                        RWT.getClient().getService(JavaScriptExecutor.class).execute("location.reload()");
index b28859fdf9506b03856a2e07e138ffb1ac1eb189..c656c2ff94bff0ba464e502f3416a39e882896b5 100644 (file)
     <extension point="org.eclipse.ui.perspectiveExtensions"> 
         <perspectiveExtension targetID="org.argeo.cms.ui.workbench.osgiPerspective"> 
             <view 
-               id="org.argeo.cms.ui.workbench.modulesView" 
+               id="org.argeo.cms.ui.workbench.cmsSessionsView" 
                minimized="false"
                ratio="0.5" 
                relationship="left" 
                relative="org.eclipse.ui.editorss"/> 
             <view 
+               id="org.argeo.cms.ui.workbench.modulesView" 
+               minimized="false"
+               relationship="stack"
+               relative="org.argeo.cms.ui.workbench.cmsSessionsView"/> 
+             <view 
                id="org.argeo.cms.ui.workbench.bundlesView" 
                minimized="false"
                relationship="stack" 
                        class="org.argeo.cms.ui.workbench.osgi.ModulesView">
                </view>
                <view
+               name="CMS Session"
+            id="org.argeo.cms.ui.workbench.cmsSessionsView"
+            icon="icons/service_published.gif"
+                       class="org.argeo.cms.ui.workbench.osgi.CmsSessionsView">
+               </view>
+               <view
                name="Bundles"
             id="org.argeo.cms.ui.workbench.bundlesView" 
             icon="icons/bundles.gif"
diff --git a/org.argeo.cms.ui.workbench/src/org/argeo/cms/ui/workbench/osgi/CmsSessionsView.java b/org.argeo.cms.ui.workbench/src/org/argeo/cms/ui/workbench/osgi/CmsSessionsView.java
new file mode 100644 (file)
index 0000000..8f34a0b
--- /dev/null
@@ -0,0 +1,207 @@
+//package org.argeo.eclipse.ui.workbench.osgi;
+//public class BundlesView {}
+
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.cms.ui.workbench.osgi;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+
+import javax.naming.ldap.LdapName;
+
+import org.argeo.cms.CmsException;
+import org.argeo.cms.auth.CmsSession;
+import org.argeo.cms.ui.workbench.WorkbenchUiPlugin;
+import org.argeo.eclipse.ui.ColumnViewerComparator;
+import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
+import org.argeo.util.LangUtils;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.ViewPart;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Overview of the active CMS sessions.
+ */
+public class CmsSessionsView extends ViewPart {
+       private TableViewer viewer;
+
+       @Override
+       public void createPartControl(Composite parent) {
+               viewer = new TableViewer(parent);
+               viewer.setContentProvider(new CmsSessionContentProvider());
+               viewer.getTable().setHeaderVisible(true);
+
+               EclipseUiSpecificUtils.enableToolTipSupport(viewer);
+
+               int longColWidth = 150;
+               int smallColWidth = 100;
+
+               // Display name
+               TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
+               column.getColumn().setWidth(longColWidth);
+               column.getColumn().setText("User");
+               column.setLabelProvider(new ColumnLabelProvider() {
+                       private static final long serialVersionUID = -5234573509093747505L;
+
+                       public String getText(Object element) {
+                               return ((CmsSession) element).getAuthorization().toString();
+                       }
+
+                       public String getToolTipText(Object element) {
+                               return ((CmsSession) element).getUserDn().toString();
+                       }
+               });
+               new ColumnViewerComparator<CmsSession>(column, new Comparator<CmsSession>() {
+                       public int compare(CmsSession o1, CmsSession o2) {
+                               return o1.getAuthorization().toString().compareTo(o2.getAuthorization().toString());
+                       }
+               });
+
+               // Creation time
+               column = new TableViewerColumn(viewer, SWT.NONE);
+               column.getColumn().setWidth(smallColWidth);
+               column.getColumn().setText("Since");
+               column.setLabelProvider(new ColumnLabelProvider() {
+                       private static final long serialVersionUID = -5234573509093747505L;
+
+                       public String getText(Object element) {
+                               return LangUtils.since(((CmsSession) element).getCreationTime());
+                       }
+
+                       public String getToolTipText(Object element) {
+                               return ((CmsSession) element).getCreationTime().toString();
+                       }
+               });
+               new ColumnViewerComparator<CmsSession>(column, new Comparator<CmsSession>() {
+                       public int compare(CmsSession o1, CmsSession o2) {
+                               return o1.getCreationTime().compareTo(o2.getCreationTime());
+                       }
+               });
+
+               // Username
+               column = new TableViewerColumn(viewer, SWT.NONE);
+               column.getColumn().setWidth(smallColWidth);
+               column.getColumn().setText("Username");
+               column.setLabelProvider(new ColumnLabelProvider() {
+                       private static final long serialVersionUID = -5234573509093747505L;
+
+                       public String getText(Object element) {
+                               LdapName userDn = ((CmsSession) element).getUserDn();
+                               return userDn.getRdn(userDn.size() - 1).getValue().toString();
+                       }
+
+                       public String getToolTipText(Object element) {
+                               return ((CmsSession) element).getUserDn().toString();
+                       }
+               });
+               new ColumnViewerComparator<CmsSession>(column, new Comparator<CmsSession>() {
+                       public int compare(CmsSession o1, CmsSession o2) {
+                               return o1.getUserDn().compareTo(o2.getUserDn());
+                       }
+               });
+
+               // UUID
+               column = new TableViewerColumn(viewer, SWT.NONE);
+               column.getColumn().setWidth(smallColWidth);
+               column.getColumn().setText("UUID");
+               column.setLabelProvider(new ColumnLabelProvider() {
+                       private static final long serialVersionUID = -5234573509093747505L;
+
+                       public String getText(Object element) {
+                               return ((CmsSession) element).getUuid().toString();
+                       }
+
+                       public String getToolTipText(Object element) {
+                               return getText(element);
+                       }
+               });
+               new ColumnViewerComparator<CmsSession>(column, new Comparator<CmsSession>() {
+                       public int compare(CmsSession o1, CmsSession o2) {
+                               return o1.getUuid().compareTo(o2.getUuid());
+                       }
+               });
+
+               // Local ID
+               column = new TableViewerColumn(viewer, SWT.NONE);
+               column.getColumn().setWidth(smallColWidth);
+               column.getColumn().setText("Local ID");
+               column.setLabelProvider(new ColumnLabelProvider() {
+                       private static final long serialVersionUID = -5234573509093747505L;
+
+                       public String getText(Object element) {
+                               return ((CmsSession) element).getLocalId();
+                       }
+
+                       public String getToolTipText(Object element) {
+                               return getText(element);
+                       }
+               });
+               new ColumnViewerComparator<CmsSession>(column, new Comparator<CmsSession>() {
+                       public int compare(CmsSession o1, CmsSession o2) {
+                               return o1.getLocalId().compareTo(o2.getLocalId());
+                       }
+               });
+
+               viewer.setInput(WorkbenchUiPlugin.getDefault().getBundle().getBundleContext());
+
+       }
+
+       @Override
+       public void setFocus() {
+               if (viewer != null)
+                       viewer.getControl().setFocus();
+       }
+
+       /** Content provider managing the array of bundles */
+       private static class CmsSessionContentProvider implements IStructuredContentProvider {
+               private static final long serialVersionUID = -8533792785725875977L;
+
+               public Object[] getElements(Object inputElement) {
+                       if (inputElement instanceof BundleContext) {
+                               BundleContext bc = (BundleContext) inputElement;
+                               Collection<ServiceReference<CmsSession>> srs;
+                               try {
+                                       srs = bc.getServiceReferences(CmsSession.class, null);
+                               } catch (InvalidSyntaxException e) {
+                                       throw new CmsException("Cannot retrieve CMS sessions", e);
+                               }
+                               List<CmsSession> res = new ArrayList<>();
+                               for (ServiceReference<CmsSession> sr : srs) {
+                                       res.add(bc.getService(sr));
+                               }
+                               return res.toArray();
+                       }
+                       return null;
+               }
+
+               public void dispose() {
+               }
+
+               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+               }
+       }
+}
index bea7117a6c6e3737e8fb1aec82797164f0462ba1..99989db19c0cdb58835d1b3ac218a864f3e53415 100644 (file)
@@ -21,10 +21,10 @@ import org.apache.commons.logging.LogFactory;
 import org.argeo.cms.CmsException;
 import org.argeo.cms.auth.CurrentUser;
 import org.argeo.cms.auth.HttpRequestCallbackHandler;
+import org.argeo.cms.auth.CmsAuthenticated;
 import org.argeo.eclipse.ui.specific.UiContext;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.node.NodeConstants;
-import org.argeo.node.security.NodeAuthenticated;
 import org.eclipse.rap.rwt.RWT;
 import org.eclipse.rap.rwt.application.AbstractEntryPoint;
 import org.eclipse.rap.rwt.client.WebClient;
@@ -71,19 +71,20 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implement
                // subject = new Subject();
 
                // Initial login
+               LoginContext lc;
                try {
-                       loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
+                       lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
                                        new HttpRequestCallbackHandler(UiContext.getHttpRequest(), UiContext.getHttpResponse()));
-                       loginContext.login();
+                       lc.login();
                } catch (LoginException e) {
                        try {
-                               loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
-                               loginContext.login();
+                               lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
+                               lc.login();
                        } catch (LoginException e1) {
                                throw new CmsException("Cannot log in as anonymous", e1);
                        }
                }
-               authChange(loginContext);
+               authChange(lc);
 
                jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
                browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
@@ -109,8 +110,8 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implement
 
        @Override
        protected final void createContents(final Composite parent) {
-               UiContext.setData(NodeAuthenticated.KEY, this);
-               Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
+               UiContext.setData(CmsAuthenticated.KEY, this);
+               Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
                        @Override
                        public Void run() {
                                try {
@@ -162,9 +163,12 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implement
        // return subject;
        // }
 
-       @Override
-       public LoginContext getLoginContext() {
-               return loginContext;
+       // @Override
+       // public LoginContext getLoginContext() {
+       // return loginContext;
+       // }
+       public Subject getSubject() {
+               return loginContext.getSubject();
        }
 
        @Override
@@ -183,11 +187,18 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implement
        }
 
        @Override
-       public synchronized void authChange(LoginContext loginContext) {
-               if (loginContext == null)
+       public synchronized void authChange(LoginContext lc) {
+               if (lc == null)
                        throw new CmsException("Login context cannot be null");
-               this.loginContext = loginContext;
-               Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
+               // logout previous login context
+               if (this.loginContext != null)
+                       try {
+                               this.loginContext.logout();
+                       } catch (LoginException e1) {
+                               log.warn("Could not log out: " + e1);
+                       }
+               this.loginContext = lc;
+               Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
 
                        @Override
                        public Void run() {
@@ -210,7 +221,6 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implement
                        }
 
                });
-
        }
 
        @Override
@@ -221,7 +231,7 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implement
        }
 
        protected synchronized void doRefresh() {
-               Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
+               Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
                        @Override
                        public Void run() {
                                refresh();
index d39d6df162f200a75150a2254b8e79845a951cb4..51f6acc8cb770e37be2c353123b2368fb701c8d1 100644 (file)
@@ -2,10 +2,10 @@ package org.argeo.cms.ui;
 
 import javax.security.auth.login.LoginContext;
 
-import org.argeo.node.security.NodeAuthenticated;
+import org.argeo.cms.auth.CmsAuthenticated;
 
 /** Provides interaction with the CMS system. UNSTABLE API at this stage. */
-public interface CmsView extends NodeAuthenticated {
+public interface CmsView extends CmsAuthenticated {
        UxContext getUxContext();
 
        // NAVIGATION
index 7864dde8b645999e094529dce4facb70bfdf441e..3bb984b6a86bfff20ec7a6d2d5aea92ead954859 100644 (file)
@@ -10,13 +10,13 @@ import javax.servlet.http.HttpServletRequest;
 
 import org.apache.commons.io.IOUtils;
 import org.argeo.cms.CmsException;
+import org.argeo.cms.auth.CmsAuthenticated;
 import org.argeo.cms.ui.CmsConstants;
 import org.argeo.cms.ui.CmsView;
 import org.argeo.eclipse.ui.specific.UiContext;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.node.NodeConstants;
 import org.argeo.node.NodeUtils;
-import org.argeo.node.security.NodeAuthenticated;
 import org.eclipse.rap.rwt.RWT;
 import org.eclipse.rap.rwt.service.ResourceManager;
 import org.eclipse.swt.SWT;
@@ -41,7 +41,7 @@ public class CmsUtils implements CmsConstants {
         * this call.
         */
        public static CmsView getCmsView() {
-               return UiContext.getData(NodeAuthenticated.KEY);
+               return UiContext.getData(CmsAuthenticated.KEY);
        }
 
        public static StringBuilder getServerBaseUrl(HttpServletRequest request) {
index a8b52a5c29c91f861b727f7a775df1f1f5121e49..a43b9ee92723f1fb28b15604e62a74b56bf32378 100644 (file)
@@ -2,12 +2,16 @@ package org.argeo.cms.util;
 
 import java.util.Locale;
 
+import javax.security.auth.Subject;
 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.cms.CmsException;
 import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.auth.CmsAuthenticated;
 import org.argeo.cms.ui.CmsImageManager;
 import org.argeo.cms.ui.CmsView;
 import org.argeo.cms.ui.UxContext;
@@ -15,7 +19,6 @@ import org.argeo.cms.widgets.auth.CmsLogin;
 import org.argeo.cms.widgets.auth.CmsLoginShell;
 import org.argeo.eclipse.ui.specific.UiContext;
 import org.argeo.node.NodeConstants;
-import org.argeo.node.security.NodeAuthenticated;
 import org.eclipse.rap.rwt.RWT;
 import org.eclipse.rap.rwt.application.EntryPoint;
 import org.eclipse.swt.events.SelectionListener;
@@ -25,15 +28,14 @@ import org.eclipse.swt.widgets.Display;
 public class LoginEntryPoint implements EntryPoint, CmsView {
        protected final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
        protected final static String HEADER_AUTHORIZATION = "Authorization";
-       // private final static Log log = LogFactory.getLog(WorkbenchLogin.class);
-       // private final Subject subject = new Subject();
+       private final static Log log = LogFactory.getLog(LoginEntryPoint.class);
        private LoginContext loginContext;
        private UxContext uxContext = null;
 
        @Override
        public int createUI() {
                final Display display = createDisplay();
-               UiContext.setData(NodeAuthenticated.KEY, this);
+               UiContext.setData(CmsAuthenticated.KEY, this);
                CmsLoginShell loginShell = createCmsLoginShell();
                try {
                        // try pre-auth
@@ -43,19 +45,21 @@ public class LoginEntryPoint implements EntryPoint, CmsView {
                        loginShell.createUi();
                        loginShell.open();
 
-//                     HttpServletRequest request = RWT.getRequest();
-//                     String authorization = request.getHeader(HEADER_AUTHORIZATION);
-//                     if (authorization == null || !authorization.startsWith("Negotiate")) {
-//                             HttpServletResponse response = RWT.getResponse();
-//                             response.setStatus(401);
-//                             response.setHeader(HEADER_WWW_AUTHENTICATE, "Negotiate");
-//                             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");
-//                     }
+                       // HttpServletRequest request = RWT.getRequest();
+                       // String authorization = request.getHeader(HEADER_AUTHORIZATION);
+                       // if (authorization == null ||
+                       // !authorization.startsWith("Negotiate")) {
+                       // HttpServletResponse response = RWT.getResponse();
+                       // response.setStatus(401);
+                       // response.setHeader(HEADER_WWW_AUTHENTICATE, "Negotiate");
+                       // 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");
+                       // }
 
                        while (!loginShell.getShell().isDisposed()) {
                                if (!display.readAndDispatch())
@@ -121,6 +125,15 @@ public class LoginEntryPoint implements EntryPoint, CmsView {
 
        @Override
        public void authChange(LoginContext loginContext) {
+               if (loginContext == null)
+                       throw new CmsException("Login context cannot be null");
+               // logout previous login context
+               if (this.loginContext != null)
+                       try {
+                               this.loginContext.logout();
+                       } catch (LoginException e1) {
+                               log.warn("Could not log out: " + e1);
+                       }
                this.loginContext = loginContext;
        }
 
@@ -142,9 +155,13 @@ public class LoginEntryPoint implements EntryPoint, CmsView {
 
        }
 
-       @Override
-       public LoginContext getLoginContext() {
-               return loginContext;
+       // @Override
+       // public LoginContext getLoginContext() {
+       // return loginContext;
+       // }
+
+       public Subject getSubject() {
+               return loginContext.getSubject();
        }
 
        @Override
index 76263c1f2a5d514c3c5533008802679a71802f3a..f25ad19e2398b3cc5d900cd6b03b04814b07cfe5 100644 (file)
@@ -13,7 +13,6 @@ import javax.security.auth.callback.LanguageCallback;
 import javax.security.auth.callback.NameCallback;
 import javax.security.auth.callback.PasswordCallback;
 import javax.security.auth.callback.UnsupportedCallbackException;
-import javax.security.auth.login.FailedLoginException;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
 
@@ -80,7 +79,7 @@ public class CmsLogin implements CmsStyles, CallbackHandler {
        }
 
        protected boolean isAnonymous() {
-               return CurrentUser.isAnonymous(cmsView.getLoginContext().getSubject());
+               return CurrentUser.isAnonymous(cmsView.getSubject());
        }
 
        public final void createUi(Composite parent) {
@@ -247,14 +246,16 @@ public class CmsLogin implements CmsStyles, CallbackHandler {
 
        protected boolean login() {
                // Subject subject = cmsView.getLoginContext().getSubject();
-               LoginContext loginContext = cmsView.getLoginContext();
+//             LoginContext loginContext = cmsView.getLoginContext();
                try {
                        //
                        // LOGIN
                        //
-                       loginContext.logout();
-                       loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, this);
+//                     loginContext.logout();
+                       LoginContext loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, this);
                        loginContext.login();
+                       cmsView.authChange(loginContext);
+                       return true;
                } catch (LoginException e) {
                        if (log.isTraceEnabled())
                                log.warn("Login failed: " + e.getMessage(), e);
@@ -273,8 +274,6 @@ public class CmsLogin implements CmsStyles, CallbackHandler {
                // log.error("Cannot login", e);
                // return false;
                // }
-               cmsView.authChange(loginContext);
-               return true;
        }
 
        protected void logout() {
index 12a0704158a22de18935fc101c966d02a47ed2a3..7a1283afa9d7cc72ed93b50eafb07320ce7e4ff1 100644 (file)
@@ -64,8 +64,8 @@ public class AnonymousLoginModule implements LoginModule {
 
        @Override
        public boolean logout() throws LoginException {
-               if (log.isDebugEnabled())
-                       log.debug("Logging out anonymous from CMS... " + subject);
+               if (log.isTraceEnabled())
+                       log.trace("Logging out anonymous from CMS... " + subject);
                CmsAuthUtils.cleanUp(subject);
                return true;
        }
index 4d59c5263a76afe974b600244c8ad6b848c98243..33a8dc62eb4a4979299bbadf501ac7cc0002f4d8 100644 (file)
@@ -118,19 +118,19 @@ class CmsAuthUtils {
        private static void registerSessionAuthorization(HttpServletRequest request, Subject subject,
                        Authorization authorization) {
                if (request != null) {
-                       HttpSession httpSession = request.getSession();
+                       HttpSession httpSession = request.getSession(false);
                        String httpSessId = httpSession.getId();
                        String remoteUser = authorization.getName() != null ? authorization.getName()
                                        : NodeConstants.ROLE_ANONYMOUS;
                        request.setAttribute(HttpContext.REMOTE_USER, remoteUser);
                        request.setAttribute(HttpContext.AUTHORIZATION, authorization);
 
-                       CmsSession cmsSession = CmsSessionImpl.getByLocalId(httpSessId);
+                       CmsSessionImpl cmsSession = (CmsSessionImpl) CmsSessionImpl.getByLocalId(httpSessId);
                        if (cmsSession != null) {
                                if (authorization.getName() != null) {
                                        if (cmsSession.getAuthorization().getName() == null) {
                                                // FIXME make it more generic
-                                               ((WebCmsSessionImpl) cmsSession).cleanUp();
+                                               cmsSession.close();
                                                cmsSession = null;
                                        } else if (!authorization.getName().equals(cmsSession.getAuthorization().getName())) {
                                                throw new CmsException("Inconsistent user " + authorization.getName()
@@ -139,14 +139,14 @@ class CmsAuthUtils {
                                } else {// anonymous
                                        if (cmsSession.getAuthorization().getName() != null) {
                                                // FIXME make it more generic
-                                               ((WebCmsSessionImpl) cmsSession).cleanUp();
+                                               cmsSession.close();
                                                cmsSession = null;
                                        }
                                }
                        }
 
                        if (cmsSession == null)
-                               cmsSession = new WebCmsSessionImpl(subject, authorization, httpSessId);
+                               cmsSession = new WebCmsSessionImpl(subject, authorization, request);
                        // request.setAttribute(CmsSession.class.getName(), cmsSession);
                        CmsSessionId nodeSessionId = new CmsSessionId(cmsSession.getUuid());
                        if (subject.getPrivateCredentials(CmsSessionId.class).size() == 0)
diff --git a/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthenticated.java b/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthenticated.java
new file mode 100644 (file)
index 0000000..704e933
--- /dev/null
@@ -0,0 +1,11 @@
+package org.argeo.cms.auth;
+
+import javax.security.auth.Subject;
+
+public interface CmsAuthenticated {
+       String KEY = "org.argeo.cms.authenticated";
+
+       Subject getSubject();
+//     LoginContext getLoginContext();
+
+}
index 14d6d71f655b54c9a23bc9fd55e1bf0761cbb885..118f875891a8782ed8248d6633b730bb689cc600 100644 (file)
@@ -1,32 +1,39 @@
 package org.argeo.cms.auth;
 
+import java.time.ZonedDateTime;
 import java.util.UUID;
 
-import javax.jcr.Repository;
-import javax.jcr.Session;
 import javax.naming.ldap.LdapName;
 
 import org.argeo.naming.LdapAttrs;
 import org.osgi.service.useradmin.Authorization;
 
 public interface CmsSession {
-       public final static String USER_DN = LdapAttrs.DN;
-       public final static String SESSION_UUID = LdapAttrs.entryUUID.name();
-       public final static String SESSION_LOCAL_ID = LdapAttrs.uniqueIdentifier.name();
+       final static String USER_DN = LdapAttrs.DN;
+       final static String SESSION_UUID = LdapAttrs.entryUUID.name();
+       final static String SESSION_LOCAL_ID = LdapAttrs.uniqueIdentifier.name();
 
        // public String getId();
 
-       public UUID getUuid();
+       UUID getUuid();
 
-       public LdapName getUserDn();
+       LdapName getUserDn();
 
-       public String getLocalId();
+       String getLocalId();
 
-       public Authorization getAuthorization();
+       Authorization getAuthorization();
 
-       public Session getDataSession(String cn, String workspace, Repository repository);
+       boolean isAnonymous();
 
-       public void releaseDataSession(String cn, Session session);
+       ZonedDateTime getCreationTime();
+       ZonedDateTime getEnd();
+
+       boolean isValid();
+
+       // public Session getDataSession(String cn, String workspace, Repository
+       // repository);
+       //
+       // public void releaseDataSession(String cn, Session session);
 
        // public void addHttpSession(HttpServletRequest request);
 
index 375600ad275406c71f36404f4fa8e43c852360ec..2f6325d279ccf687f82370771c8b5237746e3e19 100644 (file)
@@ -21,7 +21,6 @@ import java.security.PrivilegedAction;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.security.acl.Group;
-import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.UUID;
@@ -32,14 +31,9 @@ import javax.security.auth.x500.X500Principal;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.cms.CmsException;
-import org.argeo.cms.internal.http.WebCmsSessionImpl;
+import org.argeo.cms.internal.auth.CmsSessionImpl;
 import org.argeo.eclipse.ui.specific.UiContext;
 import org.argeo.node.NodeConstants;
-import org.argeo.node.security.NodeAuthenticated;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
 import org.osgi.service.useradmin.Authorization;
 
 /**
@@ -48,7 +42,7 @@ import org.osgi.service.useradmin.Authorization;
  */
 public final class CurrentUser {
        private final static Log log = LogFactory.getLog(CurrentUser.class);
-       private final static BundleContext bc = FrameworkUtil.getBundle(CurrentUser.class).getBundleContext();
+//     private final static BundleContext bc = FrameworkUtil.getBundle(CurrentUser.class).getBundleContext();
        /*
         * CURRENT USER API
         */
@@ -135,9 +129,9 @@ public final class CurrentUser {
         */
 
        private static Subject currentSubject() {
-               NodeAuthenticated cmsView = getNodeAuthenticated();
+               CmsAuthenticated cmsView = getNodeAuthenticated();
                if (cmsView != null)
-                       return cmsView.getLoginContext().getSubject();
+                       return cmsView.getSubject();
                Subject subject = Subject.getSubject(AccessController.getContext());
                if (subject != null)
                        return subject;
@@ -149,8 +143,8 @@ public final class CurrentUser {
         * display, or null if none is available from this call. <b>Not API: Only
         * for low-level access.</b>
         */
-       private static NodeAuthenticated getNodeAuthenticated() {
-               return UiContext.getData(NodeAuthenticated.KEY);
+       private static CmsAuthenticated getNodeAuthenticated() {
+               return UiContext.getData(CmsAuthenticated.KEY);
        }
 
        private static Authorization getAuthorization(Subject subject) {
@@ -163,24 +157,30 @@ public final class CurrentUser {
                        nodeSessionId = subject.getPrivateCredentials(CmsSessionId.class).iterator().next().getUuid();
                else
                        return false;
-               Collection<ServiceReference<CmsSession>> srs;
-               try {
-                       srs = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_UUID + "=" + nodeSessionId + ")");
-               } catch (InvalidSyntaxException e) {
-                       throw new CmsException("Cannot retrieve CMS session #" + nodeSessionId, e);
-               }
-
-               if (srs.size() == 0) {
-                       // if (log.isTraceEnabled())
-                       // log.warn("No CMS web session found for http session " +
-                       // nodeSessionId);
-                       return false;
-               } else if (srs.size() > 1)
-                       throw new CmsException(srs.size() + " CMS web sessions found for http session " + nodeSessionId);
-
-               WebCmsSessionImpl cmsSession = (WebCmsSessionImpl) bc.getService(srs.iterator().next());
-               cmsSession.cleanUp();
-//             subject.getPrivateCredentials().removeAll(subject.getPrivateCredentials(CmsSessionId.class));
+               CmsSessionImpl cmsSession = (CmsSessionImpl) CmsSessionImpl.getByUuid(nodeSessionId.toString());
+               cmsSession.close();
+               // Collection<ServiceReference<CmsSession>> srs;
+               // try {
+               // srs = bc.getServiceReferences(CmsSession.class, "(" +
+               // CmsSession.SESSION_UUID + "=" + nodeSessionId + ")");
+               // } catch (InvalidSyntaxException e) {
+               // throw new CmsException("Cannot retrieve CMS session #" +
+               // nodeSessionId, e);
+               // }
+               //
+               // if (srs.size() == 0) {
+               // // if (log.isTraceEnabled())
+               // // log.warn("No CMS web session found for http session " +
+               // // nodeSessionId);
+               // return false;
+               // } else if (srs.size() > 1)
+               // throw new CmsException(srs.size() + " CMS web sessions found for http
+               // session " + nodeSessionId);
+               //
+               // WebCmsSessionImpl cmsSession = (WebCmsSessionImpl)
+               // bc.getService(srs.iterator().next());
+//             cmsSession.cleanUp();
+               // subject.getPrivateCredentials().removeAll(subject.getPrivateCredentials(CmsSessionId.class));
                if (log.isDebugEnabled())
                        log.debug("Logged out CMS session " + cmsSession.getUuid());
                return true;
index ce004c58e86762e5937f4d8bae1aa8e509fe2cc4..9cf32974f536f62f50dc46b65f285cfde94a29eb 100644 (file)
@@ -68,7 +68,7 @@ public class HttpSessionLoginModule implements LoginModule {
                        return false;
                authorization = (Authorization) request.getAttribute(HttpContext.AUTHORIZATION);
                if (authorization == null) {// search by session ID
-                       String httpSessionId = request.getSession().getId();
+                       String httpSessionId = request.getSession(false).getId();
                        // authorization = (Authorization)
                        // request.getSession().getAttribute(HttpContext.AUTHORIZATION);
                        // if (authorization == null) {
index 237e074218ededa12e7d61c696adb550f1f1e32c..7e95c951a3f8eb67f80f1970feda3712b5fcdbfb 100644 (file)
@@ -187,8 +187,8 @@ public class UserAdminLoginModule implements LoginModule {
 
        @Override
        public boolean logout() throws LoginException {
-               if (log.isDebugEnabled())
-                       log.debug("Logging out from CMS... " + subject);
+               if (log.isTraceEnabled())
+                       log.trace("Logging out from CMS... " + subject);
                // boolean httpSessionLogoutOk = CmsAuthUtils.logoutSession(bc,
                // subject);
                CmsAuthUtils.cleanUp(subject);
index 0b35d1d64a8dcbc24d03a15bd7edcf4ff1376d86..af29d25945c9eb6b34a084b31f0b6a48b892b83f 100644 (file)
@@ -4,6 +4,7 @@ import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.security.PrivilegedExceptionAction;
+import java.time.ZonedDateTime;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -18,12 +19,15 @@ import javax.jcr.Session;
 import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
 import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.cms.CmsException;
 import org.argeo.cms.auth.CmsSession;
 import org.argeo.jcr.JcrUtils;
+import org.argeo.node.NodeConstants;
 import org.argeo.node.security.NodeSecurityUtils;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
@@ -44,6 +48,9 @@ public class CmsSessionImpl implements CmsSession {
        private final LdapName userDn;
        private final boolean anonymous;
 
+       private final ZonedDateTime creationTime;
+       private ZonedDateTime end;
+
        private ServiceRegistration<CmsSession> serviceRegistration;
 
        private Map<String, Session> dataSessions = new HashMap<>();
@@ -51,6 +58,7 @@ public class CmsSessionImpl implements CmsSession {
        private LinkedHashSet<Session> additionalDataSessions = new LinkedHashSet<>();
 
        public CmsSessionImpl(Subject initialSubject, Authorization authorization, String localSessionId) {
+               this.creationTime = ZonedDateTime.now();
                this.initialContext = Subject.doAs(initialSubject, new PrivilegedAction<AccessControlContext>() {
 
                        @Override
@@ -82,7 +90,8 @@ public class CmsSessionImpl implements CmsSession {
                serviceRegistration = bc.registerService(CmsSession.class, this, props);
        }
 
-       public synchronized void cleanUp() {
+       public synchronized void close() {
+               end = ZonedDateTime.now();
                serviceRegistration.unregister();
 
                // TODO check data session in use ?
@@ -90,10 +99,25 @@ public class CmsSessionImpl implements CmsSession {
                        JcrUtils.logoutQuietly(dataSessions.get(path));
                for (Session session : additionalDataSessions)
                        JcrUtils.logoutQuietly(session);
+
+               try {
+                       LoginContext lc;
+                       if (isAnonymous()) {
+                               lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS, getSubject());
+                       } else {
+                               lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, getSubject());
+                       }
+                       lc.logout();
+               } catch (LoginException e) {
+                       log.warn("Could not logout " + getSubject() + ": " + e);
+               }
                notifyAll();
        }
 
-       @Override
+       private Subject getSubject() {
+               return Subject.getSubject(initialContext);
+       }
+
        public synchronized Session getDataSession(String cn, String workspace, Repository repository) {
                // FIXME make it more robust
                if (workspace == null)
@@ -129,8 +153,7 @@ public class CmsSessionImpl implements CmsSession {
 
        private Session login(Repository repository, String workspace) {
                try {
-                       Subject initialSubject = Subject.getSubject(initialContext);
-                       return Subject.doAs(initialSubject, new PrivilegedExceptionAction<Session>() {
+                       return Subject.doAs(getSubject(), new PrivilegedExceptionAction<Session>() {
                                @Override
                                public Session run() throws Exception {
                                        return repository.login(workspace);
@@ -141,7 +164,6 @@ public class CmsSessionImpl implements CmsSession {
                }
        }
 
-       @Override
        public synchronized void releaseDataSession(String cn, Session session) {
                if (additionalDataSessions.contains(session)) {
                        JcrUtils.logoutQuietly(session);
@@ -158,6 +180,15 @@ public class CmsSessionImpl implements CmsSession {
                notifyAll();
        }
 
+       @Override
+       public boolean isValid() {
+               return !isClosed();
+       }
+
+       protected boolean isClosed() {
+               return getEnd() != null;
+       }
+
        @Override
        public Authorization getAuthorization() {
                return authorization;
@@ -190,6 +221,16 @@ public class CmsSessionImpl implements CmsSession {
                return anonymous;
        }
 
+       @Override
+       public ZonedDateTime getCreationTime() {
+               return creationTime;
+       }
+
+       @Override
+       public ZonedDateTime getEnd() {
+               return end;
+       }
+
        public String toString() {
                return "CMS Session " + userDn + " local=" + localSessionId + ", uuid=" + uuid;
        }
@@ -229,4 +270,21 @@ public class CmsSessionImpl implements CmsSession {
                        throw new CmsException(sr.size() + " CMS sessions registered for " + uuid);
 
        }
+
+       public static void closeInvalidSessions() {
+               Collection<ServiceReference<CmsSession>> srs;
+               try {
+                       srs = bc.getServiceReferences(CmsSession.class, null);
+                       for (ServiceReference<CmsSession> sr : srs) {
+                               CmsSession cmsSession = bc.getService(sr);
+                               if (!cmsSession.isValid()) {
+                                       ((CmsSessionImpl) cmsSession).close();
+                                       if (log.isDebugEnabled())
+                                               log.debug("Closed expired CMS session " + cmsSession);
+                               }
+                       }
+               } catch (InvalidSyntaxException e) {
+                       throw new CmsException("Cannot get CMS sessions", e);
+               }
+       }
 }
index 37ba5cdb15332a440e1dac222ecaf7ed16d1db28..85390e62eeb414d9c0918ca6de106826da09c8bc 100644 (file)
@@ -12,7 +12,7 @@ import javax.servlet.http.HttpServletRequest;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.jackrabbit.server.SessionProvider;
-import org.argeo.cms.auth.CmsSession;
+import org.argeo.cms.internal.auth.CmsSessionImpl;
 import org.argeo.jcr.JcrUtils;
 
 /**
@@ -26,7 +26,7 @@ class CmsSessionProvider implements SessionProvider, Serializable {
 
        private final String alias;
 
-       private LinkedHashMap<Session, CmsSession> cmsSessions = new LinkedHashMap<>();
+       private LinkedHashMap<Session, CmsSessionImpl> cmsSessions = new LinkedHashMap<>();
 
        public CmsSessionProvider(String alias) {
                this.alias = alias;
@@ -35,9 +35,9 @@ class CmsSessionProvider implements SessionProvider, Serializable {
        public Session getSession(HttpServletRequest request, Repository rep, String workspace)
                        throws javax.jcr.LoginException, ServletException, RepositoryException {
 
-               CmsSession cmsSession = WebCmsSessionImpl.getCmsSession(request);
-//             if (cmsSession == null)
-//                     return anonymousSession(request, rep, workspace);
+               CmsSessionImpl cmsSession = (CmsSessionImpl) WebCmsSessionImpl.getCmsSession(request);
+               // if (cmsSession == null)
+               // return anonymousSession(request, rep, workspace);
                if (log.isTraceEnabled()) {
                        log.debug("Get JCR session from " + cmsSession);
                }
@@ -46,32 +46,35 @@ class CmsSessionProvider implements SessionProvider, Serializable {
                return session;
        }
 
-//     private synchronized Session anonymousSession(HttpServletRequest request, Repository repository, String workspace) {
-//             // TODO rather log in here as anonymous?
-//             LoginContext lc = (LoginContext) request.getAttribute(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
-//             if (lc == null)
-//                     throw new CmsException("No login context available");
-//             // optimize
-//             Session session;
-//             try {
-//                     session = Subject.doAs(lc.getSubject(), new PrivilegedExceptionAction<Session>() {
-//                             @Override
-//                             public Session run() throws Exception {
-//                                     return repository.login(workspace);
-//                             }
-//                     });
-//             } catch (Exception e) {
-//                     throw new CmsException("Cannot log in to JCR", e);
-//             }
-//             return session;
-//     }
+       // private synchronized Session anonymousSession(HttpServletRequest request,
+       // Repository repository, String workspace) {
+       // // TODO rather log in here as anonymous?
+       // LoginContext lc = (LoginContext)
+       // request.getAttribute(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
+       // if (lc == null)
+       // throw new CmsException("No login context available");
+       // // optimize
+       // Session session;
+       // try {
+       // session = Subject.doAs(lc.getSubject(), new
+       // PrivilegedExceptionAction<Session>() {
+       // @Override
+       // public Session run() throws Exception {
+       // return repository.login(workspace);
+       // }
+       // });
+       // } catch (Exception e) {
+       // throw new CmsException("Cannot log in to JCR", e);
+       // }
+       // return session;
+       // }
 
        public synchronized void releaseSession(Session session) {
                if (cmsSessions.containsKey(session)) {
-                       CmsSession cmsSession = cmsSessions.get(session);
+                       CmsSessionImpl cmsSession = cmsSessions.get(session);
                        cmsSession.releaseDataSession(alias, session);
                } else {
-                       log.warn("JCR session "+session+" not found in CMS session list. Logging it out...");
+                       log.warn("JCR session " + session + " not found in CMS session list. Logging it out...");
                        JcrUtils.logoutQuietly(session);
                }
        }
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/http/HttpFilter.java b/org.argeo.cms/src/org/argeo/cms/internal/http/HttpFilter.java
deleted file mode 100644 (file)
index 142bccb..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.argeo.cms.internal.http;
-
-import java.io.IOException;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-/** Abstract base class for http filters. */
-abstract class HttpFilter implements Filter {
-       // private final static Log log = LogFactory.getLog(HttpFilter.class);
-
-       protected abstract void doFilter(HttpSession httpSession,
-                       HttpServletRequest request, HttpServletResponse response,
-                       FilterChain filterChain) throws IOException, ServletException;
-
-       @Override
-       public void doFilter(ServletRequest servletRequest,
-                       ServletResponse servletResponse, FilterChain filterChain)
-                       throws IOException, ServletException {
-               HttpServletRequest request = (HttpServletRequest) servletRequest;
-               doFilter(request.getSession(), request,
-                               (HttpServletResponse) servletResponse, filterChain);
-       }
-
-       @Override
-       public void destroy() {
-       }
-
-       @Override
-       public void init(FilterConfig arg0) throws ServletException {
-       }
-
-}
index 06ff57355d0b92ac3b42bb14acc514d163b45492..3d5e3fe4c612d65781e5fe8196078dc4c05cafcb 100644 (file)
@@ -2,21 +2,36 @@ package org.argeo.cms.internal.http;
 
 import javax.security.auth.Subject;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
 
 import org.argeo.cms.auth.CmsSession;
 import org.argeo.cms.internal.auth.CmsSessionImpl;
 import org.osgi.service.useradmin.Authorization;
 
 public class WebCmsSessionImpl extends CmsSessionImpl {
+       // private final static Log log =
+       // LogFactory.getLog(WebCmsSessionImpl.class);
 
-       public WebCmsSessionImpl(Subject initialSubject, Authorization authorization, String httpSessionId) {
-               super(initialSubject, authorization, httpSessionId);
+       private HttpSession httpSession;
+
+       public WebCmsSessionImpl(Subject initialSubject, Authorization authorization, HttpServletRequest request) {
+               super(initialSubject, authorization, request.getSession(false).getId());
+               httpSession = request.getSession(false);
+       }
+
+       @Override
+       public boolean isValid() {
+               if (isClosed())
+                       return false;
+               try {// test http session
+                       httpSession.getCreationTime();
+                       return true;
+               } catch (IllegalStateException ise) {
+                       return false;
+               }
        }
 
        public static CmsSession getCmsSession(HttpServletRequest request) {
-//             CmsSession cmsSession = (CmsSession) request.getAttribute(CmsSession.class.getName());
-//             if (cmsSession != null)
-//                     return cmsSession;
-               return CmsSessionImpl.getByLocalId(request.getSession().getId());
+               return CmsSessionImpl.getByLocalId(request.getSession(false).getId());
        }
 }
index 944a7cd3dbcf3bd42b59afdc37ce535c49bff558..5ebf4055fb2dce6e6d66e0392b8ef223d519be4c 100644 (file)
@@ -8,6 +8,7 @@ import org.apache.commons.logging.LogFactory;
 import org.apache.jackrabbit.api.stats.RepositoryStatistics;
 import org.apache.jackrabbit.stats.RepositoryStatisticsImpl;
 import org.argeo.cms.CmsException;
+import org.argeo.cms.internal.auth.CmsSessionImpl;
 
 /**
  * Background thread started by the {@link Kernel}, which gather statistics and
@@ -35,6 +36,9 @@ class KernelThread extends Thread {
        }
 
        private void doSmallestPeriod() {
+               // Clean expired sessions
+               CmsSessionImpl.closeInvalidSessions();
+
                if (kernelStatsLog.isDebugEnabled()) {
                        StringBuilder line = new StringBuilder(64);
                        line.append("ยง\t");
index e92e2a40216f02b35a82a1e865f25643ed87e2b1..0a90e64a520eb7e81f405f3fffa2aceb7a093ba7 100644 (file)
@@ -54,7 +54,7 @@ public class ResourceProxyServlet extends HttpServlet {
                if (log.isTraceEnabled()) {
                        log.trace("path=" + path);
                        log.trace("UserPrincipal = " + request.getUserPrincipal().getName());
-                       log.trace("SessionID = " + request.getSession().getId());
+                       log.trace("SessionID = " + request.getSession(false).getId());
                        log.trace("ContextPath = " + request.getContextPath());
                        log.trace("ServletPath = " + request.getServletPath());
                        log.trace("PathInfo = " + request.getPathInfo());
diff --git a/org.argeo.node.api/src/org/argeo/node/security/NodeAuthenticated.java b/org.argeo.node.api/src/org/argeo/node/security/NodeAuthenticated.java
deleted file mode 100644 (file)
index a316af5..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.argeo.node.security;
-
-import javax.security.auth.login.LoginContext;
-
-public interface NodeAuthenticated {
-       String KEY = "org.argeo.node.authenticated";
-
-//     Subject getSubject();
-       LoginContext getLoginContext();
-
-}
index fae6312343d0b99c267298bbecdf8567c6228fc8..b791f490d10dbf1146450d3b17a7eeac08927bdc 100644 (file)
@@ -7,6 +7,9 @@ import java.io.Writer;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.Hashtable;
@@ -157,6 +160,30 @@ public class LangUtils {
                        chainCauseMessage(buf, t.getCause());
        }
 
+       /*
+        * TIME
+        */
+       /** Formats time elapsed since start. */
+       public static String since(ZonedDateTime start) {
+               ZonedDateTime now = ZonedDateTime.now();
+               return duration(start, now);
+       }
+
+       /** Formats a duration. */
+       public static String duration(Temporal start, Temporal end) {
+               long count = ChronoUnit.DAYS.between(start, end);
+               if (count != 0)
+                       return count > 1 ? count + " days" : count + " day";
+               count = ChronoUnit.HOURS.between(start, end);
+               if (count != 0)
+                       return count > 1 ? count + " hours" : count + " hours";
+               count = ChronoUnit.MINUTES.between(start, end);
+               if (count != 0)
+                       return count > 1 ? count + " minutes" : count + " minute";
+               count = ChronoUnit.SECONDS.between(start, end);
+               return count > 1 ? count + " seconds" : count + " second";
+       }
+
        /** Singleton constructor. */
        private LangUtils() {