Clean up Jackrabbit Security
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 5 Nov 2011 13:23:00 +0000 (13:23 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 5 Nov 2011 13:23:00 +0000 (13:23 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@4887 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

security/runtime/org.argeo.security.jackrabbit/.classpath
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoAccessManager.java
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoLoginModule.java
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoSecurityManager.java
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoSystemPrincipal.java [new file with mode: 0644]
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/GrantedAuthorityPrincipal.java

index 92f19d2ff95b83a87f5210157582c70bb070ed48..8b978d9ede4d96fb47cbd858fc3b6607968c677f 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
+       <classpathentry kind="src" path="src/main/java"/>
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
        <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-       <classpathentry kind="src" path="src/main/java"/>
        <classpathentry kind="output" path="target/classes"/>
 </classpath>
index bb1fe060e390c7a9f229d69117b51faa3b55a4d1..7464078d802a75c717a93dfe4bf9cf8823d86973 100644 (file)
@@ -8,27 +8,27 @@ import org.apache.jackrabbit.core.id.ItemId;
 import org.apache.jackrabbit.core.security.DefaultAccessManager;
 import org.apache.jackrabbit.spi.Path;
 
-/** Intermediary class in order to have a consistent naming in config files. */
+/**
+ * Intermediary class in order to have a consistent naming in config files. Does
+ * nothing for the time being, but may in the future.
+ */
 public class ArgeoAccessManager extends DefaultAccessManager {
 
        @Override
        public boolean canRead(Path itemPath, ItemId itemId)
                        throws RepositoryException {
-               // TODO Auto-generated method stub
                return super.canRead(itemPath, itemId);
        }
 
        @Override
        public Privilege[] getPrivileges(String absPath)
                        throws PathNotFoundException, RepositoryException {
-               // TODO Auto-generated method stub
                return super.getPrivileges(absPath);
        }
 
        @Override
        public boolean hasPrivileges(String absPath, Privilege[] privileges)
                        throws PathNotFoundException, RepositoryException {
-               // TODO Auto-generated method stub
                return super.hasPrivileges(absPath, privileges);
        }
 
index 69bab52937fec3821e4ee53cade532e13aa9f839..3a18a38b8fb1b4030214779933582611dcfcdb9c 100644 (file)
@@ -22,6 +22,7 @@ import org.springframework.security.GrantedAuthority;
 import org.springframework.security.context.SecurityContextHolder;
 import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken;
 
+/** Jackrabbit login mechanism based on Spring Security */
 public class ArgeoLoginModule extends AbstractLoginModule {
        private String adminRole = "ROLE_ADMIN";
 
@@ -38,9 +39,9 @@ public class ArgeoLoginModule extends AbstractLoginModule {
 
        protected Set<Principal> getPrincipals() {
                // clear already registered Jackrabbit principals
-               clearPrincipals(AdminPrincipal.class);
-               clearPrincipals(AnonymousPrincipal.class);
-               clearPrincipals(GrantedAuthorityPrincipal.class);
+               //clearPrincipals(AdminPrincipal.class);
+               //clearPrincipals(AnonymousPrincipal.class);
+               //clearPrincipals(GrantedAuthorityPrincipal.class);
 
                return syncPrincipals();
        }
@@ -53,17 +54,19 @@ public class ArgeoLoginModule extends AbstractLoginModule {
                Set<Principal> principals = new LinkedHashSet<Principal>();
                principals.add(authen);
 
-               if (authen instanceof SystemAuthentication)
+               if (authen instanceof SystemAuthentication) {
                        principals.add(new AdminPrincipal(authen.getName()));
-               else if (authen instanceof AnonymousAuthenticationToken)
+                       principals.add(new ArgeoSystemPrincipal(authen.getName()));
+               } else if (authen instanceof AnonymousAuthenticationToken) {
                        principals.add(new AnonymousPrincipal());
-               else
+               } else {
                        for (GrantedAuthority ga : authen.getAuthorities()) {
                                principals.add(new GrantedAuthorityPrincipal(ga));
                                // FIXME: make it more generic
                                if (adminRole.equals(ga.getAuthority()))
                                        principals.add(new AdminPrincipal(authen.getName()));
                        }
+               }
 
                // remove previous credentials
                Set<SimpleCredentials> thisCredentials = subject
@@ -71,8 +74,8 @@ public class ArgeoLoginModule extends AbstractLoginModule {
                if (thisCredentials != null)
                        thisCredentials.clear();
                // override credentials since we did not used the one passed to us
-               credentials = new SimpleCredentials(authen.getName(), authen
-                               .getCredentials().toString().toCharArray());
+//             credentials = new SimpleCredentials(authen.getName(), authen
+//                             .getCredentials().toString().toCharArray());
 
                return principals;
        }
@@ -85,13 +88,14 @@ public class ArgeoLoginModule extends AbstractLoginModule {
        @Override
        public boolean logout() throws LoginException {
                clearPrincipals(AdminPrincipal.class);
+               clearPrincipals(ArgeoSystemPrincipal.class);
                clearPrincipals(AnonymousPrincipal.class);
                clearPrincipals(GrantedAuthorityPrincipal.class);
 
                // we resync with Spring Security since the subject may have been reused
                // in beetween
                // TODO: check if this is clean
-               //subject.getPrincipals().addAll(syncPrincipals());
+               // subject.getPrincipals().addAll(syncPrincipals());
 
                return true;
        }
index 2153e0e94025c7d96ab3daad787df5612a4be228..c6a0fc7169a310658a98749f0c58af8b2a806679 100644 (file)
@@ -27,7 +27,6 @@ import org.apache.jackrabbit.api.security.user.User;
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.core.DefaultSecurityManager;
 import org.apache.jackrabbit.core.security.SecurityConstants;
-import org.apache.jackrabbit.core.security.SystemPrincipal;
 import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
 import org.argeo.ArgeoException;
 import org.argeo.jcr.JcrUtils;
@@ -38,14 +37,19 @@ import org.springframework.security.GrantedAuthority;
 public class ArgeoSecurityManager extends DefaultSecurityManager {
        private Log log = LogFactory.getLog(ArgeoSecurityManager.class);
 
+       /**
+        * 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
-       /** Since this is called once when the session is created, we take the opportunity to synchronize Spring and Jackrabbit users and groups.*/
        public String getUserID(Subject subject, String workspaceName)
                        throws RepositoryException {
                long begin = System.currentTimeMillis();
 
+               log.debug(subject);
                // skip Jackrabbit system user
-               if (!subject.getPrincipals(SystemPrincipal.class).isEmpty())
+               if (!subject.getPrincipals(ArgeoSystemPrincipal.class).isEmpty())
                        return super.getUserID(subject, workspaceName);
 
                Authentication authen;
@@ -57,10 +61,6 @@ public class ArgeoSecurityManager extends DefaultSecurityManager {
                else
                        authen = authens.iterator().next();
 
-               // skip argeo system authenticated
-               // if (authen instanceof SystemAuthentication)
-               // return super.getUserID(subject, workspaceName);
-
                UserManager systemUm = getSystemUserManager(workspaceName);
 
                String userId = authen.getName();
@@ -68,11 +68,10 @@ public class ArgeoSecurityManager extends DefaultSecurityManager {
                if (user == null) {
                        user = systemUm.createUser(userId, authen.getCredentials()
                                        .toString(), authen, null);
+                       setSecurityHomeAuthorizations(user);
                        log.info(userId + " added as " + user);
                }
 
-               //setHomeNodeAuthorizations(user);
-
                // process groups
                List<String> userGroupIds = new ArrayList<String>();
                for (GrantedAuthority ga : authen.getAuthorities()) {
@@ -93,91 +92,52 @@ public class ArgeoSecurityManager extends DefaultSecurityManager {
                                group.removeMember(user);
                }
 
-               // write roles in profile for easy access
-//             if (!(authen instanceof SystemAuthentication)) {
-//                     Node userProfile = JcrUtils.getUserProfile(getSystemSession(),
-//                                     userId);
-//                     boolean writeRoles = false;
-//                     if (userProfile.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) {
-//                             Value[] roles = userProfile.getProperty(ArgeoNames.ARGEO_REMOTE_ROLES)
-//                                             .getValues();
-//                             if (roles.length != userGroupIds.size())
-//                                     writeRoles = true;
-//                             else
-//                                     for (int i = 0; i < roles.length; i++)
-//                                             if (!roles[i].getString().equals(userGroupIds.get(i)))
-//                                                     writeRoles = true;
-//                     } else
-//                             writeRoles = true;
-//
-//                     if (writeRoles) {
-//                             userProfile.getSession().getWorkspace().getVersionManager()
-//                                             .checkout(userProfile.getPath());
-//                             String[] roleIds = userGroupIds.toArray(new String[userGroupIds
-//                                             .size()]);
-//                             userProfile.setProperty(ArgeoNames.ARGEO_REMOTE_ROLES, roleIds);
-//                             JcrUtils.updateLastModified(userProfile);
-//                             userProfile.getSession().save();
-//                             userProfile.getSession().getWorkspace().getVersionManager()
-//                                             .checkin(userProfile.getPath());
-//                     }
-//             }
-
-               if (log.isTraceEnabled())
-                       log.trace("Spring and Jackrabbit Security synchronized for user "
+               if (log.isDebugEnabled())
+                       log.debug("Spring and Jackrabbit Security synchronized for user "
                                        + userId + " in " + (System.currentTimeMillis() - begin)
                                        + " ms");
                return userId;
        }
 
-       protected synchronized void setHomeNodeAuthorizations(User user) {
-               // give all privileges on user home
-               // FIXME: fails on an empty repo
+       protected synchronized void setSecurityHomeAuthorizations(User user) {
+               // give read privileges on user home
                String userId = "<not yet set>";
                try {
                        userId = user.getID();
-                       Node userHome = null;
-                       try {
-                               userHome = JcrUtils.getUserHome(getSystemSession(), userId);
-                               if (userHome == null) {
-                                       userHome = JcrUtils.createUserHomeIfNeeded(getSystemSession(), userId);
-                                       //log.warn("No home available for user "+userId);
-                                       return;
-                               }
-                       } catch (Exception e) {
-                               // silent
+                       Node userHome = JcrUtils.getUserHome(getSystemSession(), userId);
+                       if (userHome == null)
+                               throw new ArgeoException("No security home available for user "
+                                               + userId);
+
+                       String path = userHome.getPath();
+                       Principal principal = user.getPrincipal();
+
+                       JackrabbitAccessControlManager acm = (JackrabbitAccessControlManager) getSystemSession()
+                                       .getAccessControlManager();
+                       JackrabbitAccessControlPolicy[] ps = acm
+                                       .getApplicablePolicies(principal);
+                       if (ps.length == 0) {
+                               // log.warn("No ACL found for " + user);
+                               return;
                        }
 
-                       if (userHome != null) {
-                               String path = userHome.getPath();
-                               Principal principal = user.getPrincipal();
-
-                               JackrabbitAccessControlManager acm = (JackrabbitAccessControlManager) getSystemSession()
-                                               .getAccessControlManager();
-                               JackrabbitAccessControlPolicy[] ps = acm
-                                               .getApplicablePolicies(principal);
-                               if (ps.length == 0) {
-                                       // log.warn("No ACL found for " + user);
-                                       return;
-                               }
-
-                               JackrabbitAccessControlList list = (JackrabbitAccessControlList) ps[0];
-
-                               // add entry
-                               Privilege[] privileges = new Privilege[] { acm
-                                               .privilegeFromName(Privilege.JCR_ALL) };
-                               Map<String, Value> restrictions = new HashMap<String, Value>();
-                               ValueFactory vf = getSystemSession().getValueFactory();
-                               restrictions.put("rep:nodePath",
-                                               vf.createValue(path, PropertyType.PATH));
-                               restrictions.put("rep:glob", vf.createValue("*"));
-                               list.addEntry(principal, privileges, true /* allow or deny */,
-                                               restrictions);
-                       }
+                       JackrabbitAccessControlList list = (JackrabbitAccessControlList) ps[0];
+
+                       // add entry
+                       Privilege[] privileges = new Privilege[] { acm
+                                       .privilegeFromName(Privilege.JCR_READ) };
+                       Map<String, Value> restrictions = new HashMap<String, Value>();
+                       ValueFactory vf = getSystemSession().getValueFactory();
+                       restrictions.put("rep:nodePath",
+                                       vf.createValue(path, PropertyType.PATH));
+                       restrictions.put("rep:glob", vf.createValue("*"));
+                       list.addEntry(principal, privileges, true /* allow or deny */,
+                                       restrictions);
                } catch (Exception e) {
                        e.printStackTrace();
-                       log.warn("Cannot set authorization on user node for " + userId
-                                       + ": " + e.getMessage());
+                       throw new ArgeoException(
+                                       "Cannot set authorization on security home for " + userId
+                                                       + ": " + e.getMessage());
                }
 
        }
diff --git a/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoSystemPrincipal.java b/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoSystemPrincipal.java
new file mode 100644 (file)
index 0000000..71e42c5
--- /dev/null
@@ -0,0 +1,35 @@
+package org.argeo.security.jackrabbit;
+
+import java.security.Principal;
+
+/** Principal for non-interactive system actions. */
+class ArgeoSystemPrincipal implements Principal {
+       private String name;
+
+       public ArgeoSystemPrincipal(String name) {
+               super();
+               this.name = name;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       @Override
+       public int hashCode() {
+               return getName().hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (!(obj instanceof ArgeoSystemPrincipal))
+                       return false;
+               return getName().equals(((ArgeoSystemPrincipal) obj).getName());
+       }
+
+       @Override
+       public String toString() {
+               return "Argeo System (non interactive) name=" + getName();
+       }
+
+}
index 4e9b87abd5e1851a94dc63b4d7ac30edf19260dd..6ed2dc50a3dd39f022c228020496f693f2d011b9 100644 (file)
@@ -9,7 +9,6 @@ class GrantedAuthorityPrincipal implements Principal {
        private final GrantedAuthority grantedAuthority;
 
        public GrantedAuthorityPrincipal(GrantedAuthority grantedAuthority) {
-               super();
                this.grantedAuthority = grantedAuthority;
        }
 
@@ -29,4 +28,9 @@ class GrantedAuthorityPrincipal implements Principal {
                return getName().equals(((GrantedAuthorityPrincipal) obj).getName());
        }
 
+       @Override
+       public String toString() {
+               return "Granted Authority " + getName();
+       }
+
 }