From: Mathieu Baudier Date: Sat, 29 Feb 2020 10:18:44 +0000 (+0100) Subject: Rename home repository into ego repository. X-Git-Tag: argeo-commons-2.1.87~1 X-Git-Url: https://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=commitdiff_plain;h=2afabd9e7b225f80b341063e25188314394c9aef Rename home repository into ego repository. --- diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/files/NodeFsBrowserView.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/files/NodeFsBrowserView.java index 5b79aaf02..59d7ed401 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/files/NodeFsBrowserView.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/files/NodeFsBrowserView.java @@ -47,7 +47,7 @@ public class NodeFsBrowserView { FileSystem fileSystem = nodeFileSystemProvider.getFileSystem(uri); if (fileSystem == null) fileSystem = nodeFileSystemProvider.newFileSystem(uri, null); - Path nodePath = fileSystem.getPath("~"); + Path nodePath = fileSystem.getPath("/"); Path localPath = Paths.get(System.getProperty("user.home")); diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java index 5b5c3ff82..3e328daa3 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java @@ -44,6 +44,7 @@ import org.argeo.eclipse.ui.TreeParent; import org.argeo.eclipse.ui.jcr.AsyncUiEventListener; import org.argeo.eclipse.ui.jcr.utils.NodeViewerComparer; import org.argeo.jcr.JcrUtils; +import org.argeo.node.NodeConstants; import org.argeo.node.security.CryptoKeyring; import org.argeo.node.security.Keyring; import org.eclipse.e4.core.contexts.IEclipseContext; @@ -114,7 +115,7 @@ public class JcrBrowserView { top.setLayout(CmsUtils.noSpaceGridLayout()); try { - this.userSession = this.nodeRepository.login(); + this.userSession = this.nodeRepository.login(NodeConstants.HOME); } catch (RepositoryException e) { throw new CmsException("Cannot open user session", e); } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java index 7a6ae0646..dc6459087 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java @@ -62,7 +62,6 @@ public class CmsDeployment implements NodeDeployment { private DataModels dataModels; private DeployConfig deployConfig; - private HomeRepository homeRepository; private Long availableSince; @@ -286,10 +285,10 @@ public class CmsDeployment implements NodeDeployment { // Publish home with the highest service ranking Hashtable regProps = new Hashtable<>(); - regProps.put(NodeConstants.CN, NodeConstants.HOME); + regProps.put(NodeConstants.CN, NodeConstants.EGO); regProps.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE); - homeRepository = new HomeRepository(deployedRepository, false); - bc.registerService(Repository.class, homeRepository, regProps); + Repository egoRepository = new EgoRepository(deployedRepository, false); + bc.registerService(Repository.class, egoRepository, regProps); // Keyring only if Argeo extensions are available if (argeoDataModelExtensionsAvailable) { @@ -297,7 +296,7 @@ public class CmsDeployment implements NodeDeployment { @Override public CallbackHandler addingService(ServiceReference reference) { - NodeKeyRing nodeKeyring = new NodeKeyRing(homeRepository); + NodeKeyRing nodeKeyring = new NodeKeyRing(egoRepository); CallbackHandler callbackHandler = bc.getService(reference); nodeKeyring.setDefaultCallbackHandler(callbackHandler); bc.registerService(LangUtils.names(Keyring.class, CryptoKeyring.class, ManagedService.class), diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsFsProvider.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsFsProvider.java index cf6249398..3304bb41d 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsFsProvider.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsFsProvider.java @@ -9,6 +9,7 @@ import java.util.HashMap; import java.util.Map; import javax.jcr.Node; +import javax.jcr.Property; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.RepositoryFactory; @@ -22,7 +23,6 @@ import org.argeo.jcr.fs.JcrFileSystem; import org.argeo.jcr.fs.JcrFileSystemProvider; import org.argeo.jcr.fs.JcrFsException; import org.argeo.node.NodeConstants; -import org.argeo.node.NodeTypes; import org.argeo.node.NodeUtils; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; @@ -52,15 +52,15 @@ public class CmsFsProvider extends AbstractJackrabbitFsProvider { URI repoUri = new URI("http", uri.getUserInfo(), uri.getHost(), uri.getPort(), "/jcr/node", null, null); RepositoryFactory repositoryFactory = bc.getService(bc.getServiceReference(RepositoryFactory.class)); Repository repository = NodeUtils.getRepositoryByUri(repositoryFactory, repoUri.toString()); - Session session = repository.login("main"); - CmsFileSystem fileSystem = new CmsFileSystem(this, session); +// Session session = repository.login("main"); + CmsFileSystem fileSystem = new CmsFileSystem(this, repository); fileSystems.put(username, fileSystem); return fileSystem; } else { Repository repository = bc.getService( - bc.getServiceReferences(Repository.class, "(cn=" + NodeConstants.HOME + ")").iterator().next()); - Session session = repository.login(); - CmsFileSystem fileSystem = new CmsFileSystem(this, session); + bc.getServiceReferences(Repository.class, "(cn=" + NodeConstants.EGO + ")").iterator().next()); +// Session session = repository.login(); + CmsFileSystem fileSystem = new CmsFileSystem(this, repository); fileSystems.put(username, fileSystem); return fileSystem; } @@ -92,13 +92,18 @@ public class CmsFsProvider extends AbstractJackrabbitFsProvider { return fileSystems.get(username); } - public Node getUserHome(Session session) { - return NodeUtils.getUserHome(session); + public Node getUserHome(Repository repository) { + try { + Session session = repository.login(NodeConstants.HOME); + return NodeUtils.getUserHome(session); + } catch (RepositoryException e) { + throw new IllegalStateException("Cannot get user home", e); + } } static class CmsFileSystem extends JcrFileSystem { - public CmsFileSystem(JcrFileSystemProvider provider, Session session) throws IOException { - super(provider, session); + public CmsFileSystem(JcrFileSystemProvider provider, Repository repository) throws IOException { + super(provider, repository); } public boolean skipNode(Node node) throws RepositoryException { @@ -106,6 +111,9 @@ public class CmsFsProvider extends AbstractJackrabbitFsProvider { // || node.isNodeType(NodeTypes.NODE_GROUP_HOME)) if (node.isNodeType(NodeType.NT_HIERARCHY_NODE)) return false; + // FIXME Better identifies home + if (node.hasProperty(Property.JCR_ID)) + return false; return true; } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsInstance.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsInstance.java index 14979711b..c972f725c 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsInstance.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsInstance.java @@ -17,7 +17,7 @@ public class CmsInstance implements NodeInstance { private final Log log = LogFactory.getLog(getClass()); private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext(); - private HomeRepository homeRepository; + private EgoRepository egoRepository; public CmsInstance() { initTrackers(); @@ -29,8 +29,8 @@ public class CmsInstance implements NodeInstance { @Override public Repository addingService(ServiceReference reference) { Object cn = reference.getProperty(NodeConstants.CN); - if (cn != null && cn.equals(NodeConstants.HOME)) { - homeRepository = (HomeRepository) bc.getService(reference); + if (cn != null && cn.equals(NodeConstants.EGO)) { + egoRepository = (EgoRepository) bc.getService(reference); if (log.isTraceEnabled()) log.trace("Home repository is available"); } @@ -40,7 +40,7 @@ public class CmsInstance implements NodeInstance { @Override public void removedService(ServiceReference reference, Repository service) { super.removedService(reference, service); - homeRepository = null; + egoRepository = null; } }.open(); @@ -52,10 +52,10 @@ public class CmsInstance implements NodeInstance { @Override public void createWorkgroup(LdapName dn) { - if (homeRepository == null) - throw new CmsException("Home repository is not available"); + if (egoRepository == null) + throw new CmsException("Ego repository is not available"); // TODO add check that the group exists - homeRepository.createWorkgroup(dn); + egoRepository.createWorkgroup(dn); } } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/EgoRepository.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/EgoRepository.java new file mode 100644 index 000000000..9c5e5f5f7 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/EgoRepository.java @@ -0,0 +1,263 @@ +package org.argeo.cms.internal.kernel; + +import java.security.PrivilegedAction; +import java.text.SimpleDateFormat; +import java.util.HashSet; +import java.util.Set; + +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; +import javax.jcr.security.Privilege; +import javax.naming.InvalidNameException; +import javax.naming.ldap.LdapName; +import javax.security.auth.Subject; +import javax.security.auth.login.LoginContext; + +import org.argeo.cms.CmsException; +import org.argeo.jcr.JcrRepositoryWrapper; +import org.argeo.jcr.JcrUtils; +import org.argeo.node.NodeConstants; +import org.argeo.node.NodeUtils; + +/** + * Make sure each user has a home directory available. + */ +class EgoRepository extends JcrRepositoryWrapper implements KernelConstants { + + /** The home base path. */ +// private String homeBasePath = KernelConstants.DEFAULT_HOME_BASE_PATH; +// private String usersBasePath = KernelConstants.DEFAULT_USERS_BASE_PATH; +// private String groupsBasePath = KernelConstants.DEFAULT_GROUPS_BASE_PATH; + + private Set checkedUsers = new HashSet(); + + private SimpleDateFormat usersDatePath = new SimpleDateFormat("YYYY/MM"); + + private String defaultHomeWorkspace = NodeConstants.HOME; + private String defaultGroupsWorkspace = NodeConstants.SRV; +// private String defaultGuestsWorkspace = NodeConstants.GUESTS; + private final boolean remote; + + public EgoRepository(Repository repository, boolean remote) { + super(repository); + this.remote = remote; + putDescriptor(NodeConstants.CN, NodeConstants.EGO); + if (!remote) { + LoginContext lc; + try { + lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_DATA_ADMIN); + lc.login(); + } catch (javax.security.auth.login.LoginException e1) { + throw new CmsException("Cannot login as systrem", e1); + } + Subject.doAs(lc.getSubject(), new PrivilegedAction() { + + @Override + public Void run() { + loginOrCreateWorkspace(defaultHomeWorkspace); + loginOrCreateWorkspace(defaultGroupsWorkspace); + return null; + } + + }); + } + } + + private void loginOrCreateWorkspace(String workspace) { + Session adminSession = null; + try { + adminSession = JcrUtils.loginOrCreateWorkspace(getRepository(workspace), workspace); +// JcrUtils.addPrivilege(adminSession, "/", NodeConstants.ROLE_USER, Privilege.JCR_READ); + +// initJcr(adminSession); + } catch (RepositoryException e) { + throw new CmsException("Cannot init JCR home", e); + } finally { + JcrUtils.logoutQuietly(adminSession); + } + } + +// @Override +// public Session login(Credentials credentials, String workspaceName) +// throws LoginException, NoSuchWorkspaceException, RepositoryException { +// if (workspaceName == null) { +// return super.login(credentials, getUserHomeWorkspace()); +// } else { +// return super.login(credentials, workspaceName); +// } +// } + + protected String getUserHomeWorkspace() { + // TODO base on JAAS Subject metadata + return defaultHomeWorkspace; + } + + protected String getGroupsWorkspace() { + // TODO base on JAAS Subject metadata + return defaultGroupsWorkspace; + } + +// protected String getGuestsWorkspace() { +// // TODO base on JAAS Subject metadata +// return defaultGuestsWorkspace; +// } + + @Override + protected void processNewSession(Session session, String workspaceName) { + String username = session.getUserID(); + if (username == null || username.toString().equals("")) + return; + if (session.getUserID().equals(NodeConstants.ROLE_ANONYMOUS)) + return; + + String userHomeWorkspace = getUserHomeWorkspace(); + if (workspaceName == null || !workspaceName.equals(userHomeWorkspace)) + return; + + if (checkedUsers.contains(username)) + return; + Session adminSession = KernelUtils.openAdminSession(getRepository(workspaceName), workspaceName); + try { + syncJcr(adminSession, username); + checkedUsers.add(username); + } finally { + JcrUtils.logoutQuietly(adminSession); + } + } + + /* + * JCR + */ + /** Session is logged out. */ + private void initJcr(Session adminSession) { + try { +// JcrUtils.mkdirs(adminSession, homeBasePath); +// JcrUtils.mkdirs(adminSession, groupsBasePath); + adminSession.save(); + +// JcrUtils.addPrivilege(adminSession, homeBasePath, NodeConstants.ROLE_USER_ADMIN, Privilege.JCR_READ); +// JcrUtils.addPrivilege(adminSession, groupsBasePath, NodeConstants.ROLE_USER_ADMIN, Privilege.JCR_READ); + adminSession.save(); + } catch (RepositoryException e) { + throw new CmsException("Cannot initialize home repository", e); + } finally { + JcrUtils.logoutQuietly(adminSession); + } + } + + protected synchronized void syncJcr(Session adminSession, String username) { + // only in the default workspace +// if (workspaceName != null) +// return; + // skip system users + if (username.endsWith(NodeConstants.ROLES_BASEDN)) + return; + + try { + Node userHome = NodeUtils.getUserHome(adminSession, username); + if (userHome == null) { +// String homePath = generateUserPath(username); + String userId = extractUserId(username); +// if (adminSession.itemExists(homePath))// duplicate user id +// userHome = adminSession.getNode(homePath).getParent().addNode(JcrUtils.lastPathElement(homePath)); +// else +// userHome = JcrUtils.mkdirs(adminSession, homePath); + userHome = adminSession.getRootNode().addNode(userId); +// userHome.addMixin(NodeTypes.NODE_USER_HOME); + userHome.addMixin(NodeType.MIX_CREATED); + userHome.addMixin(NodeType.MIX_TITLE); + userHome.setProperty(Property.JCR_ID, username); + // TODO use display name + userHome.setProperty(Property.JCR_TITLE, userId); +// userHome.setProperty(NodeNames.LDAP_UID, username); + adminSession.save(); + + JcrUtils.clearAccessControList(adminSession, userHome.getPath(), username); + JcrUtils.addPrivilege(adminSession, userHome.getPath(), username, Privilege.JCR_ALL); +// JackrabbitSecurityUtils.denyPrivilege(adminSession, userHome.getPath(), NodeConstants.ROLE_USER, +// Privilege.JCR_READ); + } + if (adminSession.hasPendingChanges()) + adminSession.save(); + } catch (RepositoryException e) { + JcrUtils.discardQuietly(adminSession); + throw new CmsException("Cannot sync node security model for " + username, e); + } + } + + /** Generate path for a new user home */ + private String generateUserPath(String username) { + LdapName dn; + try { + dn = new LdapName(username); + } catch (InvalidNameException e) { + throw new CmsException("Invalid name " + username, e); + } + String userId = dn.getRdn(dn.size() - 1).getValue().toString(); + return '/' + userId; +// int atIndex = userId.indexOf('@'); +// if (atIndex < 0) { +// return homeBasePath+'/' + userId; +// } else { +// return usersBasePath + '/' + usersDatePath.format(new Date()) + '/' + userId; +// } + } + + private String extractUserId(String username) { + LdapName dn; + try { + dn = new LdapName(username); + } catch (InvalidNameException e) { + throw new CmsException("Invalid name " + username, e); + } + String userId = dn.getRdn(dn.size() - 1).getValue().toString(); + return userId; +// int atIndex = userId.indexOf('@'); +// if (atIndex < 0) { +// return homeBasePath+'/' + userId; +// } else { +// return usersBasePath + '/' + usersDatePath.format(new Date()) + '/' + userId; +// } + } + + public void createWorkgroup(LdapName dn) { + String groupsWorkspace = getGroupsWorkspace(); + Session adminSession = KernelUtils.openAdminSession(getRepository(groupsWorkspace), groupsWorkspace); + String cn = dn.getRdn(dn.size() - 1).getValue().toString(); + Node newWorkgroup = NodeUtils.getGroupHome(adminSession, cn); + if (newWorkgroup != null) { + JcrUtils.logoutQuietly(adminSession); + throw new CmsException("Workgroup " + newWorkgroup + " already exists for " + dn); + } + try { + // TODO enhance transformation of cn to a valid node name + // String relPath = cn.replaceAll("[^a-zA-Z0-9]", "_"); + String relPath = JcrUtils.replaceInvalidChars(cn); + newWorkgroup = adminSession.getRootNode().addNode(relPath, NodeType.NT_UNSTRUCTURED); +// newWorkgroup = JcrUtils.mkdirs(adminSession.getNode(groupsBasePath), relPath, NodeType.NT_UNSTRUCTURED); +// newWorkgroup.addMixin(NodeTypes.NODE_GROUP_HOME); + newWorkgroup.addMixin(NodeType.MIX_CREATED); + newWorkgroup.addMixin(NodeType.MIX_TITLE); + newWorkgroup.setProperty(Property.JCR_ID, dn.toString()); + newWorkgroup.setProperty(Property.JCR_TITLE, cn); +// newWorkgroup.setProperty(NodeNames.LDAP_CN, cn); + adminSession.save(); + JcrUtils.addPrivilege(adminSession, newWorkgroup.getPath(), dn.toString(), Privilege.JCR_ALL); + adminSession.save(); + } catch (RepositoryException e) { + throw new CmsException("Cannot create workgroup", e); + } finally { + JcrUtils.logoutQuietly(adminSession); + } + + } + + public boolean isRemote() { + return remote; + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/HomeRepository.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/HomeRepository.java deleted file mode 100644 index 4b46b2cee..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/HomeRepository.java +++ /dev/null @@ -1,266 +0,0 @@ -package org.argeo.cms.internal.kernel; - -import java.security.PrivilegedAction; -import java.text.SimpleDateFormat; -import java.util.HashSet; -import java.util.Set; - -import javax.jcr.Credentials; -import javax.jcr.LoginException; -import javax.jcr.NoSuchWorkspaceException; -import javax.jcr.Node; -import javax.jcr.Property; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.nodetype.NodeType; -import javax.jcr.security.Privilege; -import javax.naming.InvalidNameException; -import javax.naming.ldap.LdapName; -import javax.security.auth.Subject; -import javax.security.auth.login.LoginContext; - -import org.argeo.cms.CmsException; -import org.argeo.jcr.JcrRepositoryWrapper; -import org.argeo.jcr.JcrUtils; -import org.argeo.node.NodeConstants; -import org.argeo.node.NodeUtils; - -/** - * Make sure each user has a home directory available in the default workspace. - */ -class HomeRepository extends JcrRepositoryWrapper implements KernelConstants { - - /** The home base path. */ -// private String homeBasePath = KernelConstants.DEFAULT_HOME_BASE_PATH; -// private String usersBasePath = KernelConstants.DEFAULT_USERS_BASE_PATH; -// private String groupsBasePath = KernelConstants.DEFAULT_GROUPS_BASE_PATH; - - private Set checkedUsers = new HashSet(); - - private SimpleDateFormat usersDatePath = new SimpleDateFormat("YYYY/MM"); - - private String defaultHomeWorkspace = NodeConstants.HOME; - private String defaultGroupsWorkspace = NodeConstants.SRV; -// private String defaultGuestsWorkspace = NodeConstants.GUESTS; - private final boolean remote; - - public HomeRepository(Repository repository, boolean remote) { - super(repository); - this.remote = remote; - putDescriptor(NodeConstants.CN, NodeConstants.HOME); - if (!remote) { - LoginContext lc; - try { - lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_DATA_ADMIN); - lc.login(); - } catch (javax.security.auth.login.LoginException e1) { - throw new CmsException("Cannot login as systrem", e1); - } - Subject.doAs(lc.getSubject(), new PrivilegedAction() { - - @Override - public Void run() { - loginOrCreateWorkspace(defaultHomeWorkspace); - loginOrCreateWorkspace(defaultGroupsWorkspace); - return null; - } - - }); - } - } - - private void loginOrCreateWorkspace(String workspace) { - Session adminSession = null; - try { - adminSession = JcrUtils.loginOrCreateWorkspace(getRepository(workspace), workspace); -// JcrUtils.addPrivilege(adminSession, "/", NodeConstants.ROLE_USER, Privilege.JCR_READ); - -// initJcr(adminSession); - } catch (RepositoryException e) { - throw new CmsException("Cannot init JCR home", e); - } finally { - JcrUtils.logoutQuietly(adminSession); - } - } - -// @Override -// public Session login(Credentials credentials, String workspaceName) -// throws LoginException, NoSuchWorkspaceException, RepositoryException { -// if (workspaceName == null) { -// return super.login(credentials, getUserHomeWorkspace()); -// } else { -// return super.login(credentials, workspaceName); -// } -// } - - protected String getUserHomeWorkspace() { - // TODO base on JAAS Subject metadata - return defaultHomeWorkspace; - } - - protected String getGroupsWorkspace() { - // TODO base on JAAS Subject metadata - return defaultGroupsWorkspace; - } - -// protected String getGuestsWorkspace() { -// // TODO base on JAAS Subject metadata -// return defaultGuestsWorkspace; -// } - - @Override - protected void processNewSession(Session session, String workspaceName) { - String username = session.getUserID(); - if (username == null || username.toString().equals("")) - return; - if (session.getUserID().equals(NodeConstants.ROLE_ANONYMOUS)) - return; - - String userHomeWorkspace = getUserHomeWorkspace(); - if (workspaceName == null || !workspaceName.equals(userHomeWorkspace)) - return; - - if (checkedUsers.contains(username)) - return; - Session adminSession = KernelUtils.openAdminSession(getRepository(workspaceName), workspaceName); - try { - syncJcr(adminSession, username); - checkedUsers.add(username); - } finally { - JcrUtils.logoutQuietly(adminSession); - } - } - - /* - * JCR - */ - /** Session is logged out. */ - private void initJcr(Session adminSession) { - try { -// JcrUtils.mkdirs(adminSession, homeBasePath); -// JcrUtils.mkdirs(adminSession, groupsBasePath); - adminSession.save(); - -// JcrUtils.addPrivilege(adminSession, homeBasePath, NodeConstants.ROLE_USER_ADMIN, Privilege.JCR_READ); -// JcrUtils.addPrivilege(adminSession, groupsBasePath, NodeConstants.ROLE_USER_ADMIN, Privilege.JCR_READ); - adminSession.save(); - } catch (RepositoryException e) { - throw new CmsException("Cannot initialize home repository", e); - } finally { - JcrUtils.logoutQuietly(adminSession); - } - } - - protected synchronized void syncJcr(Session adminSession, String username) { - // only in the default workspace -// if (workspaceName != null) -// return; - // skip system users - if (username.endsWith(NodeConstants.ROLES_BASEDN)) - return; - - try { - Node userHome = NodeUtils.getUserHome(adminSession, username); - if (userHome == null) { -// String homePath = generateUserPath(username); - String userId = extractUserId(username); -// if (adminSession.itemExists(homePath))// duplicate user id -// userHome = adminSession.getNode(homePath).getParent().addNode(JcrUtils.lastPathElement(homePath)); -// else -// userHome = JcrUtils.mkdirs(adminSession, homePath); - userHome = adminSession.getRootNode().addNode(userId); -// userHome.addMixin(NodeTypes.NODE_USER_HOME); - userHome.addMixin(NodeType.MIX_CREATED); - userHome.addMixin(NodeType.MIX_TITLE); - userHome.setProperty(Property.JCR_ID, username); - // TODO use display name - userHome.setProperty(Property.JCR_TITLE, userId); -// userHome.setProperty(NodeNames.LDAP_UID, username); - adminSession.save(); - - JcrUtils.clearAccessControList(adminSession, userHome.getPath(), username); - JcrUtils.addPrivilege(adminSession, userHome.getPath(), username, Privilege.JCR_ALL); -// JackrabbitSecurityUtils.denyPrivilege(adminSession, userHome.getPath(), NodeConstants.ROLE_USER, -// Privilege.JCR_READ); - } - if (adminSession.hasPendingChanges()) - adminSession.save(); - } catch (RepositoryException e) { - JcrUtils.discardQuietly(adminSession); - throw new CmsException("Cannot sync node security model for " + username, e); - } - } - - /** Generate path for a new user home */ - private String generateUserPath(String username) { - LdapName dn; - try { - dn = new LdapName(username); - } catch (InvalidNameException e) { - throw new CmsException("Invalid name " + username, e); - } - String userId = dn.getRdn(dn.size() - 1).getValue().toString(); - return '/' + userId; -// int atIndex = userId.indexOf('@'); -// if (atIndex < 0) { -// return homeBasePath+'/' + userId; -// } else { -// return usersBasePath + '/' + usersDatePath.format(new Date()) + '/' + userId; -// } - } - - private String extractUserId(String username) { - LdapName dn; - try { - dn = new LdapName(username); - } catch (InvalidNameException e) { - throw new CmsException("Invalid name " + username, e); - } - String userId = dn.getRdn(dn.size() - 1).getValue().toString(); - return userId; -// int atIndex = userId.indexOf('@'); -// if (atIndex < 0) { -// return homeBasePath+'/' + userId; -// } else { -// return usersBasePath + '/' + usersDatePath.format(new Date()) + '/' + userId; -// } - } - - public void createWorkgroup(LdapName dn) { - String groupsWorkspace = getGroupsWorkspace(); - Session adminSession = KernelUtils.openAdminSession(getRepository(groupsWorkspace), groupsWorkspace); - String cn = dn.getRdn(dn.size() - 1).getValue().toString(); - Node newWorkgroup = NodeUtils.getGroupHome(adminSession, cn); - if (newWorkgroup != null) { - JcrUtils.logoutQuietly(adminSession); - throw new CmsException("Workgroup " + newWorkgroup + " already exists for " + dn); - } - try { - // TODO enhance transformation of cn to a valid node name - // String relPath = cn.replaceAll("[^a-zA-Z0-9]", "_"); - String relPath = JcrUtils.replaceInvalidChars(cn); - newWorkgroup = adminSession.getRootNode().addNode(relPath, NodeType.NT_UNSTRUCTURED); -// newWorkgroup = JcrUtils.mkdirs(adminSession.getNode(groupsBasePath), relPath, NodeType.NT_UNSTRUCTURED); -// newWorkgroup.addMixin(NodeTypes.NODE_GROUP_HOME); - newWorkgroup.addMixin(NodeType.MIX_CREATED); - newWorkgroup.addMixin(NodeType.MIX_TITLE); - newWorkgroup.setProperty(Property.JCR_ID, dn.toString()); - newWorkgroup.setProperty(Property.JCR_TITLE, cn); -// newWorkgroup.setProperty(NodeNames.LDAP_CN, cn); - adminSession.save(); - JcrUtils.addPrivilege(adminSession, newWorkgroup.getPath(), dn.toString(), Privilege.JCR_ALL); - adminSession.save(); - } catch (RepositoryException e) { - throw new CmsException("Cannot create workgroup", e); - } finally { - JcrUtils.logoutQuietly(adminSession); - } - - } - - public boolean isRemote() { - return remote; - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/InitUtils.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/InitUtils.java index b09e009ed..6eaebeb64 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/InitUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/InitUtils.java @@ -47,7 +47,7 @@ class InitUtils { } static Dictionary getRepositoryConfig(String dataModelName, Dictionary provided) { - if (dataModelName.equals(NodeConstants.NODE) || dataModelName.equals(NodeConstants.HOME)) + if (dataModelName.equals(NodeConstants.NODE) || dataModelName.equals(NodeConstants.EGO)) throw new IllegalArgumentException("Data model '" + dataModelName + "' is reserved."); Dictionary props = provided != null ? provided : new Hashtable(); for (RepoConf repoConf : RepoConf.values()) { diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java index 3e2f25146..3174285db 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java @@ -66,7 +66,7 @@ public class NodeHttp implements KernelConstants { try { registerWebdavServlet(httpService, alias, repository); registerRemotingServlet(httpService, alias, repository); - if (NodeConstants.HOME.equals(alias)) + if (NodeConstants.EGO.equals(alias)) registerFilesServlet(httpService, alias, repository); if (log.isTraceEnabled()) log.trace("Registered servlets for repository '" + alias + "'"); @@ -81,7 +81,7 @@ public class NodeHttp implements KernelConstants { try { httpService.unregister(webdavPath(alias)); httpService.unregister(remotingPath(alias)); - if (NodeConstants.HOME.equals(alias)) + if (NodeConstants.EGO.equals(alias)) httpService.unregister(filesPath(alias)); if (log.isTraceEnabled()) log.trace("Unregistered servlets for repository '" + alias + "'"); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryServiceFactory.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryServiceFactory.java index 97a3e8d5a..be99bf20e 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryServiceFactory.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryServiceFactory.java @@ -90,10 +90,9 @@ class RepositoryServiceFactory implements ManagedServiceFactory { bc.registerService(Repository.class, repository, props); // home - // TODO make a sperate home configurable if (cn.equals(NodeConstants.NODE)) { - Dictionary homeProps = LangUtils.dico(NodeConstants.CN, NodeConstants.HOME); - HomeRepository homeRepository = new HomeRepository(repository, true); + Dictionary homeProps = LangUtils.dico(NodeConstants.CN, NodeConstants.EGO); + EgoRepository homeRepository = new EgoRepository(repository, true); bc.registerService(Repository.class, homeRepository, homeProps); } } catch (Exception e) { diff --git a/org.argeo.jcr/ext/test/org/argeo/jcr/fs/JcrFileSystemTest.java b/org.argeo.jcr/ext/test/org/argeo/jcr/fs/JcrFileSystemTest.java index 886efa367..2d03b8f2c 100644 --- a/org.argeo.jcr/ext/test/org/argeo/jcr/fs/JcrFileSystemTest.java +++ b/org.argeo.jcr/ext/test/org/argeo/jcr/fs/JcrFileSystemTest.java @@ -42,6 +42,8 @@ public class JcrFileSystemTest extends TestCase { Path rootPath = fsProvider.getPath(new URI("jcr+memory:/")); log.debug("Got root " + rootPath); + Path testDir = rootPath.resolve("testDir"); + Files.createDirectory(testDir); Path testMount = fsProvider.getPath(new URI("jcr+memory:/test")); log.debug("Test path"); @@ -58,6 +60,31 @@ public class JcrFileSystemTest extends TestCase { log.debug("Created " + testPath + " (" + ft + ")"); Files.delete(testPath); log.debug("Deleted " + testPath); + + // Browse directories from root + DirectoryStream files = Files.newDirectoryStream(rootPath); + int directoryCount = 0; + for (Path file : files) { + if (Files.isDirectory(file)) { + directoryCount++; + } + } + assertEquals(2, directoryCount); + + // Browse directories from mount + Path mountSubDir = testMount.resolve("mountSubDir"); + Files.createDirectory(mountSubDir); + Path otherSubDir = testMount.resolve("otherSubDir"); + Files.createDirectory(otherSubDir); + testPath = testMount.resolve("test.txt"); + Files.createFile(testPath); + files = Files.newDirectoryStream(testMount); + int fileCount = 0; + for (Path file : files) { + fileCount++; + } + assertEquals(3, fileCount); + } public void testSimple() throws Exception { diff --git a/org.argeo.jcr/src/org/argeo/jackrabbit/fs/DavexFsProvider.java b/org.argeo.jcr/src/org/argeo/jackrabbit/fs/DavexFsProvider.java index 764eed035..30cabbe65 100644 --- a/org.argeo.jcr/src/org/argeo/jackrabbit/fs/DavexFsProvider.java +++ b/org.argeo.jcr/src/org/argeo/jackrabbit/fs/DavexFsProvider.java @@ -78,7 +78,7 @@ public class DavexFsProvider extends AbstractJackrabbitFsProvider { } return tryGetRepo(repositoryFactory, nextUri, nextWorkspace); } else { - JcrFileSystem fileSystem = new JcrFileSystem(this, session); + JcrFileSystem fileSystem = new JcrFileSystem(this, repository); fileSystems.put(repoUri.toString() + "/" + workspace, fileSystem); return fileSystem; } diff --git a/org.argeo.jcr/src/org/argeo/jcr/fs/JcrFileStore.java b/org.argeo.jcr/src/org/argeo/jcr/fs/JcrFileStore.java deleted file mode 100644 index 32a3ecb5f..000000000 --- a/org.argeo.jcr/src/org/argeo/jcr/fs/JcrFileStore.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.argeo.jcr.fs; - -import java.io.IOException; -import java.nio.file.FileStore; -import java.nio.file.attribute.FileAttributeView; -import java.nio.file.attribute.FileStoreAttributeView; - -public class JcrFileStore extends FileStore { - - @Override - public String name() { - // TODO Auto-generated method stub - return null; - } - - @Override - public String type() { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean isReadOnly() { - // TODO Auto-generated method stub - return false; - } - - @Override - public long getTotalSpace() throws IOException { - // TODO Auto-generated method stub - return 0; - } - - @Override - public long getUsableSpace() throws IOException { - // TODO Auto-generated method stub - return 0; - } - - @Override - public long getUnallocatedSpace() throws IOException { - // TODO Auto-generated method stub - return 0; - } - - @Override - public boolean supportsFileAttributeView( - Class type) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean supportsFileAttributeView(String name) { - // TODO Auto-generated method stub - return false; - } - - @Override - public V getFileStoreAttributeView( - Class type) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Object getAttribute(String attribute) throws IOException { - // TODO Auto-generated method stub - return null; - } - -} diff --git a/org.argeo.jcr/src/org/argeo/jcr/fs/JcrFileSystem.java b/org.argeo.jcr/src/org/argeo/jcr/fs/JcrFileSystem.java index 4c8355f97..3d538e8bd 100644 --- a/org.argeo.jcr/src/org/argeo/jcr/fs/JcrFileSystem.java +++ b/org.argeo.jcr/src/org/argeo/jcr/fs/JcrFileSystem.java @@ -10,6 +10,7 @@ import java.nio.file.attribute.UserPrincipalLookupService; import java.nio.file.spi.FileSystemProvider; import java.util.ArrayList; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -22,12 +23,14 @@ import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.nodetype.NodeType; +import org.argeo.jcr.Jcr; import org.argeo.jcr.JcrUtils; public class JcrFileSystem extends FileSystem { private final JcrFileSystemProvider provider; - private final Session session; + private final Repository repository; + private Session session; private WorkspaceFileStore baseFileStore; private Map mounts = new TreeMap<>(); @@ -40,13 +43,14 @@ public class JcrFileSystem extends FileSystem { this.provider = provider; baseFileStore = new WorkspaceFileStore(null, session.getWorkspace()); this.session = session; - Node userHome = provider.getUserHome(session); - if (userHome != null) - try { - userHomePath = userHome.getPath(); - } catch (RepositoryException e) { - throw new IOException("Cannot retrieve user home path", e); - } +// Node userHome = provider.getUserHome(session); +// if (userHome != null) +// try { +// userHomePath = userHome.getPath(); +// } catch (RepositoryException e) { +// throw new IOException("Cannot retrieve user home path", e); +// } + this.repository = null; } public JcrFileSystem(JcrFileSystemProvider provider, Repository repository) throws IOException { @@ -57,12 +61,17 @@ public class JcrFileSystem extends FileSystem { throws IOException { super(); this.provider = provider; + this.repository = repository; try { this.session = credentials == null ? repository.login() : repository.login(credentials); baseFileStore = new WorkspaceFileStore(null, session.getWorkspace()); workspaces: for (String workspaceName : baseFileStore.getWorkspace().getAccessibleWorkspaceNames()) { if (workspaceName.equals(baseFileStore.getWorkspace().getName())) continue workspaces;// do not mount base + if (workspaceName.equals("security")) { + continue workspaces;// do not mount security workspace + // TODO make it configurable + } Session mountSession = credentials == null ? repository.login(workspaceName) : repository.login(credentials, workspaceName); String mountPath = JcrPath.separator + workspaceName; @@ -72,15 +81,21 @@ public class JcrFileSystem extends FileSystem { throw new IOException("Cannot initialise file system", e); } - Node userHome = provider.getUserHome(session); + Node userHome = provider.getUserHome(repository); if (userHome != null) try { - userHomePath = userHome.getPath(); + userHomePath = toFsPath(userHome); } catch (RepositoryException e) { throw new IOException("Cannot retrieve user home path", e); + } finally { + JcrUtils.logoutQuietly(Jcr.session(userHome)); } } + public String toFsPath(Node node) throws RepositoryException { + return getFileStore(node).toFsPath(node); + } + /** Whether this node should be skipped in directory listings */ public boolean skipNode(Node node) throws RepositoryException { if (node.isNodeType(NodeType.NT_HIERARCHY_NODE)) @@ -95,7 +110,9 @@ public class JcrFileSystem extends FileSystem { public WorkspaceFileStore getFileStore(String path) { WorkspaceFileStore res = baseFileStore; for (String mountPath : mounts.keySet()) { - if (path.startsWith(mountPath)) { + if (path.equals(mountPath)) + return mounts.get(mountPath); + if (path.startsWith(mountPath + JcrPath.separator)) { res = mounts.get(mountPath); // we keep the last one } @@ -116,6 +133,22 @@ public class JcrFileSystem extends FileSystem { throw new IllegalStateException("No workspace mount found for " + node + " in workspace " + workspaceName); } + public Iterator listDirectMounts(Path base) { + String baseStr = base.toString(); + Set res = new HashSet<>(); + mounts: for (String mountPath : mounts.keySet()) { + if (mountPath.equals(baseStr)) + continue mounts; + if (mountPath.startsWith(baseStr)) { + JcrPath path = new JcrPath(this, mountPath); + Path relPath = base.relativize(path); + if (relPath.getNameCount() == 1) + res.add(path); + } + } + return res.iterator(); + } + public WorkspaceFileStore getBaseFileStore() { return baseFileStore; } @@ -206,8 +239,12 @@ public class JcrFileSystem extends FileSystem { throw new UnsupportedOperationException(); } - public Session getSession() { - return session; +// public Session getSession() { +// return session; +// } + + public Repository getRepository() { + return repository; } } diff --git a/org.argeo.jcr/src/org/argeo/jcr/fs/JcrFileSystemProvider.java b/org.argeo.jcr/src/org/argeo/jcr/fs/JcrFileSystemProvider.java index a9ea14826..7a38ba370 100644 --- a/org.argeo.jcr/src/org/argeo/jcr/fs/JcrFileSystemProvider.java +++ b/org.argeo.jcr/src/org/argeo/jcr/fs/JcrFileSystemProvider.java @@ -25,6 +25,7 @@ import javax.jcr.Node; import javax.jcr.Property; import javax.jcr.PropertyIterator; import javax.jcr.PropertyType; +import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.nodetype.NodeType; @@ -69,7 +70,8 @@ public abstract class JcrFileSystemProvider extends FileSystemProvider { Node base = toNode(dir); if (base == null) throw new IOException(dir + " is not a JCR node"); - return new NodeDirectoryStream((JcrFileSystem) dir.getFileSystem(), base.getNodes(), filter); + JcrFileSystem fileSystem = (JcrFileSystem) dir.getFileSystem(); + return new NodeDirectoryStream(fileSystem, base.getNodes(), fileSystem.listDirectMounts(dir), filter); } catch (RepositoryException e) { throw new IOException("Cannot list directory", e); } @@ -194,14 +196,10 @@ public abstract class JcrFileSystemProvider extends FileSystemProvider { @Override public void checkAccess(Path path, AccessMode... modes) throws IOException { - try { - Session session = ((JcrFileSystem) path.getFileSystem()).getSession(); - if (!session.itemExists(path.toString())) - throw new NoSuchFileException(path + " does not exist"); - // TODO check access via JCR api - } catch (RepositoryException e) { - throw new IOException("Cannot delete " + path, e); - } + Node node = toNode(path); + if (node == null) + throw new NoSuchFileException(path + " does not exist"); + // TODO check access via JCR api } @Override @@ -317,7 +315,7 @@ public abstract class JcrFileSystemProvider extends FileSystemProvider { * * @return null by default */ - public Node getUserHome(Session session) { + public Node getUserHome(Repository session) { return null; } diff --git a/org.argeo.jcr/src/org/argeo/jcr/fs/NodeDirectoryStream.java b/org.argeo.jcr/src/org/argeo/jcr/fs/NodeDirectoryStream.java index 84dd22d6a..eda07a548 100644 --- a/org.argeo.jcr/src/org/argeo/jcr/fs/NodeDirectoryStream.java +++ b/org.argeo.jcr/src/org/argeo/jcr/fs/NodeDirectoryStream.java @@ -11,11 +11,14 @@ import javax.jcr.NodeIterator; public class NodeDirectoryStream implements DirectoryStream { private final JcrFileSystem fs; private final NodeIterator nodeIterator; + private final Iterator additionalPaths; private final Filter filter; - public NodeDirectoryStream(JcrFileSystem fs, NodeIterator nodeIterator, Filter filter) { + public NodeDirectoryStream(JcrFileSystem fs, NodeIterator nodeIterator, Iterator additionalPaths, + Filter filter) { this.fs = fs; this.nodeIterator = nodeIterator; + this.additionalPaths = additionalPaths; this.filter = filter; } @@ -50,6 +53,12 @@ public class NodeDirectoryStream implements DirectoryStream { throw new JcrFsException("Could not get next path", e); } } + + if (next == null) { + if (additionalPaths.hasNext()) + next = additionalPaths.next(); + } + return next != null; } diff --git a/org.argeo.jcr/src/org/argeo/jcr/fs/SessionFsProvider.java b/org.argeo.jcr/src/org/argeo/jcr/fs/SessionFsProvider.java deleted file mode 100644 index 3c5bf163a..000000000 --- a/org.argeo.jcr/src/org/argeo/jcr/fs/SessionFsProvider.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.argeo.jcr.fs; - -import java.io.IOException; -import java.net.URI; -import java.nio.file.FileSystem; -import java.nio.file.FileSystemAlreadyExistsException; -import java.nio.file.Path; -import java.util.Map; - -import javax.jcr.Session; - -/** An FS provider based on a single JCR session (experimental). */ -public class SessionFsProvider extends JcrFileSystemProvider { - private Session session; - private JcrFileSystem fileSystem; - - public SessionFsProvider(Session session) { - this.session = session; - } - - @Override - public String getScheme() { - return "jcr+session"; - } - - @Override - public FileSystem newFileSystem(URI uri, Map env) throws IOException { - if (fileSystem != null && fileSystem.isOpen()) - throw new FileSystemAlreadyExistsException(); - fileSystem = new JcrFileSystem(this, session) { - boolean open; - - @Override - public void close() throws IOException { - // prevent the session logout - open = false; - } - - @Override - public boolean isOpen() { - return open; - } - - }; - return fileSystem; - } - - @Override - public FileSystem getFileSystem(URI uri) { - return fileSystem; - } - - @Override - public Path getPath(URI uri) { - return new JcrPath(fileSystem, uri.getPath()); - } - -} diff --git a/org.argeo.node.api/src/org/argeo/node/NodeConstants.java b/org.argeo.node.api/src/org/argeo/node/NodeConstants.java index 50647de50..c639c7584 100644 --- a/org.argeo.node.api/src/org/argeo/node/NodeConstants.java +++ b/org.argeo.node.api/src/org/argeo/node/NodeConstants.java @@ -23,8 +23,9 @@ public interface NodeConstants { * COMMON NAMES */ String NODE = "node"; + String EGO = "ego"; String HOME = "home"; - String SRV = "groups"; + String SRV = "srv"; String GUESTS = "guests"; String PUBLIC = "public";