Massive Argeo APIs refactoring
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / auth / CmsSessionImpl.java
index 211f21c94ead35175e5e730dee0348765f93c3da..b0824e84bb1924835d0232c1691a7609d8de1807 100644 (file)
@@ -1,36 +1,30 @@
 package org.argeo.cms.internal.auth;
 
+import java.io.Serializable;
 import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
 import java.time.ZonedDateTime;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Hashtable;
-import java.util.LinkedHashSet;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 
 import javax.crypto.SecretKey;
-import javax.jcr.Repository;
-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 javax.security.auth.x500.X500Principal;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.api.NodeConstants;
-import org.argeo.api.security.NodeSecurityUtils;
-import org.argeo.cms.auth.CmsSession;
-import org.argeo.jcr.JcrUtils;
+import org.argeo.api.cms.CmsSession;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.security.NodeSecurityUtils;
+import org.argeo.api.cms.CmsAuth;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
@@ -38,15 +32,17 @@ import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.useradmin.Authorization;
 
-public class CmsSessionImpl implements CmsSession {
+/** Default CMS session implementation. */
+public class CmsSessionImpl implements CmsSession, Serializable {
+       private static final long serialVersionUID = 1867719354246307225L;
        private final static BundleContext bc = FrameworkUtil.getBundle(CmsSessionImpl.class).getBundleContext();
-       private final static Log log = LogFactory.getLog(CmsSessionImpl.class);
+       private final static CmsLog log = CmsLog.getLog(CmsSessionImpl.class);
 
        // private final Subject initialSubject;
-       private final AccessControlContext initialContext;
+       private transient AccessControlContext accessControlContext;
        private final UUID uuid;
        private final String localSessionId;
-       private final Authorization authorization;
+       private Authorization authorization;
        private final LdapName userDn;
        private final boolean anonymous;
 
@@ -56,16 +52,12 @@ public class CmsSessionImpl implements CmsSession {
 
        private ServiceRegistration<CmsSession> serviceRegistration;
 
-       private Map<String, Session> dataSessions = new HashMap<>();
-       private Set<String> dataSessionsInUse = new HashSet<>();
-       private LinkedHashSet<Session> additionalDataSessions = new LinkedHashSet<>();
-
        private Map<String, Object> views = new HashMap<>();
 
        public CmsSessionImpl(Subject initialSubject, Authorization authorization, Locale locale, String localSessionId) {
                this.creationTime = ZonedDateTime.now();
                this.locale = locale;
-               this.initialContext = Subject.doAs(initialSubject, new PrivilegedAction<AccessControlContext>() {
+               this.accessControlContext = Subject.doAs(initialSubject, new PrivilegedAction<AccessControlContext>() {
 
                        @Override
                        public AccessControlContext run() {
@@ -100,120 +92,55 @@ public class CmsSessionImpl implements CmsSession {
                end = ZonedDateTime.now();
                serviceRegistration.unregister();
 
-               synchronized (this) {
-                       // TODO check data session in use ?
-                       for (String path : dataSessions.keySet())
-                               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());
+                               lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS, getSubject());
                        } else {
-                               lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, getSubject());
+                               lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_USER, getSubject());
                        }
                        lc.logout();
                } catch (LoginException e) {
                        log.warn("Could not logout " + getSubject() + ": " + e);
+               } finally {
+                       accessControlContext = null;
                }
                log.debug("Closed " + this);
        }
 
-       private Subject getSubject() {
-               return Subject.getSubject(initialContext);
+       public Subject getSubject() {
+               return Subject.getSubject(accessControlContext);
        }
 
        public Set<SecretKey> getSecretKeys() {
+               checkValid();
                return getSubject().getPrivateCredentials(SecretKey.class);
        }
 
-       public Session newDataSession(String cn, String workspace, Repository repository) {
-               return login(repository, workspace);
-       }
-
-       public synchronized Session getDataSession(String cn, String workspace, Repository repository) {
-               // FIXME make it more robust
-               if (workspace == null)
-                       workspace = NodeConstants.SYS_WORKSPACE;
-               String path = cn + '/' + workspace;
-               if (dataSessionsInUse.contains(path)) {
-                       try {
-                               wait(1000);
-                               if (dataSessionsInUse.contains(path)) {
-                                       Session session = login(repository, workspace);
-                                       additionalDataSessions.add(session);
-                                       if (log.isTraceEnabled())
-                                               log.trace("Additional data session " + path + " for " + userDn);
-                                       return session;
-                               }
-                       } catch (InterruptedException e) {
-                               // silent
-                       }
-               }
-
-               Session session = null;
-               if (dataSessions.containsKey(path)) {
-                       session = dataSessions.get(path);
-               } else {
-                       session = login(repository, workspace);
-                       dataSessions.put(path, session);
-                       if (log.isTraceEnabled())
-                               log.trace("New data session " + path + " for " + userDn);
-               }
-               dataSessionsInUse.add(path);
-               return session;
-       }
-
-       private Session login(Repository repository, String workspace) {
-               try {
-                       return Subject.doAs(getSubject(), new PrivilegedExceptionAction<Session>() {
-                               @Override
-                               public Session run() throws Exception {
-                                       return repository.login(workspace);
-                               }
-                       });
-               } catch (PrivilegedActionException e) {
-                       throw new IllegalStateException("Cannot log in " + userDn + " to JCR", e);
-               }
-       }
-
-       public synchronized void releaseDataSession(String cn, Session session) {
-               if (additionalDataSessions.contains(session)) {
-                       JcrUtils.logoutQuietly(session);
-                       additionalDataSessions.remove(session);
-                       if (log.isTraceEnabled())
-                               log.trace("Remove additional data session " + session);
-                       return;
-               }
-               String path = cn + '/' + session.getWorkspace().getName();
-               if (!dataSessionsInUse.contains(path))
-                       log.warn("Data session " + path + " was not in use for " + userDn);
-               dataSessionsInUse.remove(path);
-               Session registeredSession = dataSessions.get(path);
-               if (session != registeredSession)
-                       log.warn("Data session " + path + " not consistent for " + userDn);
-               if (log.isTraceEnabled())
-                       log.trace("Released data session " + session + " for " + path);
-               notifyAll();
-       }
-
        @Override
        public boolean isValid() {
                return !isClosed();
        }
 
-       protected boolean isClosed() {
+       private void checkValid() {
+               if (!isValid())
+                       throw new IllegalStateException("CMS session " + uuid + " is not valid since " + end);
+       }
+
+       final protected boolean isClosed() {
                return getEnd() != null;
        }
 
-       @Override
        public Authorization getAuthorization() {
+               checkValid();
                return authorization;
        }
 
+       @Override
+       public String getDisplayName() {
+               return authorization.toString();
+       }
+
        @Override
        public UUID getUuid() {
                return uuid;
@@ -224,6 +151,11 @@ public class CmsSessionImpl implements CmsSession {
                return userDn;
        }
 
+       @Override
+       public String getUserRole() {
+               return new X500Principal(authorization.getName()).getName();
+       }
+
        @Override
        public String getLocalId() {
                return localSessionId;
@@ -251,6 +183,7 @@ public class CmsSessionImpl implements CmsSession {
 
        @Override
        public void registerView(String uid, Object view) {
+               checkValid();
                if (views.containsKey(uid))
                        throw new IllegalArgumentException("View " + uid + " is already registered.");
                views.put(uid, view);