Introduce CMS sessions monitoring view.
-log4j.rootLogger=WARN, console
+log4j.rootLogger=WARN, development
log4j.logger.org.argeo=DEBUG
log4j.logger.org.argeo.cms.internal=TRACE
@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()");
@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()");
<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"
--- /dev/null
+//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) {
+ }
+ }
+}
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;
// 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);
@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 {
// return subject;
// }
- @Override
- public LoginContext getLoginContext() {
- return loginContext;
+ // @Override
+ // public LoginContext getLoginContext() {
+ // return loginContext;
+ // }
+ public Subject getSubject() {
+ return loginContext.getSubject();
}
@Override
}
@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() {
}
});
-
}
@Override
}
protected synchronized void doRefresh() {
- Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
+ Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
@Override
public Void run() {
refresh();
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
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;
* this call.
*/
public static CmsView getCmsView() {
- return UiContext.getData(NodeAuthenticated.KEY);
+ return UiContext.getData(CmsAuthenticated.KEY);
}
public static StringBuilder getServerBaseUrl(HttpServletRequest request) {
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;
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;
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
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())
@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;
}
}
- @Override
- public LoginContext getLoginContext() {
- return loginContext;
+ // @Override
+ // public LoginContext getLoginContext() {
+ // return loginContext;
+ // }
+
+ public Subject getSubject() {
+ return loginContext.getSubject();
}
@Override
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;
}
protected boolean isAnonymous() {
- return CurrentUser.isAnonymous(cmsView.getLoginContext().getSubject());
+ return CurrentUser.isAnonymous(cmsView.getSubject());
}
public final void createUi(Composite parent) {
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);
// log.error("Cannot login", e);
// return false;
// }
- cmsView.authChange(loginContext);
- return true;
}
protected void logout() {
@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;
}
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()
} 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)
--- /dev/null
+package org.argeo.cms.auth;
+
+import javax.security.auth.Subject;
+
+public interface CmsAuthenticated {
+ String KEY = "org.argeo.cms.authenticated";
+
+ Subject getSubject();
+// LoginContext getLoginContext();
+
+}
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);
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;
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;
/**
*/
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
*/
*/
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;
* 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) {
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;
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) {
@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);
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;
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;
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<>();
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
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 ?
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)
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);
}
}
- @Override
public synchronized void releaseDataSession(String cn, Session session) {
if (additionalDataSessions.contains(session)) {
JcrUtils.logoutQuietly(session);
notifyAll();
}
+ @Override
+ public boolean isValid() {
+ return !isClosed();
+ }
+
+ protected boolean isClosed() {
+ return getEnd() != null;
+ }
+
@Override
public Authorization getAuthorization() {
return authorization;
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;
}
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);
+ }
+ }
}
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;
/**
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;
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);
}
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);
}
}
+++ /dev/null
-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 {
- }
-
-}
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());
}
}
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
}
private void doSmallestPeriod() {
+ // Clean expired sessions
+ CmsSessionImpl.closeInvalidSessions();
+
if (kernelStatsLog.isDebugEnabled()) {
StringBuilder line = new StringBuilder(64);
line.append("ยง\t");
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());
+++ /dev/null
-package org.argeo.node.security;
-
-import javax.security.auth.login.LoginContext;
-
-public interface NodeAuthenticated {
- String KEY = "org.argeo.node.authenticated";
-
-// Subject getSubject();
- LoginContext getLoginContext();
-
-}
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;
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() {