Rename packages in order to make future stable documentation clearer.
[lgpl/argeo-commons.git] / org.argeo.ext.jackrabbit / src / org / argeo / security / jackrabbit / ArgeoSecurityManager.java
index 978be436b648623c1e6cf00199a226c26c96ace0..3976f3ba97e21c6f37c49a2c8143f2c9aa0cd2f1 100644 (file)
 package org.argeo.security.jackrabbit;
 
 import java.security.Principal;
+import java.util.HashSet;
+import java.util.Properties;
 import java.util.Set;
 
+import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.security.auth.Subject;
 import javax.security.auth.x500.X500Principal;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.core.DefaultSecurityManager;
 import org.apache.jackrabbit.core.security.AMContext;
 import org.apache.jackrabbit.core.security.AccessManager;
 import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.core.security.SystemPrincipal;
 import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
+import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
+import org.apache.jackrabbit.core.security.principal.PrincipalProvider;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.security.AnonymousPrincipal;
+import org.argeo.api.security.DataAdminPrincipal;
+import org.argeo.cms.auth.CmsSession;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
 
-/** Integrates Spring Security and Jackrabbit Security users and roles. */
+/** Customises Jackrabbit security. */
 public class ArgeoSecurityManager extends DefaultSecurityManager {
+       private final static Log log = LogFactory.getLog(ArgeoSecurityManager.class);
+
+       private BundleContext cmsBundleContext = null;
+
+       public ArgeoSecurityManager() {
+               if (FrameworkUtil.getBundle(CmsSession.class) != null) {
+                       cmsBundleContext = FrameworkUtil.getBundle(CmsSession.class).getBundleContext();
+               }
+       }
+
        @Override
-       public AccessManager getAccessManager(Session session, AMContext amContext)
-                       throws RepositoryException {
+       public AccessManager getAccessManager(Session session, AMContext amContext) throws RepositoryException {
                synchronized (getSystemSession()) {
                        return super.getAccessManager(session, amContext);
                }
        }
 
        @Override
-       public UserManager getUserManager(Session session)
-                       throws RepositoryException {
+       public UserManager getUserManager(Session session) throws RepositoryException {
                synchronized (getSystemSession()) {
                        return super.getUserManager(session);
                }
        }
 
-       /**
-        * Since this is called once when the session is created, we take the
-        * opportunity to make sure that Jackrabbit users and groups reflect Spring
-        * Security name and authorities.
-        */
        @Override
-       public String getUserID(Subject subject, String workspaceName)
-                       throws RepositoryException {
-               Set<X500Principal> userPrincipal = subject
-                               .getPrincipals(X500Principal.class);
-               if (userPrincipal.isEmpty())
-                       return super.getUserID(subject, workspaceName);
-               if (userPrincipal.size() > 1) {
-                       StringBuilder buf = new StringBuilder();
-                       for (X500Principal principal : userPrincipal)
-                               buf.append(' ').append('\"').append(principal).append('\"');
-                       throw new RuntimeException("Multiple user principals:" + buf);
+       protected PrincipalProvider createDefaultPrincipalProvider(Properties[] moduleConfig) throws RepositoryException {
+               return super.createDefaultPrincipalProvider(moduleConfig);
+       }
+
+       /** Called once when the session is created */
+       @Override
+       public String getUserID(Subject subject, String workspaceName) throws RepositoryException {
+               boolean isAnonymous = !subject.getPrincipals(AnonymousPrincipal.class).isEmpty();
+               boolean isDataAdmin = !subject.getPrincipals(DataAdminPrincipal.class).isEmpty();
+               boolean isJackrabbitSystem = !subject.getPrincipals(SystemPrincipal.class).isEmpty();
+               Set<X500Principal> userPrincipal = subject.getPrincipals(X500Principal.class);
+               boolean isRegularUser = !userPrincipal.isEmpty();
+               CmsSession cmsSession = null;
+               if (cmsBundleContext != null) {
+                       cmsSession = CmsSession.getCmsSession(cmsBundleContext, subject);
+                       if (log.isTraceEnabled())
+                               log.trace("Opening JCR session for CMS session " + cmsSession);
+               }
+
+               if (isAnonymous) {
+                       if (isDataAdmin || isJackrabbitSystem || isRegularUser)
+                               throw new IllegalStateException("Inconsistent " + subject);
+                       else
+                               return NodeConstants.ROLE_ANONYMOUS;
+               } else if (isRegularUser) {// must be before DataAdmin
+                       if (isAnonymous || isJackrabbitSystem)
+                               throw new IllegalStateException("Inconsistent " + subject);
+                       else {
+                               if (userPrincipal.size() > 1) {
+                                       StringBuilder buf = new StringBuilder();
+                                       for (X500Principal principal : userPrincipal)
+                                               buf.append(' ').append('\"').append(principal).append('\"');
+                                       throw new RuntimeException("Multiple user principals:" + buf);
+                               }
+                               return userPrincipal.iterator().next().getName();
+                       }
+               } else if (isDataAdmin) {
+                       if (isAnonymous || isJackrabbitSystem || isRegularUser)
+                               throw new IllegalStateException("Inconsistent " + subject);
+                       else {
+                               assert !subject.getPrincipals(AdminPrincipal.class).isEmpty();
+                               return NodeConstants.ROLE_DATA_ADMIN;
+                       }
+               } else if (isJackrabbitSystem) {
+                       if (isAnonymous || isDataAdmin || isRegularUser)
+                               throw new IllegalStateException("Inconsistent " + subject);
+                       else
+                               return super.getUserID(subject, workspaceName);
+               } else {
+                       throw new IllegalStateException("Unrecognized subject type: " + subject);
                }
-               return userPrincipal.iterator().next().getName();
-               // Authentication authentication = SecurityContextHolder.getContext()
-               // .getAuthentication();
-               // if (authentication != null)
-               // return authentication.getName();
-               // else
-               // return super.getUserID(subject, workspaceName);
        }
 
        @Override
        protected WorkspaceAccessManager createDefaultWorkspaceAccessManager() {
-               WorkspaceAccessManager wam = super
-                               .createDefaultWorkspaceAccessManager();
-               return new ArgeoWorkspaceAccessManagerImpl(wam);
+               WorkspaceAccessManager wam = super.createDefaultWorkspaceAccessManager();
+               ArgeoWorkspaceAccessManagerImpl workspaceAccessManager = new ArgeoWorkspaceAccessManagerImpl(wam);
+               if (log.isTraceEnabled())
+                       log.trace("Created workspace access manager");
+               return workspaceAccessManager;
        }
 
-       private class ArgeoWorkspaceAccessManagerImpl implements SecurityConstants,
-                       WorkspaceAccessManager {
+       private class ArgeoWorkspaceAccessManagerImpl implements SecurityConstants, WorkspaceAccessManager {
                private final WorkspaceAccessManager wam;
 
                public ArgeoWorkspaceAccessManagerImpl(WorkspaceAccessManager wam) {
@@ -93,15 +143,21 @@ public class ArgeoSecurityManager extends DefaultSecurityManager {
 
                public void init(Session systemSession) throws RepositoryException {
                        wam.init(systemSession);
+                       Repository repository = systemSession.getRepository();
+                       if (log.isTraceEnabled())
+                               log.trace("Initialised workspace access manager on repository " + repository
+                                               + ", systemSession workspace: " + systemSession.getWorkspace().getName());
                }
 
                public void close() throws RepositoryException {
                }
 
-               public boolean grants(Set<Principal> principals, String workspaceName)
-                               throws RepositoryException {
+               public boolean grants(Set<Principal> principals, String workspaceName) throws RepositoryException {
                        // TODO: implements finer access to workspaces
+                       if (log.isTraceEnabled())
+                               log.trace("Grants " + new HashSet<>(principals) + " access to workspace '" + workspaceName + "'");
                        return true;
+                       // return wam.grants(principals, workspaceName);
                }
        }