Improve CMS security layer documentation.
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 20 Jan 2021 07:18:24 +0000 (08:18 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 20 Jan 2021 07:18:24 +0000 (08:18 +0100)
14 files changed:
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/CmsSessionId.java
org.argeo.cms/src/org/argeo/cms/auth/CurrentUser.java
org.argeo.cms/src/org/argeo/cms/auth/HttpRequestCallback.java
org.argeo.cms/src/org/argeo/cms/auth/HttpSessionLoginModule.java
org.argeo.cms/src/org/argeo/cms/auth/SingleUserAuthorization.java
org.argeo.cms/src/org/argeo/cms/auth/SingleUserLoginModule.java
org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java
org.argeo.cms/src/org/argeo/cms/auth/UserAdminUtils.java
org.argeo.cms/src/org/argeo/cms/internal/auth/CmsSessionImpl.java
org.argeo.cms/src/org/argeo/cms/internal/auth/ConsoleCallbackHandler.java
org.argeo.cms/src/org/argeo/cms/internal/auth/ImpliedByPrincipal.java
org.argeo.cms/src/org/argeo/cms/internal/http/WebCmsSessionImpl.java

index e91fd6033be2623557f38a14bca1b70a309b21e7..1d24be7ade914c45b4e862ca9fe310844c83cb3c 100644 (file)
@@ -11,7 +11,6 @@ import javax.servlet.http.HttpServletRequest;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.service.useradmin.Authorization;
@@ -37,7 +36,7 @@ public class AnonymousLoginModule implements LoginModule {
                        bc = FrameworkUtil.getBundle(AnonymousLoginModule.class).getBundleContext();
                        assert bc != null;
                } catch (Exception e) {
-                       throw new CmsException("Cannot initialize login module", e);
+                       throw new IllegalStateException("Cannot initialize login module", e);
                }
        }
 
