]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - org.argeo.cms/src/org/argeo/cms/internal/auth/CmsSessionImpl.java
Improve remote authentication
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / auth / CmsSessionImpl.java
index 734b874efff24743c9dc998f5c6aab0db9d67f16..dfedfab1968f02a474bc073f3c7f15914ee810c2 100644 (file)
 package org.argeo.cms.internal.auth;
 
 import java.io.Serializable;
-import java.security.AccessControlContext;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import java.time.ZonedDateTime;
-import java.util.Collection;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
-import java.util.Hashtable;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Set;
+import java.util.Objects;
 import java.util.UUID;
+import java.util.function.Consumer;
 
-import javax.crypto.SecretKey;
-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.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
+import org.argeo.api.cms.CmsAuth;
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.CmsSession;
+import org.argeo.cms.internal.runtime.CmsContextImpl;
 import org.osgi.service.useradmin.Authorization;
 
 /** 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 transient AccessControlContext accessControlContext;
+       private transient Subject subject;
        private final UUID uuid;
        private final String localSessionId;
        private Authorization authorization;
-       private final LdapName userDn;
+//     private final LdapName userDn;
+       private final String userDn;
        private final boolean anonymous;
 
        private final ZonedDateTime creationTime;
        private ZonedDateTime end;
        private final Locale locale;
 
-       private ServiceRegistration<CmsSession> serviceRegistration;
-
        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.accessControlContext = Subject.doAs(initialSubject, new PrivilegedAction<AccessControlContext>() {
+       private List<Consumer<CmsSession>> onCloseCallbacks = Collections.synchronizedList(new ArrayList<>());
 
-                       @Override
-                       public AccessControlContext run() {
-                               return AccessController.getContext();
-                       }
+       public CmsSessionImpl(UUID uuid, Subject initialSubject, Authorization authorization, Locale locale,
+                       String localSessionId) {
+               Objects.requireNonNull(uuid);
 
-               });
-               // this.initialSubject = initialSubject;
+               this.creationTime = ZonedDateTime.now();
+               this.locale = locale;
+               this.subject = initialSubject;
                this.localSessionId = localSessionId;
                this.authorization = authorization;
-               if (authorization.getName() != null)
-                       try {
-                               this.userDn = new LdapName(authorization.getName());
-                               this.anonymous = false;
-                       } catch (InvalidNameException e) {
-                               throw new IllegalArgumentException("Invalid user name " + authorization.getName(), e);
-                       }
-               else {
-                       this.userDn = NodeSecurityUtils.ROLE_ANONYMOUS_NAME;
+               if (authorization.getName() != null) {
+                       this.userDn = authorization.getName();
+                       this.anonymous = false;
+               } else {
+                       this.userDn = CmsConstants.ROLE_ANONYMOUS;
                        this.anonymous = true;
                }
-               this.uuid = UUID.randomUUID();
-               // register as service
-               Hashtable<String, String> props = new Hashtable<>();
-               props.put(CmsSession.USER_DN, userDn.toString());
-               props.put(CmsSession.SESSION_UUID, uuid.toString());
-               props.put(CmsSession.SESSION_LOCAL_ID, localSessionId);
-               serviceRegistration = bc.registerService(CmsSession.class, this, props);
+               this.uuid = uuid;
        }
 
        public void close() {
                end = ZonedDateTime.now();
-               serviceRegistration.unregister();
+               CmsContextImpl.getCmsContext().unregisterCmsSession(this);
+//             serviceRegistration.unregister();
 
+               for (Consumer<CmsSession> onClose : onCloseCallbacks) {
+                       onClose.accept(this);
+               }
 
                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;
+                       subject = null;
                }
                log.debug("Closed " + this);
        }
 
-       public Subject getSubject() {
-               return Subject.getSubject(accessControlContext);
+       @Override
+       public void addOnCloseCallback(Consumer<CmsSession> onClose) {
+               onCloseCallbacks.add(onClose);
        }
 
-       public Set<SecretKey> getSecretKeys() {
-               checkValid();
-               return getSubject().getPrivateCredentials(SecretKey.class);
+       public Subject getSubject() {
+               return subject;
        }
 
+//     public Set<SecretKey> getSecretKeys() {
+//             checkValid();
+//             return getSubject().getPrivateCredentials(SecretKey.class);
+//     }
+
        @Override
        public boolean isValid() {
                return !isClosed();
@@ -133,19 +117,23 @@ public class CmsSessionImpl implements CmsSession, Serializable {
                return getEnd() != null;
        }
 
-       @Override
        public Authorization getAuthorization() {
                checkValid();
                return authorization;
        }
 
+       @Override
+       public String getDisplayName() {
+               return authorization.toString();
+       }
+
        @Override
        public UUID getUuid() {
                return uuid;
        }
 
        @Override
-       public LdapName getUserDn() {
+       public String getUserDn() {
                return userDn;
        }
 
@@ -188,59 +176,6 @@ public class CmsSessionImpl implements CmsSession, Serializable {
        }
 
        public String toString() {
-               return "CMS Session " + userDn + " local=" + localSessionId + ", uuid=" + uuid;
-       }
-
-       public static CmsSessionImpl getByLocalId(String localId) {
-               Collection<ServiceReference<CmsSession>> sr;
-               try {
-                       sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_LOCAL_ID + "=" + localId + ")");
-               } catch (InvalidSyntaxException e) {
-                       throw new IllegalArgumentException("Cannot get CMS session for id " + localId, e);
-               }
-               ServiceReference<CmsSession> cmsSessionRef;
-               if (sr.size() == 1) {
-                       cmsSessionRef = sr.iterator().next();
-                       return (CmsSessionImpl) bc.getService(cmsSessionRef);
-               } else if (sr.size() == 0) {
-                       return null;
-               } else
-                       throw new IllegalStateException(sr.size() + " CMS sessions registered for " + localId);
-
-       }
-
-       public static CmsSessionImpl getByUuid(Object uuid) {
-               Collection<ServiceReference<CmsSession>> sr;
-               try {
-                       sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_UUID + "=" + uuid + ")");
-               } catch (InvalidSyntaxException e) {
-                       throw new IllegalArgumentException("Cannot get CMS session for uuid " + uuid, e);
-               }
-               ServiceReference<CmsSession> cmsSessionRef;
-               if (sr.size() == 1) {
-                       cmsSessionRef = sr.iterator().next();
-                       return (CmsSessionImpl) bc.getService(cmsSessionRef);
-               } else if (sr.size() == 0) {
-                       return null;
-               } else
-                       throw new IllegalStateException(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 IllegalArgumentException("Cannot get CMS sessions", e);
-               }
+               return "CMS Session " + userDn + " localId=" + localSessionId + ", uuid=" + uuid;
        }
 }