Change profile and user home
authorMathieu Baudier <mbaudier@argeo.org>
Thu, 23 Aug 2012 20:19:14 +0000 (20:19 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Thu, 23 Aug 2012 20:19:14 +0000 (20:19 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@5539 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

20 files changed:
security/modules/org.argeo.security.dao.ldap/META-INF/spring/security-ldap-jcr.xml
security/modules/org.argeo.security.dao.ldap/META-INF/spring/security-ldap.xml
security/modules/org.argeo.security.dao.ldap/ldap.properties
security/modules/org.argeo.security.dao.os/META-INF/spring/security-os.xml
security/plugins/org.argeo.security.ui.admin/META-INF/spring/common.xml
security/plugins/org.argeo.security.ui.admin/security-admin.properties
security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/NewUser.java
security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/wizards/NewUserWizard.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrSecurityModel.java [new file with mode: 0644]
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrUserDetails.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrAuthenticationProvider.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrUserAdminService.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/JackrabbitSecurityModel.java [new file with mode: 0644]
security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrLdapSynchronizer.java
server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddRemoteRepository.java
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoJcrConstants.java
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/UserJcrUtils.java
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/SecurityJcrUtils.java

index ef18e04197b162d43a3a132f0ec93ab22009a1ae..9940b5b1fdc969dbc8a556839718f63dfa647e82 100644 (file)
                <property name="rawLdapTemplate" ref="rawLdapTemplate" />
                <!-- JCR -->
                <property name="repository" ref="nodeRepository" />
-               <property name="securityWorkspace" value="${argeo.node.repo.securityWorkspace}" />
+               <property name="jcrSecurityModel" ref="jcrSecurityModel" />
                <property name="propertyToAttributes" ref="propertyToAttributes" />
        </bean>
 
+       <bean name="jcrSecurityModel" class="org.argeo.security.jackrabbit.JackrabbitSecurityModel" />
+
        <!-- LDAP / JCR mapping -->
        <util:map id="propertyToAttributes">
                <entry value="cn">
index a31f79dc124416260fd4e4f17b3e1513ae5bd8af..3777f8853d5e6ab1437d92f668b477697ca3cd0c 100644 (file)
@@ -55,6 +55,7 @@
                <property name="userAdminDao" ref="userAdminDao" />
                <property name="passwordEncoder" ref="passwordEncoder" />
                <property name="passwordAttributeName" value="${argeo.ldap.passwordAttribute}" />
+               <property name="superUsername" value="${argeo.security.superUsername}" />
        </bean>
 
        <bean id="userAdminDao" class="org.argeo.security.ldap.ArgeoUserAdminDaoLdap">
index b00b5261f311c6f4842884260746b7c775f9a3d9..5c88a22553d16add393a56c25399535d899c2744 100644 (file)
@@ -1,9 +1,8 @@
-argeo.node.repo.securityWorkspace=security
-
 argeo.security.defaultRole=ROLE_USER
 argeo.security.rolePrefix=ROLE_
 
 argeo.security.systemKey=argeo
+argeo.security.superUsername=root
 
 argeo.ldap.rootdn=dc=demo,dc=argeo,dc=org
 argeo.ldap.protocol=ldap
index ee424b9e214c68e3f708fdc3f550fd2156a79ed8..970f38182afc7db9954d2af0567f28499d41dd43 100644 (file)
        <bean id="osJcrAuthenticationProvider" class="org.argeo.security.jcr.OsJcrAuthenticationProvider"
                init-method="init" destroy-method="destroy" depends-on="argeoDataModel">
                <property name="repository" ref="nodeRepository" />
+               <property name="jcrSecurityModel" ref="jcrSecurityModel" />
        </bean>
 
+       <bean name="jcrSecurityModel" class="org.argeo.security.jackrabbit.JackrabbitSecurityModel" />
+
        <bean id="authByAdapterProvider"
                class="org.springframework.security.adapters.AuthByAdapterProvider">
                <description><![CDATA[System authentication]]></description>
index 5b64119f816b88dd3c783122ca7c27ae9e251f31..b034f0362c7fbc70a55559fca98c20163137b430 100644 (file)
@@ -12,7 +12,6 @@
        </bean>\r
 \r
        <bean id="session" class="org.argeo.security.jcr.SecureThreadBoundSession">\r
-               <property name="workspace" value="${argeo.node.repo.securityWorkspace}" />\r
                <property name="repository" ref="nodeRepository" />\r
        </bean>\r
 </beans>
\ No newline at end of file
index 7dcc6104ef86ca12937c71a7b0b403fc05521a61..dab1b4ce7efba5b5a6f14c0f49e4df055b7636a4 100644 (file)
@@ -18,6 +18,7 @@ package org.argeo.security.ui.admin.commands;
 import javax.jcr.Session;
 
 import org.argeo.security.UserAdminService;
+import org.argeo.security.jcr.JcrSecurityModel;
 import org.argeo.security.ui.admin.wizards.NewUserWizard;
 import org.eclipse.core.commands.AbstractHandler;
 import org.eclipse.core.commands.ExecutionEvent;
@@ -29,11 +30,12 @@ import org.eclipse.ui.handlers.HandlerUtil;
 public class NewUser extends AbstractHandler {
        private Session session;
        private UserAdminService userAdminService;
+       private JcrSecurityModel jcrSecurityModel;
 
        public Object execute(ExecutionEvent event) throws ExecutionException {
                try {
                        NewUserWizard newUserWizard = new NewUserWizard(session,
-                                       userAdminService);
+                                       userAdminService,jcrSecurityModel);
                        WizardDialog dialog = new WizardDialog(
                                        HandlerUtil.getActiveShell(event), newUserWizard);
                        dialog.open();
@@ -51,4 +53,8 @@ public class NewUser extends AbstractHandler {
                this.userAdminService = userAdminService;
        }
 
+       public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) {
+               this.jcrSecurityModel = jcrSecurityModel;
+       }
+
 }
index 40a243f9422c47122b4f2c2dd4c4fc00320257f2..719290f10ff5968b90120185f7ede47141bf916b 100644 (file)
@@ -24,8 +24,8 @@ import org.apache.commons.logging.LogFactory;
 import org.argeo.eclipse.ui.ErrorFeedback;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.jcr.UserJcrUtils;
-import org.argeo.jcr.security.SecurityJcrUtils;
 import org.argeo.security.UserAdminService;
+import org.argeo.security.jcr.JcrSecurityModel;
 import org.argeo.security.jcr.JcrUserDetails;
 import org.eclipse.jface.wizard.Wizard;
 import org.springframework.security.GrantedAuthority;
@@ -35,13 +35,16 @@ public class NewUserWizard extends Wizard {
        private final static Log log = LogFactory.getLog(NewUserWizard.class);
        private Session session;
        private UserAdminService userAdminService;
+       private JcrSecurityModel jcrSecurityModel;
 
        // pages
        private MainUserInfoWizardPage mainUserInfo;
 
-       public NewUserWizard(Session session, UserAdminService userAdminService) {
+       public NewUserWizard(Session session, UserAdminService userAdminService,
+                       JcrSecurityModel jcrSecurityModel) {
                this.session = session;
                this.userAdminService = userAdminService;
+               this.jcrSecurityModel = jcrSecurityModel;
        }
 
        @Override
@@ -57,7 +60,9 @@ public class NewUserWizard extends Wizard {
 
                String username = mainUserInfo.getUsername();
                try {
-                       Node userProfile = SecurityJcrUtils.createUserProfile(session, username);
+                       // Node userProfile = SecurityJcrUtils.createUserProfile(session,
+                       // username);
+                       Node userProfile = jcrSecurityModel.sync(session, username);
                        // session.getWorkspace().getVersionManager()
                        // .checkout(userProfile.getPath());
                        mainUserInfo.mapToProfileNode(userProfile);
diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrSecurityModel.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrSecurityModel.java
new file mode 100644 (file)
index 0000000..3fffa1a
--- /dev/null
@@ -0,0 +1,106 @@
+package org.argeo.security.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.Privilege;
+import javax.jcr.version.VersionManager;
+
+import org.argeo.ArgeoException;
+import org.argeo.jcr.ArgeoJcrConstants;
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.jcr.ArgeoTypes;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.jcr.UserJcrUtils;
+
+/**
+ * Manages data expected by the Argeo security model, such as user home and
+ * profile.
+ */
+public class JcrSecurityModel {
+       // ArgeoNames not implemented as interface in order to ease derivation by
+       // Jackrabbit bundles
+
+       /** The home base path. */
+       private String homeBasePath = "/home";
+
+       /**
+        * To be called before user details are loaded
+        * 
+        * @return the user profile (whose parent is the user home)
+        */
+       public Node sync(Session session, String username) {
+               // TODO check user name validity (e.g. should not start by ROLE_)
+
+               try {
+                       Node userHome = UserJcrUtils.getUserHome(session, username);
+                       if (userHome == null) {
+                               String homePath = generateUserPath(homeBasePath, username);
+                               userHome = JcrUtils.mkdirs(session, homePath);
+                               // userHome = JcrUtils.mkfolders(session, homePath);
+                               userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
+                               userHome.setProperty(ArgeoNames.ARGEO_USER_ID, username);
+                               session.save();
+
+                               JcrUtils.clearAccesControList(session, homePath, username);
+                               JcrUtils.addPrivilege(session, homePath, username,
+                                               Privilege.JCR_ALL);
+                       }
+
+                       Node userProfile = UserJcrUtils.getUserProfile(session, username);
+                       if (userProfile == null) {
+                               String personPath = generateUserPath(
+                                               ArgeoJcrConstants.PEOPLE_BASE_PATH, username);
+                               Node personBase = JcrUtils.mkdirs(session, personPath);
+                               userProfile = personBase.addNode(ArgeoNames.ARGEO_PROFILE);
+                               userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE);
+                               userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username);
+                               userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, true);
+                               userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED,
+                                               true);
+                               userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED,
+                                               true);
+                               userProfile.setProperty(
+                                               ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED, true);
+                               session.save();
+
+                               JcrUtils.clearAccesControList(session, userProfile.getPath(),
+                                               username);
+                               JcrUtils.addPrivilege(session, userProfile.getPath(), username,
+                                               Privilege.JCR_READ);
+
+                               VersionManager versionManager = session.getWorkspace()
+                                               .getVersionManager();
+                               if (versionManager.isCheckedOut(userProfile.getPath()))
+                                       versionManager.checkin(userProfile.getPath());
+                       }
+                       return userProfile;
+               } catch (RepositoryException e) {
+                       JcrUtils.discardQuietly(session);
+                       throw new ArgeoException("Cannot sync node security model for "
+                                       + username, e);
+               }
+       }
+
+       /** Generate path for a new user home */
+       protected String generateUserPath(String base, String username) {
+               int atIndex = username.indexOf('@');
+               if (atIndex > 0) {
+                       String domain = username.substring(0, atIndex);
+                       String name = username.substring(atIndex + 1);
+                       return base + '/' + JcrUtils.firstCharsToPath(domain, 2) + '/'
+                                       + domain + '/' + JcrUtils.firstCharsToPath(name, 2) + '/'
+                                       + name;
+               } else if (atIndex == 0 || atIndex == (username.length() - 1)) {
+                       throw new ArgeoException("Unsupported username " + username);
+               } else {
+                       return base + '/' + JcrUtils.firstCharsToPath(username, 2) + '/'
+                                       + username;
+               }
+       }
+
+       public void setHomeBasePath(String homeBasePath) {
+               this.homeBasePath = homeBasePath;
+       }
+
+}
index 1a19ecb20c1a030c9bc82fefa92edc0b6e509653..0dbe3de0823f606635b435b6051ea24b406a0657 100644 (file)
@@ -24,7 +24,7 @@ import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
 import org.argeo.jcr.ArgeoNames;
-import org.argeo.jcr.security.SecurityJcrUtils;
+import org.argeo.jcr.UserJcrUtils;
 import org.springframework.security.BadCredentialsException;
 import org.springframework.security.DisabledException;
 import org.springframework.security.GrantedAuthority;
@@ -90,7 +90,7 @@ public class JcrUserDetails extends User implements ArgeoNames {
         */
        public JcrUserDetails(Session session, String username, String password,
                        GrantedAuthority[] authorities) throws RepositoryException {
-               this(SecurityJcrUtils.getUserProfile(session, username),
+               this(UserJcrUtils.getUserProfile(session, username),
                                password != null ? password : "", authorities);
        }
 
index d304dc36571d8e41da2dec883179be220bcdd57b..cb9146a8b662407593675de216655715d1c4504e 100644 (file)
@@ -22,7 +22,6 @@ import javax.jcr.Session;
 
 import org.argeo.ArgeoException;
 import org.argeo.jcr.JcrUtils;
-import org.argeo.jcr.security.SecurityJcrUtils;
 import org.argeo.security.OsAuthenticationToken;
 import org.argeo.security.core.OsAuthenticationProvider;
 import org.springframework.security.Authentication;
@@ -34,15 +33,16 @@ import org.springframework.security.userdetails.UserDetails;
 /** Relies on OS to authenticate and additionally setup JCR */
 public class OsJcrAuthenticationProvider extends OsAuthenticationProvider {
        private Repository repository;
-       private String securityWorkspace = "security";
-       private Session securitySession;
+       // private String securityWorkspace = "security";
+       // private Session securitySession;
        private Session nodeSession;
 
        private UserDetails userDetails;
+       private JcrSecurityModel jcrSecurityModel = new JcrSecurityModel();
 
        public void init() {
                try {
-                       securitySession = repository.login(securityWorkspace);
+                       // securitySession = repository.login();
                        nodeSession = repository.login();
                } catch (RepositoryException e) {
                        throw new ArgeoException("Cannot initialize", e);
@@ -50,7 +50,7 @@ public class OsJcrAuthenticationProvider extends OsAuthenticationProvider {
        }
 
        public void destroy() {
-               JcrUtils.logoutQuietly(securitySession);
+               // JcrUtils.logoutQuietly(securitySession);
                JcrUtils.logoutQuietly(nodeSession);
        }
 
@@ -77,24 +77,24 @@ public class OsJcrAuthenticationProvider extends OsAuthenticationProvider {
                                // WARNING: at this stage we assume that the java properties
                                // will have the same value
                                String username = System.getProperty("user.name");
-                               Node userProfile = SecurityJcrUtils.createUserProfileIfNeeded(
-                                               securitySession, username);
+                               Node userProfile = jcrSecurityModel.sync(nodeSession, username);
                                JcrUserDetails.checkAccountStatus(userProfile);
 
                                // each user should have a writable area in the default
                                // workspace of the node
-                               SecurityJcrUtils.createUserHomeIfNeeded(nodeSession, username);
+                               // SecurityJcrUtils.createUserHomeIfNeeded(nodeSession,
+                               // username);
                                userDetails = new JcrUserDetails(userProfile, authen
                                                .getCredentials().toString(), getBaseAuthorities());
                                authen.setDetails(userDetails);
                                return authen;
                        } catch (RepositoryException e) {
-                               JcrUtils.discardQuietly(securitySession);
+                               JcrUtils.discardQuietly(nodeSession);
                                throw new ArgeoException(
                                                "Unexpected exception when synchronizing OS and JCR security ",
                                                e);
                        } finally {
-                               JcrUtils.logoutQuietly(securitySession);
+                               JcrUtils.logoutQuietly(nodeSession);
                        }
                } else {
                        throw new ArgeoException("Unsupported authentication "
@@ -102,14 +102,18 @@ public class OsJcrAuthenticationProvider extends OsAuthenticationProvider {
                }
        }
 
-       public void setSecurityWorkspace(String securityWorkspace) {
-               this.securityWorkspace = securityWorkspace;
-       }
+       // public void setSecurityWorkspace(String securityWorkspace) {
+       // this.securityWorkspace = securityWorkspace;
+       // }
 
        public void setRepository(Repository repository) {
                this.repository = repository;
        }
 
+       public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) {
+               this.jcrSecurityModel = jcrSecurityModel;
+       }
+
        @SuppressWarnings("rawtypes")
        public boolean supports(Class authentication) {
                return OsAuthenticationToken.class.isAssignableFrom(authentication)
index 80ef1e55963d99544c3194896d9584f2419fb39c..44521f1bd8aa9df32a04caecbf05153d09139451 100644 (file)
@@ -10,7 +10,7 @@ import javax.jcr.Session;
 
 import org.argeo.ArgeoException;
 import org.argeo.jcr.JcrUtils;
-import org.argeo.jcr.security.SecurityJcrUtils;
+import org.argeo.jcr.UserJcrUtils;
 import org.argeo.security.UserAdminService;
 import org.springframework.dao.DataAccessException;
 import org.springframework.security.userdetails.UserDetails;
@@ -68,7 +68,7 @@ public class OsJcrUserAdminService implements UserAdminService {
        public UserDetails loadUserByUsername(String username)
                        throws UsernameNotFoundException, DataAccessException {
                if (getSPropertyUsername().equals(username)) {
-                       Node userProfile = SecurityJcrUtils.getUserProfile(securitySession,
+                       Node userProfile = UserJcrUtils.getUserProfile(securitySession,
                                        username);
                        JcrUserDetails userDetails;
                        try {
index 4af5d3f3d5a53997b79418e7a019d7c0f8e8cc4c..efd19b87d6a7e22539208a32a3d81dacf03a5d0e 100644 (file)
@@ -40,7 +40,8 @@ import org.springframework.security.GrantedAuthority;
 
 /** Integrates Spring Security and Jackrabbit Security user and roles. */
 public class ArgeoSecurityManager extends DefaultSecurityManager {
-       private Log log = LogFactory.getLog(ArgeoSecurityManager.class);
+       private final static Log log = LogFactory
+                       .getLog(ArgeoSecurityManager.class);
 
        /**
         * Since this is called once when the session is created, we take the
@@ -71,7 +72,9 @@ public class ArgeoSecurityManager extends DefaultSecurityManager {
                        authen = authens.iterator().next();
 
                // sync Spring and Jackrabbit
-               syncSpringAndJackrabbitSecurity(authen);
+               // workspace is irrelevant here
+               UserManager systemUm = getSystemUserManager(null);
+               syncSpringAndJackrabbitSecurity(systemUm, authen);
 
                return authen.getName();
        }
@@ -80,13 +83,10 @@ public class ArgeoSecurityManager extends DefaultSecurityManager {
         * Make sure that the Jackrabbit security model contains this user and its
         * granted authorities
         */
-       protected void syncSpringAndJackrabbitSecurity(Authentication authen)
-                       throws RepositoryException {
+       static void syncSpringAndJackrabbitSecurity(UserManager systemUm,
+                       Authentication authen) throws RepositoryException {
                long begin = System.currentTimeMillis();
 
-               // workspace is irrelevant here
-               UserManager systemUm = getSystemUserManager(null);
-
                String userId = authen.getName();
                User user = (User) systemUm.getAuthorizable(userId);
                if (user == null) {
diff --git a/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/JackrabbitSecurityModel.java b/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/JackrabbitSecurityModel.java
new file mode 100644 (file)
index 0000000..75345ed
--- /dev/null
@@ -0,0 +1,35 @@
+package org.argeo.security.jackrabbit;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.argeo.ArgeoException;
+import org.argeo.security.jcr.JcrSecurityModel;
+import org.argeo.util.security.SimplePrincipal;
+
+/** Make sure that user authorizable exists before syncing user directories. */
+public class JackrabbitSecurityModel extends JcrSecurityModel {
+
+       @Override
+       public Node sync(Session session, String username) {
+               try {
+                       if (session instanceof JackrabbitSession) {
+                               UserManager userManager = ((JackrabbitSession) session)
+                                               .getUserManager();
+                               User user = (User) userManager
+                                               .getAuthorizable(new SimplePrincipal(username));
+                               if (user == null)
+                                       userManager.createUser(username, "");
+                       }
+               } catch (RepositoryException e) {
+                       throw new ArgeoException(
+                                       "Cannot perform Jackrabbit specific operaitons", e);
+               }
+               return super.sync(session, username);
+       }
+
+}
index 178785602d5aa7eff0ad8d5583c39210f0350fb0..fa940f93d7370fae077686ac3876d54a6011ee5b 100644 (file)
@@ -59,7 +59,7 @@ import org.argeo.ArgeoException;
 import org.argeo.jcr.ArgeoNames;
 import org.argeo.jcr.ArgeoTypes;
 import org.argeo.jcr.JcrUtils;
-import org.argeo.jcr.security.SecurityJcrUtils;
+import org.argeo.security.jcr.JcrSecurityModel;
 import org.argeo.security.jcr.JcrUserDetails;
 import org.springframework.ldap.core.ContextExecutor;
 import org.springframework.ldap.core.ContextMapper;
@@ -73,7 +73,7 @@ import org.springframework.security.providers.encoding.PasswordEncoder;
 import org.springframework.security.userdetails.UserDetails;
 import org.springframework.security.userdetails.ldap.UserDetailsContextMapper;
 
-/** Guarantees that LDAP and JCR are in line. */
+/** Makes sure that LDAP and JCR are in line. */
 public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                ArgeoNames {
        private final static Log log = LogFactory.getLog(JcrLdapSynchronizer.class);
@@ -102,12 +102,11 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
 
        // JCR
        /** Admin session on the security workspace */
-       private Session securitySession;
+       private Session nodeSession;
        private Repository repository;
 
-       private String securityWorkspace = "security";
-
        private JcrProfileListener jcrProfileListener;
+       private JcrSecurityModel jcrSecurityModel = new JcrSecurityModel();
 
        // Mapping
        private Map<String, String> propertyToAttributes = new HashMap<String, String>();
@@ -118,7 +117,7 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
 
        public void init() {
                try {
-                       securitySession = repository.login(securityWorkspace);
+                       nodeSession = repository.login();
 
                        synchronize();
 
@@ -142,22 +141,22 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                        jcrProfileListener = new JcrProfileListener();
                        // noLocal is used so that we are not notified when we modify JCR
                        // from LDAP
-                       securitySession
+                       nodeSession
                                        .getWorkspace()
                                        .getObservationManager()
                                        .addEventListener(jcrProfileListener,
                                                        Event.PROPERTY_CHANGED | Event.NODE_ADDED, "/",
                                                        true, null, nodeTypes, true);
                } catch (Exception e) {
-                       JcrUtils.logoutQuietly(securitySession);
+                       JcrUtils.logoutQuietly(nodeSession);
                        throw new ArgeoException("Cannot initialize LDAP/JCR synchronizer",
                                        e);
                }
        }
 
        public void destroy() {
-               JcrUtils.removeListenerQuietly(securitySession, jcrProfileListener);
-               JcrUtils.logoutQuietly(securitySession);
+               JcrUtils.removeListenerQuietly(nodeSession, jcrProfileListener);
+               JcrUtils.logoutQuietly(nodeSession);
                try {
                        rawLdapTemplate.executeReadOnly(new ContextExecutor() {
                                public Object executeWithContext(DirContext ctx)
@@ -191,7 +190,7 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                                        });
 
                        // disable accounts which are not in LDAP
-                       Query query = securitySession
+                       Query query = nodeSession
                                        .getWorkspace()
                                        .getQueryManager()
                                        .createQuery(
@@ -207,28 +206,30 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                                                        + " not found in LDAP, disabling user "
                                                        + userProfile.getProperty(ArgeoNames.ARGEO_USER_ID)
                                                                        .getString());
-                                       VersionManager versionManager = securitySession
-                                                       .getWorkspace().getVersionManager();
+                                       VersionManager versionManager = nodeSession.getWorkspace()
+                                                       .getVersionManager();
                                        versionManager.checkout(userProfile.getPath());
                                        userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, false);
-                                       securitySession.save();
+                                       nodeSession.save();
                                        versionManager.checkin(userProfile.getPath());
                                }
                        }
                } catch (Exception e) {
-                       JcrUtils.discardQuietly(securitySession);
-                       throw new ArgeoException("Cannot synchronized LDAP and JCR", e);
+                       JcrUtils.discardQuietly(nodeSession);
+                       log.error("Cannot synchronize LDAP and JCR", e);
+                       // throw new ArgeoException("Cannot synchronize LDAP and JCR", e);
                }
        }
 
        /** Called during authentication in order to retrieve user details */
        public UserDetails mapUserFromContext(final DirContextOperations ctx,
                        final String username, GrantedAuthority[] authorities) {
-               log.debug("mapUserFromContext");
                if (ctx == null)
                        throw new ArgeoException("No LDAP information for user " + username);
-               Node userProfile = SecurityJcrUtils.createUserProfileIfNeeded(securitySession,
-                               username);
+
+               // Node userProfile = SecurityJcrUtils.createUserProfileIfNeeded(
+               // securitySession, username);
+               Node userProfile = jcrSecurityModel.sync(nodeSession, username);
                JcrUserDetails.checkAccountStatus(userProfile);
 
                // password
@@ -258,36 +259,38 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
         * @return path to user profile
         */
        protected synchronized String mapLdapToJcr(DirContextAdapter ctx) {
-               Session session = securitySession;
+               Session session = nodeSession;
                try {
                        // process
                        String username = ctx.getStringAttribute(usernameAttribute);
-                       Node userHome = SecurityJcrUtils.createUserHomeIfNeeded(session, username);
-                       Node userProfile; // = userHome.getNode(ARGEO_PROFILE);
-                       if (userHome.hasNode(ARGEO_PROFILE)) {
-                               userProfile = userHome.getNode(ARGEO_PROFILE);
-
-                               // compatibility with legacy, will be removed
-                               if (!userProfile.hasProperty(ARGEO_ENABLED)) {
-                                       session.getWorkspace().getVersionManager()
-                                                       .checkout(userProfile.getPath());
-                                       userProfile.setProperty(ARGEO_ENABLED, true);
-                                       userProfile.setProperty(ARGEO_ACCOUNT_NON_EXPIRED, true);
-                                       userProfile.setProperty(ARGEO_ACCOUNT_NON_LOCKED, true);
-                                       userProfile
-                                                       .setProperty(ARGEO_CREDENTIALS_NON_EXPIRED, true);
-                                       session.save();
-                                       session.getWorkspace().getVersionManager()
-                                                       .checkin(userProfile.getPath());
-                               }
-                       } else {
-                               userProfile = SecurityJcrUtils.createUserProfile(securitySession,
-                                               username);
-                               userProfile.getSession().save();
-                               userProfile.getSession().getWorkspace().getVersionManager()
-                                               .checkin(userProfile.getPath());
-                       }
-
+                       // Node userHome = SecurityJcrUtils.createUserHomeIfNeeded(session,
+                       // username);
+                       // Node userProfile; // = userHome.getNode(ARGEO_PROFILE);
+                       // if (userHome.hasNode(ARGEO_PROFILE)) {
+                       // userProfile = userHome.getNode(ARGEO_PROFILE);
+                       //
+                       // // compatibility with legacy, will be removed
+                       // if (!userProfile.hasProperty(ARGEO_ENABLED)) {
+                       // session.getWorkspace().getVersionManager()
+                       // .checkout(userProfile.getPath());
+                       // userProfile.setProperty(ARGEO_ENABLED, true);
+                       // userProfile.setProperty(ARGEO_ACCOUNT_NON_EXPIRED, true);
+                       // userProfile.setProperty(ARGEO_ACCOUNT_NON_LOCKED, true);
+                       // userProfile
+                       // .setProperty(ARGEO_CREDENTIALS_NON_EXPIRED, true);
+                       // session.save();
+                       // session.getWorkspace().getVersionManager()
+                       // .checkin(userProfile.getPath());
+                       // }
+                       // } else {
+                       // userProfile = SecurityJcrUtils.createUserProfile(
+                       // securitySession, username);
+                       // userProfile.getSession().save();
+                       // userProfile.getSession().getWorkspace().getVersionManager()
+                       // .checkin(userProfile.getPath());
+                       // }
+
+                       Node userProfile = jcrSecurityModel.sync(session, username);
                        Map<String, String> modifications = new HashMap<String, String>();
                        for (String jcrProperty : propertyToAttributes.keySet())
                                ldapToJcr(userProfile, jcrProperty, ctx, modifications);
@@ -375,8 +378,9 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
 
                final JcrUserDetails jcrUserDetails = (JcrUserDetails) user;
                try {
-                       Node userProfile = securitySession.getNode(
-                                       jcrUserDetails.getHomePath()).getNode(ARGEO_PROFILE);
+                       Node userProfile = nodeSession
+                                       .getNode(jcrUserDetails.getHomePath()).getNode(
+                                                       ARGEO_PROFILE);
                        for (String jcrProperty : propertyToAttributes.keySet()) {
                                if (userProfile.hasProperty(jcrProperty)) {
                                        ModificationItem mi = jcrToLdap(jcrProperty, userProfile
@@ -457,10 +461,6 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                this.repository = repository;
        }
 
-       public void setSecurityWorkspace(String securityWorkspace) {
-               this.securityWorkspace = securityWorkspace;
-       }
-
        public void setUserBase(String userBase) {
                this.userBase = userBase;
        }
@@ -489,6 +489,10 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                this.passwordEncoder = passwordEncoder;
        }
 
+       public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) {
+               this.jcrSecurityModel = jcrSecurityModel;
+       }
+
        /** Listen to LDAP */
        class LdapUserListener implements ObjectChangeListener,
                        NamespaceChangeListener, UnsolicitedNotificationListener {
@@ -550,7 +554,7 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                                        Event event = events.nextEvent();
                                        try {
                                                if (Event.PROPERTY_CHANGED == event.getType()) {
-                                                       Property property = (Property) securitySession
+                                                       Property property = (Property) nodeSession
                                                                        .getItem(event.getPath());
                                                        String propertyName = property.getName();
                                                        Node userProfile = property.getParent();
@@ -568,7 +572,7 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                                                                        modifications.get(name).add(mi);
                                                        }
                                                } else if (Event.NODE_ADDED == event.getType()) {
-                                                       Node userProfile = securitySession.getNode(event
+                                                       Node userProfile = nodeSession.getNode(event
                                                                        .getPath());
                                                        String username = userProfile.getProperty(
                                                                        ARGEO_USER_ID).getString();
index 332e94444812628401438299ad94dab68850ec4c..b7d4e030a2439b9267f66158146e3517b69a2a09 100644 (file)
@@ -32,7 +32,6 @@ import org.argeo.jcr.ArgeoTypes;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.jcr.UserJcrUtils;
 import org.argeo.jcr.security.JcrKeyring;
-import org.argeo.jcr.security.SecurityJcrUtils;
 import org.argeo.jcr.ui.explorer.JcrExplorerConstants;
 import org.eclipse.core.commands.AbstractHandler;
 import org.eclipse.core.commands.ExecutionEvent;
@@ -162,11 +161,6 @@ public class AddRemoteRepository extends AbstractHandler implements
                                Session nodeSession = keyring.getSession();
                                Node home = UserJcrUtils.getUserHome(nodeSession);
 
-                               // FIXME better deal with non existing home dir
-                               if (home == null)
-                                       home = SecurityJcrUtils.createUserHomeIfNeeded(nodeSession,
-                                                       nodeSession.getUserID());
-
                                Node remote = home.hasNode(ARGEO_REMOTE) ? home
                                                .getNode(ARGEO_REMOTE) : home.addNode(ARGEO_REMOTE);
                                if (remote.hasNode(name.getText()))
index 5cfb1d0fa79cf3940c88a6ebaf40df09880efd31..0e23f8893c974faf3aee5e3ac8a3c4b8932257f9 100644 (file)
  */
 package org.argeo.jcr;
 
-/** JCR related constants */
+/** Argeo model specific constants */
 public interface ArgeoJcrConstants {
        public final static String ARGEO_BASE_PATH = "/argeo:system";
        public final static String DATA_MODELS_BASE_PATH = ARGEO_BASE_PATH
                        + "/argeo:dataModels";
+       public final static String PEOPLE_BASE_PATH = ARGEO_BASE_PATH
+                       + "/argeo:people";
 
        // parameters (typically for call to a RepositoryFactory)
        public final static String JCR_REPOSITORY_ALIAS = "argeo.jcr.repository.alias";
index 3364ebfea896fbb79d391756bb8ec4cd27ae6e8e..0d889626ec065c2f9d7848a2ac3f7032187a06ba 100644 (file)
@@ -1289,6 +1289,23 @@ public class JcrUtils implements ArgeoJcrConstants {
                        Principal principal, List<Privilege> privs)
                        throws RepositoryException {
                AccessControlManager acm = session.getAccessControlManager();
+               AccessControlList acl = getAccessControlList(acm, path);
+               acl.addAccessControlEntry(principal,
+                               privs.toArray(new Privilege[privs.size()]));
+               acm.setPolicy(path, acl);
+               if (log.isDebugEnabled()) {
+                       StringBuffer privBuf = new StringBuffer();
+                       for (Privilege priv : privs)
+                               privBuf.append(priv.getName());
+                       log.debug("Added privileges " + privBuf + " to " + principal
+                                       + " on " + path);
+               }
+               session.save();
+       }
+
+       /** Gets access control list for this path, throws exception if not found */
+       public static AccessControlList getAccessControlList(
+                       AccessControlManager acm, String path) throws RepositoryException {
                // search for an access control list
                AccessControlList acl = null;
                AccessControlPolicyIterator policyIterator = acm
@@ -1307,19 +1324,21 @@ public class JcrUtils implements ArgeoJcrConstants {
                                        acl = ((AccessControlList) acp);
                        }
                }
+               if (acl != null)
+                       return acl;
+               else
+                       throw new ArgeoException("ACL not found at " + path);
+       }
 
-               if (acl != null) {
-                       acl.addAccessControlEntry(principal,
-                                       privs.toArray(new Privilege[privs.size()]));
-                       acm.setPolicy(path, acl);
-                       if (log.isDebugEnabled())
-                               log.debug("Added privileges " + privs + " to " + principal
-                                               + " on " + path);
-               } else {
-                       throw new ArgeoException("Don't know how to apply  privileges "
-                                       + privs + " to " + principal + " on " + path);
+       /** Clear authorizations for a user at this path */
+       public static void clearAccesControList(Session session, String path,
+                       String username) throws RepositoryException {
+               AccessControlManager acm = session.getAccessControlManager();
+               AccessControlList acl = getAccessControlList(acm, path);
+               for (AccessControlEntry ace : acl.getAccessControlEntries()) {
+                       if (ace.getPrincipal().getName().equals(username)) {
+                               acl.removeAccessControlEntry(ace);
+                       }
                }
-               session.save();
        }
-
 }
index 016347ada7064c089b74e404ce9ea57416849895..b357227a570a62d42ad36fd71d5b633519b45ba4 100644 (file)
@@ -3,19 +3,22 @@ package org.argeo.jcr;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.query.Query;
+import javax.jcr.query.qom.Constraint;
+import javax.jcr.query.qom.DynamicOperand;
+import javax.jcr.query.qom.QueryObjectModelFactory;
+import javax.jcr.query.qom.Selector;
+import javax.jcr.query.qom.StaticOperand;
 
 import org.argeo.ArgeoException;
 
 /** Utilities related to the user home and properties based on Argeo JCR model. */
 public class UserJcrUtils {
        /** The home base path. Not yet configurable */
-       public final static String DEFAULT_HOME_BASE_PATH = "/argeo:home";
-
-       private UserJcrUtils() {
-       }
+       public final static String DEFAULT_HOME_BASE_PATH = "/home";
 
        /**
-        * Returns the home node of the session user or null if none was found.
+        * Returns the home node of the user or null if none was found.
         * 
         * @param session
         *            the session to use in order to perform the search, this can be
@@ -26,23 +29,41 @@ public class UserJcrUtils {
         */
        public static Node getUserHome(Session session, String username) {
                try {
-                       String homePath = UserJcrUtils.getUserHomePath(username);
-                       return session.itemExists(homePath) ? session.getNode(homePath)
-                                       : null;
+                       // String homePath = UserJcrUtils.getUserHomePath(username);
+                       // return session.itemExists(homePath) ? session.getNode(homePath)
+                       // : null;
                        // kept for example of QOM queries
-                       // QueryObjectModelFactory qomf = session.getWorkspace()
-                       // .getQueryManager().getQOMFactory();
-                       // Selector userHomeSel = qomf.selector(ArgeoTypes.ARGEO_USER_HOME,
-                       // "userHome");
-                       // DynamicOperand userIdDop = qomf.propertyValue("userHome",
-                       // ArgeoNames.ARGEO_USER_ID);
-                       // StaticOperand userIdSop = qomf.literal(session.getValueFactory()
-                       // .createValue(username));
-                       // Constraint constraint = qomf.comparison(userIdDop,
-                       // QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, userIdSop);
-                       // Query query = qomf.createQuery(userHomeSel, constraint, null,
-                       // null);
-                       // Node userHome = JcrUtils.querySingleNode(query);
+                       QueryObjectModelFactory qomf = session.getWorkspace()
+                                       .getQueryManager().getQOMFactory();
+                       Selector userHomeSel = qomf.selector(ArgeoTypes.ARGEO_USER_HOME,
+                                       "userHome");
+                       DynamicOperand userIdDop = qomf.propertyValue(
+                                       userHomeSel.getSelectorName(), ArgeoNames.ARGEO_USER_ID);
+                       StaticOperand userIdSop = qomf.literal(session.getValueFactory()
+                                       .createValue(username));
+                       Constraint constraint = qomf.comparison(userIdDop,
+                                       QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, userIdSop);
+                       Query query = qomf.createQuery(userHomeSel, constraint, null, null);
+                       return JcrUtils.querySingleNode(query);
+               } catch (RepositoryException e) {
+                       throw new ArgeoException("Cannot find home for user " + username, e);
+               }
+       }
+
+       public static Node getUserProfile(Session session, String username) {
+               try {
+                       QueryObjectModelFactory qomf = session.getWorkspace()
+                                       .getQueryManager().getQOMFactory();
+                       Selector userHomeSel = qomf.selector(ArgeoTypes.ARGEO_USER_PROFILE,
+                                       "userProfile");
+                       DynamicOperand userIdDop = qomf.propertyValue(
+                                       userHomeSel.getSelectorName(), ArgeoNames.ARGEO_USER_ID);
+                       StaticOperand userIdSop = qomf.literal(session.getValueFactory()
+                                       .createValue(username));
+                       Constraint constraint = qomf.comparison(userIdDop,
+                                       QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, userIdSop);
+                       Query query = qomf.createQuery(userHomeSel, constraint, null, null);
+                       return JcrUtils.querySingleNode(query);
                } catch (RepositoryException e) {
                        throw new ArgeoException("Cannot find home for user " + username, e);
                }
@@ -54,11 +75,6 @@ public class UserJcrUtils {
                return getUserHome(session, userID);
        }
 
-       /** @deprecated Use {@link getUserHome} directly */
-       @Deprecated
-       static String getUserHomePath(String username) {
-               String homeBasePath = DEFAULT_HOME_BASE_PATH;
-               return homeBasePath + '/' + JcrUtils.firstCharsToPath(username, 2)
-                               + '/' + username;
+       private UserJcrUtils() {
        }
 }
index 1ba42197e049ae4ea955f64f2847df913ca74e36..90a8d87bdd124d08d2e9fa1e89fd7734dfde07f3 100644 (file)
@@ -13,12 +13,13 @@ import org.argeo.jcr.JcrUtils;
 import org.argeo.jcr.UserJcrUtils;
 
 /** Utilities related to Argeo security model in JCR */
+@Deprecated
 public class SecurityJcrUtils implements ArgeoJcrConstants {
        /**
         * Creates an Argeo user home, does nothing if it already exists. Session is
         * NOT saved.
         */
-       public static Node createUserHomeIfNeeded(Session session, String username) {
+       static Node createUserHomeIfNeeded(Session session, String username) {
                try {
                        String homePath = generateUserHomePath(username);
                        if (session.itemExists(homePath))
@@ -27,8 +28,9 @@ public class SecurityJcrUtils implements ArgeoJcrConstants {
                                Node userHome = JcrUtils.mkdirs(session, homePath);
                                userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
                                userHome.setProperty(ArgeoNames.ARGEO_USER_ID, username);
-                               
-                               //JcrUtils.addPrivilege(session, homePath, username, "jcr:all");
+
+                               // JcrUtils.addPrivilege(session, homePath, username,
+                               // "jcr:all");
                                return userHome;
                        }
                } catch (RepositoryException e) {
@@ -50,7 +52,7 @@ public class SecurityJcrUtils implements ArgeoJcrConstants {
         * is not saved and the node is in a checkedOut state (that is, it requires
         * a subsequent checkin after saving the session).
         */
-       public static Node createUserProfile(Session session, String username) {
+       static Node createUserProfile(Session session, String username) {
                try {
                        Node userHome = createUserHomeIfNeeded(session, username);
                        if (userHome.hasNode(ArgeoNames.ARGEO_PROFILE))
@@ -78,7 +80,7 @@ public class SecurityJcrUtils implements ArgeoJcrConstants {
         * 
         * @return the user profile
         */
-       public static Node createUserProfileIfNeeded(Session securitySession,
+       static Node createUserProfileIfNeeded(Session securitySession,
                        String username) {
                try {
                        Node userHome = createUserHomeIfNeeded(securitySession, username);
@@ -103,7 +105,7 @@ public class SecurityJcrUtils implements ArgeoJcrConstants {
        /**
         * @return null if not found *
         */
-       public static Node getUserProfile(Session session, String username) {
+       static Node getUserProfile(Session session, String username) {
                try {
                        Node userHome = UserJcrUtils.getUserHome(session, username);
                        if (userHome == null)