@@ -63,7 +62,6 @@ public class AnonymousLoginModule implements LoginModule {
 
        @Override
        public boolean abort() throws LoginException {
-               // authorization = null;
                return true;
        }
 
index 5e59187e0dad574a1283970aca39d851cf618342..e9462c3add31cb7dbd0ef16f48afb00e2225a611 100644 (file)
@@ -17,10 +17,6 @@ import org.argeo.api.NodeConstants;
 import org.argeo.api.security.AnonymousPrincipal;
 import org.argeo.api.security.DataAdminPrincipal;
 import org.argeo.api.security.NodeSecurityUtils;
-//import org.apache.jackrabbit.core.security.AnonymousPrincipal;
-//import org.apache.jackrabbit.core.security.SecurityConstants;
-//import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
-import org.argeo.cms.CmsException;
 import org.argeo.cms.internal.auth.CmsSessionImpl;
 import org.argeo.cms.internal.auth.ImpliedByPrincipal;
 import org.argeo.cms.internal.http.WebCmsSessionImpl;
@@ -32,6 +28,7 @@ import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.HttpContext;
 import org.osgi.service.useradmin.Authorization;
 
+/** Centrlaises security related registrations. */
 class CmsAuthUtils {
        // Standard
        final static String SHARED_STATE_NAME = AuthenticatingUser.SHARED_STATE_NAME;
@@ -75,8 +72,6 @@ class CmsAuthUtils {
                                NodeSecurityUtils.checkUserName(name);
                                userPrincipal = new X500Principal(name.toString());
                                principals.add(userPrincipal);
-                               // principals.add(new ImpliedByPrincipal(NodeSecurityUtils.ROLE_USER_NAME,
-                               // userPrincipal));
 
                                if (Activator.isSingleUser()) {
                                        principals.add(new ImpliedByPrincipal(NodeSecurityUtils.ROLE_ADMIN_NAME, userPrincipal));
@@ -99,10 +94,8 @@ class CmsAuthUtils {
                        }
 
                } catch (InvalidNameException e) {
-                       throw new CmsException("Cannot commit", e);
+                       throw new IllegalArgumentException("Cannot commit", e);
                }
-
-               // registerSessionAuthorization(request, subject, authorization, locale);
        }
 
        private static void checkSubjectEmpty(Subject subject) {
@@ -150,7 +143,7 @@ class CmsAuthUtils {
                                                cmsSession.close();
                                                cmsSession = null;
                                        } else if (!authorization.getName().equals(cmsSession.getAuthorization().getName())) {
-                                               throw new CmsException("Inconsistent user " + authorization.getName()
+                                               throw new IllegalStateException("Inconsistent user " + authorization.getName()
                                                                + " for existing CMS session " + cmsSession);
                                        }
                                        // keyring
@@ -175,7 +168,7 @@ class CmsAuthUtils {
                                        UUID storedSessionId = subject.getPrivateCredentials(CmsSessionId.class).iterator().next()
                                                        .getUuid();
                                        // if (storedSessionId.equals(httpSessionId.getValue()))
-                                       throw new CmsException(
+                                       throw new IllegalStateException(
                                                        "Subject already logged with session " + storedSessionId + " (not " + nodeSessionId + ")");
                                }
                        }
@@ -191,7 +184,7 @@ class CmsAuthUtils {
                        sr = bc.getServiceReferences(CmsSession.class,
                                        "(" + CmsSession.SESSION_LOCAL_ID + "=" + httpSessionId + ")");
                } catch (InvalidSyntaxException e) {
-                       throw new CmsException("Cannot get CMS session for id " + httpSessionId, e);
+                       throw new IllegalArgumentException("Cannot get CMS session for id " + httpSessionId, e);
                }
                CmsSession cmsSession;
                if (sr.size() == 1) {
@@ -203,7 +196,7 @@ class CmsAuthUtils {
                } else if (sr.size() == 0)
                        return null;
                else
-                       throw new CmsException(sr.size() + ">1 web sessions detected for http session " + httpSessionId);
+                       throw new IllegalStateException(sr.size() + ">1 web sessions detected for http session " + httpSessionId);
                return cmsSession;
        }
 
index b71eb4fc786a589283ac271dde899e80c05dfabd..cc435aeb8f7b568e6c59a1be69f3cb46f53ac07c 100644 (file)
@@ -4,8 +4,6 @@ import java.util.UUID;
 
 import javax.security.auth.Subject;
 
-import org.argeo.cms.CmsException;
-
 /**
  * The ID of a {@link CmsSession}, which must be available in the private
  * credentials of an authenticated {@link Subject}.
@@ -15,7 +13,7 @@ public class CmsSessionId {
 
        public CmsSessionId(UUID value) {
                if (value == null)
-                       throw new CmsException("value cannot be null");
+                       throw new IllegalArgumentException("Value cannot be null");
                this.uuid = value;
        }
 
index 11dbaa3f79002b5b73c451d96be9fe204d75c2f0..fa552323c4bfa3d9b65bef79ec34bce5cd7ebc8e 100644 (file)
@@ -14,7 +14,6 @@ import javax.security.auth.Subject;
 import javax.security.auth.x500.X500Principal;
 
 import org.argeo.api.NodeConstants;
-import org.argeo.cms.CmsException;
 import org.argeo.cms.internal.auth.CmsSessionImpl;
 import org.argeo.cms.internal.auth.ImpliedByPrincipal;
 import org.argeo.cms.internal.kernel.Activator;
@@ -25,9 +24,6 @@ import org.osgi.service.useradmin.Authorization;
  * context.
  */
 public final class CurrentUser {
-       // private final static Log log = LogFactory.getLog(CurrentUser.class);
-       // private final static BundleContext bc =
-       // FrameworkUtil.getBundle(CurrentUser.class).getBundleContext();
        /*
         * CURRENT USER API
         */
@@ -86,7 +82,7 @@ public final class CurrentUser {
 
        public final static String getUsername(Subject subject) {
                if (subject == null)
-                       throw new CmsException("Subject cannot be null");
+                       throw new IllegalArgumentException("Subject cannot be null");
                if (subject.getPrincipals(X500Principal.class).size() != 1)
                        return NodeConstants.ROLE_ANONYMOUS;
                Principal principal = subject.getPrincipals(X500Principal.class).iterator().next();
@@ -133,32 +129,16 @@ public final class CurrentUser {
         * HELPERS
         */
        private static Subject currentSubject() {
-               // CmsAuthenticated cmsView = getNodeAuthenticated();
-               // if (cmsView != null)
-               // return cmsView.getSubject();
                Subject subject = getAccessControllerSubject();
                if (subject != null)
                        return subject;
-               throw new CmsException("Cannot find related subject");
+               throw new IllegalStateException("Cannot find related subject");
        }
 
        private static Subject getAccessControllerSubject() {
                return Subject.getSubject(AccessController.getContext());
        }
 
-       // public static boolean isAuthenticated() {
-       // return getAccessControllerSubject() != null;
-       // }
-
-       /**
-        * The node authenticated component (typically a CMS view) related to this
-        * display, or null if none is available from this call. <b>Not API: Only for
-        * low-level access.</b>
-        */
-       // private static CmsAuthenticated getNodeAuthenticated() {
-       // return UiContext.getData(CmsAuthenticated.KEY);
-       // }
-
        private static Authorization getAuthorization(Subject subject) {
                return subject.getPrivateCredentials(Authorization.class).iterator().next();
        }
index 3a3a9f9e0a5639468b66a7cc6d52592073422290..920f04e343514ecac54bd29697d2c87216959735 100644 (file)
@@ -5,6 +5,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+/** Retrieves credentials from an HTTP request. */
 public class HttpRequestCallback implements Callback {
        private HttpServletRequest request;
        private HttpServletResponse response;
index acc0ba4e8ff58ee0a4fc437e24065bc5ab5873fc..8cb524fbe344bd6b864a40b5bfd0f89555ba7a3a 100644 (file)
@@ -19,7 +19,6 @@ import javax.servlet.http.HttpSession;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
 import org.argeo.cms.internal.kernel.Activator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
@@ -182,10 +181,10 @@ public class HttpSessionLoginModule implements LoginModule {
                                                        sharedState.put(CmsAuthUtils.SHARED_STATE_NAME, login);
                                                        sharedState.put(CmsAuthUtils.SHARED_STATE_PWD, password);
                                                } else {
-                                                       throw new CmsException("Invalid authentication token");
+                                                       throw new IllegalStateException("Invalid authentication token");
                                                }
                                        } catch (Exception e) {
-                                               throw new CmsException("Couldn't retrieve authentication", e);
+                                               throw new IllegalStateException("Couldn't retrieve authentication", e);
                                        }
                                } else if (basic.equalsIgnoreCase("Negotiate")) {
                                        String spnegoToken = st.nextToken();
index c82394850aa78d8ff0b8c577b03f8213b598c6d9..b4144d30f85761c701a96dd072f3365e7e3a82c0 100644 (file)
@@ -2,6 +2,11 @@ package org.argeo.cms.auth;
 
 import org.osgi.service.useradmin.Authorization;
 
+/**
+ * {@link Authorization} for a single user.
+ * 
+ * @see SingleUserLoginModule
+ */
 public class SingleUserAuthorization implements Authorization {
 
        @Override
index 8583bc194f7dde537f03de505a444298833c4ae1..0b163bac3fb9c12c98f5f85c8a2d36dde0e9abb2 100644 (file)
@@ -3,6 +3,7 @@ package org.argeo.cms.auth;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.security.Principal;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
@@ -13,6 +14,7 @@ import javax.security.auth.kerberos.KerberosPrincipal;
 import javax.security.auth.login.LoginException;
 import javax.security.auth.spi.LoginModule;
 import javax.security.auth.x500.X500Principal;
+import javax.servlet.http.HttpServletRequest;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -23,6 +25,7 @@ import org.argeo.naming.LdapAttrs;
 import org.argeo.osgi.useradmin.IpaUtils;
 import org.osgi.service.useradmin.Authorization;
 
+/** Login module for when the system is owned by a single user. */
 public class SingleUserLoginModule implements LoginModule {
        private final static Log log = LogFactory.getLog(SingleUserLoginModule.class);
 
@@ -70,9 +73,16 @@ public class SingleUserLoginModule implements LoginModule {
                principals.add(principal);
                principals.add(new ImpliedByPrincipal(NodeConstants.ROLE_ADMIN, principal));
                principals.add(new DataAdminPrincipal());
-               
+
+               HttpServletRequest request = (HttpServletRequest) sharedState.get(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST);
+               Locale locale = Locale.getDefault();
+               if (request != null)
+                       locale = request.getLocale();
+               if (locale == null)
+                       locale = Locale.getDefault();
                Authorization authorization = new SingleUserAuthorization();
-               subject.getPrivateCredentials().add(authorization);
+               CmsAuthUtils.addAuthorization(subject, authorization);
+               CmsAuthUtils.registerSessionAuthorization(request, subject, authorization, locale);
 
                return true;
        }
@@ -84,7 +94,7 @@ public class SingleUserLoginModule implements LoginModule {
 
        @Override
        public boolean logout() throws LoginException {
-               // TODO Auto-generated method stub
+               CmsAuthUtils.cleanUp(subject);
                return true;
        }
 
index 54d328cc9787d329aa31ffc6512f3c4fa2036075..4b72903e22ae3dc66933ca0e91e267ff7b13b581 100644 (file)
@@ -29,7 +29,6 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.api.NodeConstants;
 import org.argeo.api.security.CryptoKeyring;
-import org.argeo.cms.CmsException;
 import org.argeo.cms.internal.kernel.Activator;
 import org.argeo.naming.LdapAttrs;
 import org.argeo.osgi.useradmin.AuthenticatingUser;
@@ -77,7 +76,7 @@ public class UserAdminLoginModule implements LoginModule {
                        this.callbackHandler = callbackHandler;
                        this.sharedState = (Map<String, Object>) sharedState;
                } catch (Exception e) {
-                       throw new CmsException("Cannot initialize login module", e);
+                       throw new IllegalStateException("Cannot initialize login module", e);
                }
        }
 
@@ -117,6 +116,8 @@ public class UserAdminLoginModule implements LoginModule {
                } else if (singleUser) {
                        username = OsUserUtils.getOsUsername();
                        password = null;
+                       // TODO retrieve from http session
+                       locale = Locale.getDefault();
                } else {
 
                        // ask for username and password
@@ -207,9 +208,7 @@ public class UserAdminLoginModule implements LoginModule {
 
        @Override
        public boolean commit() throws LoginException {
-               if (locale == null)
-                       subject.getPublicCredentials().add(Locale.getDefault());
-               else
+               if (locale != null)
                        subject.getPublicCredentials().add(locale);
 
                if (singleUser) {
@@ -299,8 +298,6 @@ public class UserAdminLoginModule implements LoginModule {
        public boolean logout() throws LoginException {
                if (log.isTraceEnabled())
                        log.trace("Logging out from CMS... " + subject);
-               // boolean httpSessionLogoutOk = CmsAuthUtils.logoutSession(bc,
-               // subject);
                CmsAuthUtils.cleanUp(subject);
                return true;
        }
index 3dbc7ad52fa03a7792afecaf6cd53757604bba7e..8fe042653d8f5e015df9d7b650ada4081e2a32c5 100644 (file)
@@ -7,7 +7,6 @@ import javax.naming.ldap.LdapName;
 import javax.naming.ldap.Rdn;
 
 import org.argeo.api.NodeConstants;
-import org.argeo.cms.CmsException;
 import org.argeo.naming.LdapAttrs;
 import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.User;
@@ -59,7 +58,7 @@ public class UserAdminUtils {
                                || last.getType().toLowerCase().equals(LdapAttrs.cn.name()))
                        return (String) last.getValue();
                else
-                       throw new CmsException("Cannot retrieve user local id, non valid dn: " + dn);
+                       throw new IllegalArgumentException("Cannot retrieve user local id, non valid dn: " + dn);
        }
 
        /**
@@ -129,7 +128,7 @@ public class UserAdminUtils {
                try {
                        return new LdapName(dn);
                } catch (InvalidNameException e) {
-                       throw new CmsException("Cannot parse LDAP name " + dn, e);
+                       throw new IllegalArgumentException("Cannot parse LDAP name " + dn, e);
                }
        }
 
@@ -158,7 +157,7 @@ public class UserAdminUtils {
                        }
                        return dname;
                } catch (InvalidNameException e) {
-                       throw new CmsException("Unable to get domain name for " + dn, e);
+                       throw new IllegalArgumentException("Unable to get domain name for " + dn, e);
                }
        }
 
index 9ae0fd8d8b5634091d221633085bd93618df2090..b6966765d9534ea1469188dc5a81c06b1cf80fa3 100644 (file)
@@ -39,6 +39,7 @@ import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.useradmin.Authorization;
 
+/** Default CMS session implementation. */
 public class CmsSessionImpl implements CmsSession {
        private final static BundleContext bc = FrameworkUtil.getBundle(CmsSessionImpl.class).getBundleContext();
        private final static Log log = LogFactory.getLog(CmsSessionImpl.class);
index 4f1d3637bad56c79ef1b8fc343eb36e1cf34bd72..0979a215793a6fcc7fc1565c9f5ab64d3832fb13 100644 (file)
@@ -12,17 +12,14 @@ import javax.security.auth.callback.PasswordCallback;
 import javax.security.auth.callback.TextOutputCallback;
 import javax.security.auth.callback.UnsupportedCallbackException;
 
-import org.argeo.cms.CmsException;
-
 /** Callback handler to be used with a command line UI. */
 public class ConsoleCallbackHandler implements CallbackHandler {
 
        @Override
-       public void handle(Callback[] callbacks) throws IOException,
-                       UnsupportedCallbackException {
+       public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
                Console console = System.console();
                if (console == null)
-                       throw new CmsException("No console available");
+                       throw new IllegalStateException("No console available");
 
                PrintWriter writer = console.writer();
                for (int i = 0; i < callbacks.length; i++) {
@@ -36,8 +33,7 @@ public class ConsoleCallbackHandler implements CallbackHandler {
                                        writer.write(" (" + callback.getDefaultName() + ")");
                                writer.write(" : ");
                                String answer = console.readLine();
-                               if (callback.getDefaultName() != null
-                                               && answer.trim().equals(""))
+                               if (callback.getDefaultName() != null && answer.trim().equals(""))
                                        callback.setName(callback.getDefaultName());
                                else
                                        callback.setName(answer);
index 5afacf69db134c522274dbe812a0291bd40c5efa..c753601296657c9e69d03499a7b931ad9bdf8ee4 100644 (file)
@@ -10,7 +10,6 @@ import java.util.Set;
 import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
 
-import org.argeo.cms.CmsException;
 import org.osgi.service.useradmin.Authorization;
 import org.osgi.service.useradmin.Role;
 
@@ -32,7 +31,7 @@ public final class ImpliedByPrincipal implements Principal, Role {
                try {
                        this.name = new LdapName(name);
                } catch (InvalidNameException e) {
-                       throw new CmsException("Badly formatted role name", e);
+                       throw new IllegalArgumentException("Badly formatted role name", e);
                }
                if (userPrincipal != null)
                        causes.add(userPrincipal);
index 1df7b1760cfb4471ca013ca3b564ec3b87929379..20f4c032e6ab5cab6ac55ea978df809546aaf2e1 100644 (file)
@@ -9,14 +9,16 @@ import javax.servlet.http.HttpSession;
 import org.argeo.cms.internal.auth.CmsSessionImpl;
 import org.osgi.service.useradmin.Authorization;
 
+/** CMS session implementation in a web context. */
 public class WebCmsSessionImpl extends CmsSessionImpl {
        // private final static Log log =
        // LogFactory.getLog(WebCmsSessionImpl.class);
 
        private HttpSession httpSession;
 
-       public WebCmsSessionImpl(Subject initialSubject, Authorization authorization, Locale locale, HttpServletRequest request) {
-               super(initialSubject, authorization, locale,request.getSession(false).getId());
+       public WebCmsSessionImpl(Subject initialSubject, Authorization authorization, Locale locale,
+                       HttpServletRequest request) {
+               super(initialSubject, authorization, locale, request.getSession(false).getId());
                httpSession = request.getSession(false);
        }