diff --git a/config/alfresco/bootstrap/alfrescoAuthorityStore.xml b/config/alfresco/bootstrap/alfrescoAuthorityStore.xml index 8febc87fb4..4c6125cc69 100644 --- a/config/alfresco/bootstrap/alfrescoAuthorityStore.xml +++ b/config/alfresco/bootstrap/alfrescoAuthorityStore.xml @@ -58,6 +58,72 @@ Read + + + + + + + + AUTH.ALF + AUTH.ALF + + + + + + + + + + + + + + + + + + + + + + APP.DEFAULT + APP.DEFAULT + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/ehcache-default.xml b/config/alfresco/ehcache-default.xml index 6aa9af1a79..021dc71817 100644 --- a/config/alfresco/ehcache-default.xml +++ b/config/alfresco/ehcache-default.xml @@ -382,7 +382,7 @@ @@ -390,7 +390,7 @@ diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties index 5ec5daa8b6..e379a0afb4 100644 --- a/config/alfresco/messages/patch-service.properties +++ b/config/alfresco/messages/patch-service.properties @@ -274,3 +274,7 @@ patch.zonedAuthorities.description=Adds the remodelled cm:authority container to patch.authorityMigration.description=Copies any old authorities from the user store to the spaces store. patch.authorityMigration.result=Migrated {0} authorities to the spaces store. + +patch.authorityDefaultZonesPatch.description=Adds groups and people to the appropriate zones for wcm, share and everything else. +patch.authorityDefaultZonesPatch.result=Unzoned groups and people added to the default zones. + diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index 9c25c30fda..80cd95e18e 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -1807,5 +1807,30 @@ + + + patch.authorityDefaultZonesPatch + patch.authorityDefaultZonesPatch.description + 0 + 2013 + 2014 + + + + + + + + + + + + + + + + + + diff --git a/config/alfresco/public-services-security-context.xml b/config/alfresco/public-services-security-context.xml index 48596f0498..77a7115472 100644 --- a/config/alfresco/public-services-security-context.xml +++ b/config/alfresco/public-services-security-context.xml @@ -693,10 +693,11 @@ org.alfresco.service.cmr.security.AuthorityService.hasAdminAuthority=ACL_ALLOW org.alfresco.service.cmr.security.AuthorityService.isAdminAuthority=ACL_ALLOW org.alfresco.service.cmr.security.AuthorityService.getAuthorities=ACL_ALLOW + org.alfresco.service.cmr.security.AuthorityService.getAuthoritiesForUser=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.security.AuthorityService.getAllAuthorities=ACL_ALLOW + org.alfresco.service.cmr.security.AuthorityService.findAuthoritiesByShortName=ACL_ALLOW + org.alfresco.service.cmr.security.AuthorityService.findAuthorities=ACL_ALLOW org.alfresco.service.cmr.security.AuthorityService.getAllRootAuthorities=ACL_ALLOW - org.alfresco.service.cmr.security.AuthorityService.findAuthoritiesByShortName=ACL_ALLOW - org.alfresco.service.cmr.security.AuthorityService.findAuthorities=ACL_ALLOW org.alfresco.service.cmr.security.AuthorityService.createAuthority=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.security.AuthorityService.addAuthority=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.security.AuthorityService.removeAuthority=ACL_METHOD.ROLE_ADMINISTRATOR @@ -706,9 +707,15 @@ org.alfresco.service.cmr.security.AuthorityService.getShortName=ACL_ALLOW org.alfresco.service.cmr.security.AuthorityService.getName=ACL_ALLOW org.alfresco.service.cmr.security.AuthorityService.authorityExists=ACL_ALLOW - org.alfresco.service.cmr.security.AuthorityService.getAuthoritiesForUser=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.security.AuthorityService.setAuthorityDisplayName=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.security.AuthorityService.getAuthorityDisplayName=ACL_ALLOW + org.alfresco.service.cmr.security.AuthorityService.getOrCreateZone=ACL_METHOD.ROLE_ADMINISTRATOR + org.alfresco.service.cmr.security.AuthorityService.getAuthorityZones=ACL_ALLOW + org.alfresco.service.cmr.security.AuthorityService.getAllAuthoritiesInZone=ACL_ALLOW + org.alfresco.service.cmr.security.AuthorityService.getAllRootAuthoritiesInZone=ACL_ALLOW + org.alfresco.service.cmr.security.AuthorityService.addAuthorityToZones=ACL_METHOD.ROLE_ADMINISTRATOR + org.alfresco.service.cmr.security.AuthorityService.removeAuthorityFromZones=ACL_METHOD.ROLE_ADMINISTRATOR + org.alfresco.service.cmr.security.AuthorityService.getDefaultZones=ACL_ALLOW diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties index 046e12648c..900c70e119 100644 --- a/config/alfresco/version.properties +++ b/config/alfresco/version.properties @@ -19,4 +19,4 @@ version.build=@build-number@ # Schema number -version.schema=2013 +version.schema=2014 diff --git a/source/java/org/alfresco/repo/admin/patch/impl/AuthorityDefaultZonesPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/AuthorityDefaultZonesPatch.java new file mode 100644 index 0000000000..83aaab497c --- /dev/null +++ b/source/java/org/alfresco/repo/admin/patch/impl/AuthorityDefaultZonesPatch.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2005-2009 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.admin.patch.impl; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.domain.hibernate.HibernateSessionHelper; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avm.AVMStoreDescriptor; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.AuthorityType; +import org.alfresco.service.cmr.site.SiteInfo; +import org.alfresco.service.cmr.site.SiteService; + +/** + * Patch to assign users and groups to default zones + * + * @author andyh + */ +public class AuthorityDefaultZonesPatch extends AbstractPatch +{ + /** Success message. */ + private static final String MSG_SUCCESS = "patch.authorityDefaultZonesPatch.result"; + + /** The authority service. */ + private AuthorityService authorityService; + + private AVMService avmService; + + private SiteService siteService; + + private HibernateSessionHelper hibernateSessionHelper; + + /** + * Sets the authority service. + * + * @param authorityService + * the authority service + */ + public void setAuthorityService(AuthorityService authorityService) + { + this.authorityService = authorityService; + } + + /** + * Set the avm service + * @param avmService + */ + public void setAvmService(AVMService avmService) + { + this.avmService = avmService; + } + + /** + * Set the site service + * @param siteService + */ + public void setSiteService(SiteService siteService) + { + this.siteService = siteService; + } + + /** + * @param hibernateSessionHelper + */ + public void setHibernateSessionHelper(HibernateSessionHelper hibernateSessionHelper) + { + this.hibernateSessionHelper = hibernateSessionHelper; + } + + @Override + protected String applyInternal() throws Exception + { + setZonesForPeople(); + setZonesForGroups(); + + return MSG_SUCCESS; + + } + + private void setZonesForPeople() + { + Set defaultZones = new HashSet(2, 1.0f); + defaultZones.add(AuthorityService.ZONE_APP_DEFAULT); + defaultZones.add(AuthorityService.ZONE_AUTH_ALFRESCO); + + List personActions = new ArrayList(1); + personActions.add(new Action(null, defaultZones, ActionType.ADD)); + + setZones(AuthorityType.USER, personActions); + + } + + private void setZonesForGroups() + { + Set defaultZones = new HashSet(2, 1.0f); + defaultZones.add(AuthorityService.ZONE_APP_DEFAULT); + defaultZones.add(AuthorityService.ZONE_AUTH_ALFRESCO); + + Set wcmZones = new HashSet(2, 1.0f); + wcmZones.add(AuthorityService.ZONE_APP_WCM); + wcmZones.add(AuthorityService.ZONE_AUTH_ALFRESCO); + + Set shareZones = new HashSet(2, 1.0f); + shareZones.add(AuthorityService.ZONE_APP_SHARE); + shareZones.add(AuthorityService.ZONE_AUTH_ALFRESCO); + + List stores = avmService.getStores(); + List sites = siteService.listSites(null, null); + + List groupActions = new ArrayList(stores.size() * 4 + sites.size() * 5 + 1); + for (AVMStoreDescriptor store : stores) + { + groupActions.add(new Action("GROUP_"+store.getName()+"-ContentManager", wcmZones, ActionType.ADD)); + groupActions.add(new Action("GROUP_"+store.getName()+"-ContentPublisher", wcmZones, ActionType.ADD)); + groupActions.add(new Action("GROUP_"+store.getName()+"-ContentContributor", wcmZones, ActionType.ADD)); + groupActions.add(new Action("GROUP_"+store.getName()+"-ContentReviewer", wcmZones, ActionType.ADD)); + } + for (SiteInfo site : sites) + { + groupActions.add(new Action("GROUP_site_" + site.getShortName(), shareZones, ActionType.ADD)); + groupActions.add(new Action("GROUP_site_" + site.getShortName()+"_SiteManager", shareZones, ActionType.ADD)); + groupActions.add(new Action("GROUP_site_" + site.getShortName()+"_SiteCollaborator", shareZones, ActionType.ADD)); + groupActions.add(new Action("GROUP_site_" + site.getShortName()+"_SiteContributor", shareZones, ActionType.ADD)); + groupActions.add(new Action("GROUP_site_" + site.getShortName()+"_SiteConsumer", shareZones, ActionType.ADD)); + } + groupActions.add(new Action(null, defaultZones, ActionType.ADD)); + + setZones(AuthorityType.GROUP, groupActions); + + } + + private void setZones(AuthorityType authorityType, List actions) + { + + //hibernateSessionHelper.mark(); + Set authorities = authorityService.getAllAuthorities(authorityType); + //hibernateSessionHelper.reset(); + for (String authority : authorities) + { + for (Action action : actions) + { + if (action.name != null) + { + if (action.name.equals(authority)) + { + fixAuthority(action.actionType, action.zones, authority); + break; + } + } + else + { + fixAuthority(action.actionType, action.zones, authority); + break; + } + } + //hibernateSessionHelper.reset(); + } + } + + private void fixAuthority(ActionType actionType, Set zones, String authority) + { + Set current; + switch (actionType) + { + case ADD: + authorityService.addAuthorityToZones(authority, zones); + break; + case SET: + current = authorityService.getAuthorityZones(authority); + authorityService.removeAuthorityFromZones(authority, current); + authorityService.addAuthorityToZones(authority, zones); + break; + case SET_IF_UNSET: + current = authorityService.getAuthorityZones(authority); + if (current.size() == 0) + { + authorityService.addAuthorityToZones(authority, zones); + + } + break; + } + } + + private enum ActionType + { + ADD, SET, SET_IF_UNSET; + } + + private static class Action + { + String name; + + Set zones; + + ActionType actionType; + + Action(String name, Set zones, ActionType actionType) + { + this.name = name; + this.zones = zones; + this.actionType = actionType; + } + } + +} diff --git a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java index 7ade1a1b15..c63d954974 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java @@ -815,11 +815,11 @@ public class IndexInfo implements IndexMonitor { indexEntries.put(id, new IndexEntry(IndexType.DELTA, id, "", TransactionStatus.ACTIVE, "", 0, 0, false)); } - // Downgrade lock - getReadLock(); + } finally - { + { // Downgrade lock + getReadLock(); releaseWriteLock(); } } @@ -1075,11 +1075,11 @@ public class IndexInfo implements IndexMonitor getWriteLock(); try { - mainIndexReader = null; - getReadLock(); + mainIndexReader = null; } finally { + getReadLock(); releaseWriteLock(); } } @@ -1110,10 +1110,11 @@ public class IndexInfo implements IndexMonitor mainIndexReader = createMainIndexReader(); } - getReadLock(); + } finally { + getReadLock(); releaseWriteLock(); } } @@ -1162,10 +1163,10 @@ public class IndexInfo implements IndexMonitor try { mainIndexReader = null; - getReadLock(); } finally { + getReadLock(); releaseWriteLock(); } } @@ -1195,10 +1196,10 @@ public class IndexInfo implements IndexMonitor mainIndexReader = createMainIndexReader(); } - getReadLock(); } finally { + getReadLock(); releaseWriteLock(); } } @@ -1294,10 +1295,10 @@ public class IndexInfo implements IndexMonitor } dumpInfo(); } - getReadLock(); } finally { + getReadLock(); releaseWriteLock(); } } @@ -3073,10 +3074,10 @@ public class IndexInfo implements IndexMonitor return true; } }); - getReadLock(); } finally { + getReadLock(); releaseWriteLock(); } } @@ -3342,10 +3343,10 @@ public class IndexInfo implements IndexMonitor } }); - getReadLock(); } finally { + getReadLock(); releaseWriteLock(); } diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityDAO.java b/source/java/org/alfresco/repo/security/authority/AuthorityDAO.java index 500c1b236e..46f9390c17 100644 --- a/source/java/org/alfresco/repo/security/authority/AuthorityDAO.java +++ b/source/java/org/alfresco/repo/security/authority/AuthorityDAO.java @@ -45,9 +45,9 @@ public interface AuthorityDAO * * @param name * @param authorityDisplayName - * @param authorityZone + * @param authorityZones */ - void createAuthority(String name, String authorityDisplayName, String authorityZone); + void createAuthority(String name, String authorityDisplayName, Set authorityZones); /** * Delete an authority. @@ -163,10 +163,10 @@ public interface AuthorityDAO * * @param name * the authority long name - * @return the the name of the zone containing the specified authority, {@link AuthorityService#DEFAULT_ZONE} if the + * @return the set of names of all zones containing the specified authority, an empty set if the * authority exists but has no zone, or null if the authority does not exist. */ - public String getAuthorityZone(String name); + public Set getAuthorityZones(String name); /** * Gets the names of all authorities in a zone, optionally filtered by type. @@ -178,4 +178,26 @@ public interface AuthorityDAO * @return the names of all authorities in a zone, optionally filtered by type */ public Set getAllAuthoritiesInZone(String zoneName, AuthorityType type); + + /** + * Add an authority to zones + * @param authorityName + * @param zones + */ + public void addAuthorityToZones(String authorityName, Set zones); + + /** + * Remove an authority from zones. + * @param authorityName + * @param zones + */ + public void removeAuthorityFromZones(String authorityName, Set zones); + + /** + * Get all root authorities in a zone + * @param zoneName + * @param type (optional) + * @return the set of authority names + */ + public Set getAllRootAuthoritiesInZone(String zoneName, AuthorityType type); } diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java b/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java index 67b96ccca6..56ef3aaa1d 100644 --- a/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java +++ b/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java @@ -122,37 +122,36 @@ public class AuthorityDAOImpl implements AuthorityDAO throw new UnknownAuthorityException("An authority was not found for " + parentName); } AuthorityType authorityType = AuthorityType.getAuthorityType(childName); - if (!authorityType.equals(AuthorityType.USER) && !authorityType.equals(AuthorityType.GROUP) - && !(authorityType.equals(AuthorityType.ROLE) && AuthorityType.getAuthorityType(parentName).equals( - AuthorityType.ROLE))) + if (!authorityType.equals(AuthorityType.USER) + && !authorityType.equals(AuthorityType.GROUP) + && !(authorityType.equals(AuthorityType.ROLE) && AuthorityType.getAuthorityType(parentName).equals(AuthorityType.ROLE))) { - throw new AlfrescoRuntimeException("Authorities of the type " + authorityType - + " may not be added to other authorities"); + throw new AlfrescoRuntimeException("Authorities of the type " + authorityType + " may not be added to other authorities"); } NodeRef childRef = getAuthorityOrNull(childName); if (childRef == null) { throw new UnknownAuthorityException("An authority was not found for " + childName); } - nodeService.addChild(parentRef, childRef, ContentModel.ASSOC_MEMBER, QName.createQName("cm", childName, - namespacePrefixResolver)); + nodeService.addChild(parentRef, childRef, ContentModel.ASSOC_MEMBER, QName.createQName("cm", childName, namespacePrefixResolver)); authorityLookupCache.clear(); } - public void createAuthority(String name, String authorityDisplayName, String authorityZone) + public void createAuthority(String name, String authorityDisplayName, Set authorityZones) { HashMap props = new HashMap(); props.put(ContentModel.PROP_AUTHORITY_NAME, name); props.put(ContentModel.PROP_AUTHORITY_DISPLAY_NAME, authorityDisplayName); NodeRef childRef; NodeRef authorityContainerRef = getAuthorityContainer(); - childRef = nodeService.createNode(authorityContainerRef, ContentModel.ASSOC_CHILDREN, - QName.createQName("cm", name, namespacePrefixResolver), ContentModel.TYPE_AUTHORITY_CONTAINER, props) - .getChildRef(); - if (authorityZone != null) + childRef = nodeService.createNode(authorityContainerRef, ContentModel.ASSOC_CHILDREN, QName.createQName("cm", name, namespacePrefixResolver), + ContentModel.TYPE_AUTHORITY_CONTAINER, props).getChildRef(); + if (authorityZones != null) { - nodeService.addChild(getOrCreateZone(authorityZone), childRef, ContentModel.ASSOC_IN_ZONE, QName - .createQName("cm", name, namespacePrefixResolver)); + for (String authorityZone : authorityZones) + { + nodeService.addChild(getOrCreateZone(authorityZone), childRef, ContentModel.ASSOC_IN_ZONE, QName.createQName("cm", name, namespacePrefixResolver)); + } } authorityLookupCache.clear(); } @@ -175,14 +174,13 @@ public class AuthorityDAOImpl implements AuthorityDAO return Collections. emptySet(); } Set authorities = new HashSet(); - for (NodeRef nodeRef : nodeService.getNodesWithoutParentAssocsOfType(this.storeRef, - ContentModel.TYPE_AUTHORITY_CONTAINER, ContentModel.ASSOC_MEMBER)) + for (NodeRef nodeRef : nodeService.getNodesWithoutParentAssocsOfType(this.storeRef, ContentModel.TYPE_AUTHORITY_CONTAINER, ContentModel.ASSOC_MEMBER)) { addAuthorityNameIfMatches(authorities, nodeRef, type, null); } return authorities; } - + public Set getAllAuthorities(AuthorityType type) { return findAuthorities(type, null); @@ -193,8 +191,7 @@ public class AuthorityDAOImpl implements AuthorityDAO Pattern pattern = null; if (namePattern != null) { - String regExpString = SearchLanguageConversion.convert(SearchLanguageConversion.DEF_LUCENE, - SearchLanguageConversion.DEF_REGEX, namePattern); + String regExpString = SearchLanguageConversion.convert(SearchLanguageConversion.DEF_LUCENE, SearchLanguageConversion.DEF_REGEX, namePattern); pattern = Pattern.compile(regExpString, Pattern.CASE_INSENSITIVE); } HashSet authorities = new HashSet(); @@ -204,11 +201,11 @@ public class AuthorityDAOImpl implements AuthorityDAO { for (NodeRef nodeRef : personService.getAllPeople()) { - addAuthorityNameIfMatches(authorities, DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(nodeRef, - ContentModel.PROP_USERNAME)), type, pattern); + addAuthorityNameIfMatches(authorities, DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME)), type, + pattern); } } - + // For other types, we just look directly under the authority container if (type == null || !type.equals(AuthorityType.USER)) { @@ -284,8 +281,8 @@ public class AuthorityDAOImpl implements AuthorityDAO private void addAuthorityNameIfMatches(Set authorities, NodeRef nodeRef, AuthorityType type, Pattern pattern) { - addAuthorityNameIfMatches(authorities, DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(nodeRef, - ContentModel.PROP_AUTHORITY_NAME)), type, pattern); + addAuthorityNameIfMatches(authorities, DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(nodeRef, ContentModel.PROP_AUTHORITY_NAME)), type, + pattern); } private void addAuthorityNameIfMatches(Set authorities, String authorityName, AuthorityType type, Pattern pattern) @@ -307,10 +304,9 @@ public class AuthorityDAOImpl implements AuthorityDAO } } - private void findAuthorities(AuthorityType type, String name, Set authorities, boolean parents, - boolean recursive) + private void findAuthorities(AuthorityType type, String name, Set authorities, boolean parents, boolean recursive) { - AuthorityType localType = AuthorityType.getAuthorityType(name); + AuthorityType localType = AuthorityType.getAuthorityType(name); if (localType.equals(AuthorityType.GUEST)) { // Nothing to do @@ -332,26 +328,23 @@ public class AuthorityDAOImpl implements AuthorityDAO } } - private void findAuthorities(AuthorityType type, Pattern pattern, NodeRef nodeRef, Set authorities, - boolean parents, boolean recursive, boolean includeNode) + private void findAuthorities(AuthorityType type, Pattern pattern, NodeRef nodeRef, Set authorities, boolean parents, boolean recursive, boolean includeNode) { QName currentType = nodeService.getType(nodeRef); boolean isAuthority = dictionaryService.isSubClass(currentType, ContentModel.TYPE_AUTHORITY); if (includeNode && isAuthority) { - String authorityName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService - .getProperty(nodeRef, dictionaryService.isSubClass(currentType, - ContentModel.TYPE_AUTHORITY_CONTAINER) ? ContentModel.PROP_AUTHORITY_NAME - : ContentModel.PROP_USERNAME)); + String authorityName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(nodeRef, dictionaryService.isSubClass(currentType, + ContentModel.TYPE_AUTHORITY_CONTAINER) ? ContentModel.PROP_AUTHORITY_NAME : ContentModel.PROP_USERNAME)); addAuthorityNameIfMatches(authorities, authorityName, type, pattern); } // Loop over children if we want immediate children or are in recursive mode if (!includeNode || (recursive && isAuthority)) { - List cars = parents ? nodeService.getParentAssocs(nodeRef, ContentModel.ASSOC_MEMBER, - RegexQNamePattern.MATCH_ALL) : nodeService.getChildAssocs(nodeRef); + List cars = parents ? nodeService.getParentAssocs(nodeRef, ContentModel.ASSOC_MEMBER, RegexQNamePattern.MATCH_ALL) : nodeService + .getChildAssocs(nodeRef); for (ChildAssociationRef car : cars) { @@ -361,7 +354,6 @@ public class AuthorityDAOImpl implements AuthorityDAO } } - private NodeRef getAuthorityOrNull(String name) { if (AuthorityType.getAuthorityType(name).equals(AuthorityType.USER)) @@ -372,10 +364,26 @@ public class AuthorityDAOImpl implements AuthorityDAO } return personService.getPerson(name); } + else if (AuthorityType.getAuthorityType(name).equals(AuthorityType.GUEST)) + { + if (!personService.personExists(name)) + { + return null; + } + return personService.getPerson(name); + } + else if (AuthorityType.getAuthorityType(name).equals(AuthorityType.ADMIN)) + { + if (!personService.personExists(name)) + { + return null; + } + return personService.getPerson(name); + } else { - List results = nodeService.getChildAssocs(getAuthorityContainer(), - ContentModel.ASSOC_CHILDREN, QName.createQName("cm", name, namespacePrefixResolver)); + List results = nodeService.getChildAssocs(getAuthorityContainer(), ContentModel.ASSOC_CHILDREN, QName.createQName("cm", name, + namespacePrefixResolver)); return results.isEmpty() ? null : results.get(0).getChildRef(); } } @@ -399,8 +407,7 @@ public class AuthorityDAOImpl implements AuthorityDAO private NodeRef getSystemContainer(QName assocQName) { NodeRef rootNodeRef = nodeService.getRootNode(this.storeRef); - List results = nodeService.getChildAssocs(rootNodeRef, RegexQNamePattern.MATCH_ALL, - qnameAssocSystem); + List results = nodeService.getChildAssocs(rootNodeRef, RegexQNamePattern.MATCH_ALL, qnameAssocSystem); NodeRef sysNodeRef = null; if (results.size() == 0) { @@ -476,14 +483,12 @@ public class AuthorityDAOImpl implements AuthorityDAO { NodeRef zoneContainerRef = getZoneContainer(); QName zoneQName = QName.createQName("cm", zoneName, namespacePrefixResolver); - List results = nodeService.getChildAssocs(zoneContainerRef, ContentModel.ASSOC_CHILDREN, - zoneQName); + List results = nodeService.getChildAssocs(zoneContainerRef, ContentModel.ASSOC_CHILDREN, zoneQName); if (results.isEmpty()) { HashMap props = new HashMap(); props.put(ContentModel.PROP_NAME, zoneName); - return nodeService.createNode(zoneContainerRef, ContentModel.ASSOC_CHILDREN, zoneQName, - ContentModel.TYPE_ZONE, props).getChildRef(); + return nodeService.createNode(zoneContainerRef, ContentModel.ASSOC_CHILDREN, zoneQName, ContentModel.TYPE_ZONE, props).getChildRef(); } else { @@ -491,29 +496,37 @@ public class AuthorityDAOImpl implements AuthorityDAO } } - public String getAuthorityZone(String name) + public Set getAuthorityZones(String name) { + HashSet zones = new HashSet(); NodeRef childRef = getAuthorityOrNull(name); if (childRef == null) { return null; } - List results = nodeService.getParentAssocs(childRef, ContentModel.ASSOC_IN_ZONE, - RegexQNamePattern.MATCH_ALL); + List results = nodeService.getParentAssocs(childRef, ContentModel.ASSOC_IN_ZONE, RegexQNamePattern.MATCH_ALL); if (results.isEmpty()) { - - return AuthorityService.DEFAULT_ZONE; + return zones; } - NodeRef zoneRef = results.get(0).getParentRef(); - Serializable value = nodeService.getProperty(zoneRef, ContentModel.PROP_NAME); - if (value == null) + + for (ChildAssociationRef current : results) { - return null; + NodeRef zoneRef = current.getParentRef(); + Serializable value = nodeService.getProperty(zoneRef, ContentModel.PROP_NAME); + if (value == null) + { + continue; + } + else + { + String zone = DefaultTypeConverter.INSTANCE.convert(String.class, value); + zones.add(zone); + } } - return DefaultTypeConverter.INSTANCE.convert(String.class, value); + return zones; } - + public Set getAllAuthoritiesInZone(String zoneName, AuthorityType type) { HashSet authorities = new HashSet(); @@ -525,6 +538,51 @@ public class AuthorityDAOImpl implements AuthorityDAO return authorities; } + public void addAuthorityToZones(String authorityName, Set zones) + { + if ((zones != null) && (zones.size() > 0)) + { + NodeRef authRef = getAuthorityOrNull(authorityName); + if (authRef != null) + { + + for (String zone : zones) + { + // Add the person to an authentication zone (corresponding to an external user registry) + // Let's preserve case on this child association + nodeService.addChild(getOrCreateZone(zone), authRef, ContentModel.ASSOC_IN_ZONE, QName.createQName("cm", authorityName, namespacePrefixResolver)); + } + } + } + } + + public void removeAuthorityFromZones(String authorityName, Set zones) + { + if ((zones != null) && (zones.size() > 0)) + { + NodeRef authRef = getAuthorityOrNull(authorityName); + List results = nodeService.getParentAssocs(authRef, ContentModel.ASSOC_IN_ZONE, RegexQNamePattern.MATCH_ALL); + for (ChildAssociationRef current : results) + { + NodeRef zoneRef = current.getParentRef(); + Serializable value = nodeService.getProperty(zoneRef, ContentModel.PROP_NAME); + if (value == null) + { + continue; + } + else + { + String testZone = DefaultTypeConverter.INSTANCE.convert(String.class, value); + if (zones.contains(testZone)) + { + nodeService.removeChildAssociation(current); + } + } + } + } + + } + private static class CacheKey implements Serializable { /** @@ -537,7 +595,7 @@ public class AuthorityDAOImpl implements AuthorityDAO String name; boolean parents; - + boolean recursive; CacheKey(AuthorityType type, String name, boolean parents, boolean recursive) @@ -591,7 +649,13 @@ public class AuthorityDAOImpl implements AuthorityDAO return true; } - - + } + + public Set getAllRootAuthoritiesInZone(String zoneName, AuthorityType type) + { + Set roots = getAllRootAuthorities(type); + Set inZone = getAllAuthoritiesInZone(zoneName, type); + roots.retainAll(inZone); + return roots; } } diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java b/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java index de66c5845f..c9e6007144 100644 --- a/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java +++ b/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java @@ -53,6 +53,8 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean { private static Log logger = LogFactory.getLog(AuthorityServiceImpl.class); + private static Set DEFAULT_ZONES = new HashSet(); + private PersonService personService; private NodeService nodeService; @@ -73,6 +75,12 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean private Set adminGroups = Collections.emptySet(); + static + { + DEFAULT_ZONES.add(AuthorityService.ZONE_APP_DEFAULT); + DEFAULT_ZONES.add(AuthorityService.ZONE_AUTH_ALFRESCO); + } + public AuthorityServiceImpl() { super(); @@ -290,7 +298,7 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean public String createAuthority(AuthorityType type, String shortName) { - return createAuthority(type, shortName, shortName, null); + return createAuthority(type, shortName, shortName, getDefaultZones()); } public void deleteAuthority(String name) @@ -373,11 +381,11 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean } public String createAuthority(AuthorityType type, String shortName, String authorityDisplayName, - String authorityZone) + Set authorityZones) { checkTypeIsMutable(type); String name = getName(type, shortName); - authorityDAO.createAuthority(name, authorityDisplayName, authorityZone); + authorityDAO.createAuthority(name, authorityDisplayName, authorityZones); return name; } @@ -398,9 +406,9 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean authorityDAO.setAuthorityDisplayName(authorityName, authorityDisplayName); } - public String getAuthorityZone(String name) + public Set getAuthorityZones(String name) { - return authorityDAO.getAuthorityZone(name); + return authorityDAO.getAuthorityZones(name); } public NodeRef getOrCreateZone(String zoneName) @@ -412,4 +420,25 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean { return authorityDAO.getAllAuthoritiesInZone(zoneName, type); } + + public void addAuthorityToZones(String authorityName, Set zones) + { + authorityDAO.addAuthorityToZones(authorityName, zones); + + } + + public void removeAuthorityFromZones(String authorityName, Set zones) + { + authorityDAO.removeAuthorityFromZones(authorityName, zones); + } + + public Set getDefaultZones() + { + return DEFAULT_ZONES; + } + + public Set getAllRootAuthoritiesInZone(String zoneName, AuthorityType type) + { + return authorityDAO.getAllRootAuthoritiesInZone(zoneName, type); + } } diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java b/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java index cd8f5f53f3..538dc23fac 100644 --- a/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java +++ b/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java @@ -26,6 +26,7 @@ package org.alfresco.repo.security.authority; import java.io.Serializable; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -159,6 +160,93 @@ public class AuthorityServiceTest extends TestCase super.tearDown(); } + + public void testZones() + { + assertNull(pubAuthorityService.getAuthorityZones("GROUP_DEFAULT")); + assertNull(pubAuthorityService.getAuthorityZones("GROUP_NULL")); + assertNull(pubAuthorityService.getAuthorityZones("GROUP_EMPTY")); + assertNull(pubAuthorityService.getAuthorityZones("GROUP_1")); + assertNull(pubAuthorityService.getAuthorityZones("GROUP_2")); + assertNull(pubAuthorityService.getAuthorityZones("GROUP_3")); + + pubAuthorityService.createAuthority(AuthorityType.GROUP, "DEFAULT"); + Set zones = pubAuthorityService.getAuthorityZones("GROUP_DEFAULT"); + assertEquals(2, zones.size()); + pubAuthorityService.removeAuthorityFromZones("GROUP_DEFAULT", zones); + assertEquals(0, pubAuthorityService.getAuthorityZones("GROUP_DEFAULT").size()); + pubAuthorityService.addAuthorityToZones("GROUP_DEFAULT", zones); + assertEquals(2, pubAuthorityService.getAuthorityZones("GROUP_DEFAULT").size()); + + HashSet newZones = null; + pubAuthorityService.createAuthority(AuthorityType.GROUP, "NULL", "NULL", newZones); + assertEquals(0, pubAuthorityService.getAuthorityZones("GROUP_NULL").size()); + + newZones = new HashSet(); + pubAuthorityService.createAuthority(AuthorityType.GROUP, "EMPTY", "EMPTY", newZones); + assertEquals(0, pubAuthorityService.getAuthorityZones("GROUP_EMPTY").size()); + + newZones.add("One"); + pubAuthorityService.createAuthority(AuthorityType.GROUP, "1", "1", newZones); + assertEquals(1, pubAuthorityService.getAuthorityZones("GROUP_1").size()); + + newZones.add("Two"); + pubAuthorityService.createAuthority(AuthorityType.GROUP, "2", "2", newZones); + assertEquals(2, pubAuthorityService.getAuthorityZones("GROUP_2").size()); + + newZones.add("Three"); + pubAuthorityService.createAuthority(AuthorityType.GROUP, "3", "3", newZones); + assertEquals(3, pubAuthorityService.getAuthorityZones("GROUP_3").size()); + + HashSet toRemove = null; + pubAuthorityService.removeAuthorityFromZones("GROUP_3", toRemove); + assertEquals(3, pubAuthorityService.getAuthorityZones("GROUP_3").size()); + + toRemove = new HashSet(); + pubAuthorityService.removeAuthorityFromZones("GROUP_3", toRemove); + assertEquals(3, pubAuthorityService.getAuthorityZones("GROUP_3").size()); + + toRemove.add("Three"); + pubAuthorityService.removeAuthorityFromZones("GROUP_3", toRemove); + assertEquals(2, pubAuthorityService.getAuthorityZones("GROUP_3").size()); + + toRemove.add("Two"); + pubAuthorityService.removeAuthorityFromZones("GROUP_3", toRemove); + assertEquals(1, pubAuthorityService.getAuthorityZones("GROUP_3").size()); + + toRemove.add("One"); + pubAuthorityService.removeAuthorityFromZones("GROUP_3", toRemove); + assertEquals(0, pubAuthorityService.getAuthorityZones("GROUP_3").size()); + + pubAuthorityService.addAuthorityToZones("GROUP_3", newZones); + assertEquals(3, pubAuthorityService.getAuthorityZones("GROUP_3").size()); + assertEquals(3, pubAuthorityService.getAllAuthoritiesInZone("One", null).size()); + assertEquals(2, pubAuthorityService.getAllAuthoritiesInZone("Two", null).size()); + assertEquals(1, pubAuthorityService.getAllAuthoritiesInZone("Three", null).size()); + assertEquals(3, pubAuthorityService.getAllAuthoritiesInZone("One", AuthorityType.GROUP).size()); + assertEquals(2, pubAuthorityService.getAllAuthoritiesInZone("Two", AuthorityType.GROUP).size()); + assertEquals(1, pubAuthorityService.getAllAuthoritiesInZone("Three", AuthorityType.GROUP).size()); + + assertEquals(3, pubAuthorityService.getAllRootAuthoritiesInZone("One", null).size()); + assertEquals(2, pubAuthorityService.getAllRootAuthoritiesInZone("Two", null).size()); + assertEquals(1, pubAuthorityService.getAllRootAuthoritiesInZone("Three", null).size()); + assertEquals(3, pubAuthorityService.getAllRootAuthoritiesInZone("One", AuthorityType.GROUP).size()); + assertEquals(2, pubAuthorityService.getAllRootAuthoritiesInZone("Two", AuthorityType.GROUP).size()); + assertEquals(1, pubAuthorityService.getAllRootAuthoritiesInZone("Three", AuthorityType.GROUP).size()); + + // I am not convinced of the definition of root within zone ... + + pubAuthorityService.addAuthority("GROUP_1", "GROUP_2"); + pubAuthorityService.addAuthority("GROUP_1", "GROUP_3"); + + assertEquals(1, pubAuthorityService.getAllRootAuthoritiesInZone("One", null).size()); + assertEquals(0, pubAuthorityService.getAllRootAuthoritiesInZone("Two", null).size()); + assertEquals(0, pubAuthorityService.getAllRootAuthoritiesInZone("Three", null).size()); + assertEquals(1, pubAuthorityService.getAllRootAuthoritiesInZone("One", AuthorityType.GROUP).size()); + assertEquals(0, pubAuthorityService.getAllRootAuthoritiesInZone("Two", AuthorityType.GROUP).size()); + assertEquals(0, pubAuthorityService.getAllRootAuthoritiesInZone("Three", AuthorityType.GROUP).size()); + } + public void testGroupWildcards() { long before, after; @@ -937,7 +1025,7 @@ public class AuthorityServiceTest extends TestCase pubAuthorityService.setAuthorityDisplayName(authOne, "Selfish Crocodile"); assertEquals(pubAuthorityService.getAuthorityDisplayName(authOne), "Selfish Crocodile"); - String authTwo = pubAuthorityService.createAuthority(AuthorityType.GROUP, "Two", "Lamp posts", null); + String authTwo = pubAuthorityService.createAuthority(AuthorityType.GROUP, "Two", "Lamp posts", authorityService.getDefaultZones()); assertEquals(pubAuthorityService.getAuthorityDisplayName(authTwo), "Lamp posts"); pubAuthorityService.setAuthorityDisplayName(authTwo, "Happy Hippos"); assertEquals(pubAuthorityService.getAuthorityDisplayName(authTwo), "Happy Hippos"); diff --git a/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceImpl.java b/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceImpl.java index bbe63d501a..a1d5f122a7 100644 --- a/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceImpl.java +++ b/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceImpl.java @@ -190,11 +190,6 @@ public class SimpleAuthorityServiceImpl implements AuthorityService return ""; } - public String createAuthority(AuthorityType type, String shortName, String authorityDisplayName, - String authorityZone) - { - return ""; - } public void deleteAuthority(String name) { @@ -298,16 +293,41 @@ public class SimpleAuthorityServiceImpl implements AuthorityService public Set getAllAuthoritiesInZone(String zoneName, AuthorityType type) { - return Collections.emptySet(); - } - - public String getAuthorityZone(String name) - { - return AuthorityService.DEFAULT_ZONE; + return Collections.emptySet(); } public NodeRef getOrCreateZone(String zoneName) { return null; } + + public void addAuthorityToZones(String authorityName, Set zones) + { + + } + + public String createAuthority(AuthorityType type, String shortName, String authorityDisplayName, Set authorityZones) + { + return ""; + } + + public Set getAllRootAuthoritiesInZone(String zoneName, AuthorityType type) + { + return Collections.emptySet(); + } + + public Set getAuthorityZones(String name) + { + return Collections.emptySet(); + } + + public Set getDefaultZones() + { + return Collections.emptySet(); + } + + public void removeAuthorityFromZones(String authorityName, Set zones) + { + + } } diff --git a/source/java/org/alfresco/repo/security/authority/script/ScriptAuthorityService.java b/source/java/org/alfresco/repo/security/authority/script/ScriptAuthorityService.java index b49be3cb65..96de1bde77 100644 --- a/source/java/org/alfresco/repo/security/authority/script/ScriptAuthorityService.java +++ b/source/java/org/alfresco/repo/security/authority/script/ScriptAuthorityService.java @@ -76,7 +76,7 @@ public class ScriptAuthorityService extends BaseScopableProcessorExtension public ScriptGroup[] getAllRootGroups(boolean includeInternal) { Set groups = new LinkedHashSet(0); - Set authorities = authorityService.getAllRootAuthorities(AuthorityType.GROUP); + Set authorities = authorityService.getAllRootAuthoritiesInZone(AuthorityService.ZONE_APP_DEFAULT, AuthorityType.GROUP); for(String authority : authorities) { ScriptGroup group = new ScriptGroup(authority, authorityService); @@ -128,7 +128,7 @@ public class ScriptAuthorityService extends BaseScopableProcessorExtension */ public ScriptGroup createRootGroup(String shortName, String displayName) { - authorityService.createAuthority(AuthorityType.GROUP, shortName, displayName, null); + authorityService.createAuthority(AuthorityType.GROUP, shortName, displayName, authorityService.getDefaultZones()); return getGroup(shortName); } diff --git a/source/java/org/alfresco/repo/security/authority/script/ScriptGroup.java b/source/java/org/alfresco/repo/security/authority/script/ScriptGroup.java index 090bf477d7..01528ae64b 100644 --- a/source/java/org/alfresco/repo/security/authority/script/ScriptGroup.java +++ b/source/java/org/alfresco/repo/security/authority/script/ScriptGroup.java @@ -297,7 +297,7 @@ public class ScriptGroup implements Authority, Serializable */ public ScriptGroup createGroup(String shortName, String displayName) { - String authorityName = authorityService.createAuthority(AuthorityType.GROUP, shortName, displayName, null); + String authorityName = authorityService.createAuthority(AuthorityType.GROUP, shortName, displayName, authorityService.getDefaultZones()); authorityService.addAuthority(fullName, authorityName); ScriptGroup childGroup = new ScriptGroup(authorityName, authorityService); clearCaches(); diff --git a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java index cc65139f7e..023c8c813d 100644 --- a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java +++ b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java @@ -173,12 +173,11 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per PropertyCheck.mandatory(this, "personCache", personCache); PropertyCheck.mandatory(this, "personDao", personDao); - - this.policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"), ContentModel.TYPE_PERSON, new JavaBehaviour(this, "onCreateNode")); + this.policyComponent + .bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"), ContentModel.TYPE_PERSON, new JavaBehaviour(this, "onCreateNode")); this.policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"), ContentModel.TYPE_PERSON, new JavaBehaviour(this, "beforeDeleteNode")); - - + } public UserNameMatcher getUserNameMatcher() @@ -257,7 +256,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per if (tenantService.isEnabled() && (AuthenticationUtil.SYSTEM_USER_NAME.equals(AuthenticationUtil.getRunAsUser())) && tenantService.isTenantUser(userName)) { final String tenantDomain = tenantService.getUserDomain(userName); - + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() { public NodeRef doWork() throws Exception @@ -271,7 +270,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per return getPersonImpl(userName); } } - + private NodeRef getPersonImpl(String userName) { NodeRef personNode = getPersonOrNull(userName); @@ -583,10 +582,10 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per public NodeRef createPerson(Map properties) { - return createPerson(properties, null); + return createPerson(properties, authorityService.getDefaultZones()); } - public NodeRef createPerson(Map properties, String zone) + public NodeRef createPerson(Map properties, Set zones) { String userName = DefaultTypeConverter.INSTANCE.convert(String.class, properties.get(ContentModel.PROP_USERNAME)); AuthorityType authorityType = AuthorityType.getAuthorityType(userName); @@ -594,24 +593,24 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per { throw new AlfrescoRuntimeException("Attempt to create person for an authority which is not a user"); } - + tenantService.checkDomainUser(userName); properties.put(ContentModel.PROP_USERNAME, userName); properties.put(ContentModel.PROP_SIZE_CURRENT, 0L); - NodeRef personRef = nodeService.createNode( - getPeopleContainer(), - ContentModel.ASSOC_CHILDREN, - QName.createQName("cm", userName.toLowerCase(), namespacePrefixResolver), // Lowercase: ETHREEOH-1431 - ContentModel.TYPE_PERSON, - properties).getChildRef(); - - if (zone != null) + NodeRef personRef = nodeService.createNode(getPeopleContainer(), ContentModel.ASSOC_CHILDREN, QName.createQName("cm", userName.toLowerCase(), namespacePrefixResolver), // Lowercase: + // ETHREEOH-1431 + ContentModel.TYPE_PERSON, properties).getChildRef(); + + if (zones != null) { - // Add the person to an authentication zone (corresponding to an external user registry) - // Let's preserve case on this child association - nodeService.addChild(authorityService.getOrCreateZone(zone), personRef, ContentModel.ASSOC_IN_ZONE, QName.createQName("cm", userName, namespacePrefixResolver)); + for (String zone : zones) + { + // Add the person to an authentication zone (corresponding to an external user registry) + // Let's preserve case on this child association + nodeService.addChild(authorityService.getOrCreateZone(zone), personRef, ContentModel.ASSOC_IN_ZONE, QName.createQName("cm", userName, namespacePrefixResolver)); + } } return personRef; } diff --git a/source/java/org/alfresco/repo/security/person/PersonTest.java b/source/java/org/alfresco/repo/security/person/PersonTest.java index aac48a0c7f..1163bb09fb 100644 --- a/source/java/org/alfresco/repo/security/person/PersonTest.java +++ b/source/java/org/alfresco/repo/security/person/PersonTest.java @@ -26,7 +26,9 @@ package org.alfresco.repo.security.person; import java.io.Serializable; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -94,6 +96,67 @@ public class PersonTest extends BaseSpringTest super.onTearDownInTransaction(); } + public void testZones() + { + assertNull(authorityService.getAuthorityZones("derek")); + assertNull(authorityService.getAuthorityZones("null")); + + personService.createPerson(createDefaultProperties("derek", "Derek", "Hulley", "dh@dh", "alfresco", rootNodeRef)); + Set zones = authorityService.getAuthorityZones("derek"); + assertEquals(2, zones.size()); + authorityService.removeAuthorityFromZones("derek", zones); + assertEquals(0, authorityService.getAuthorityZones("derek").size()); + authorityService.addAuthorityToZones("derek", zones); + assertEquals(2, authorityService.getAuthorityZones("derek").size()); + + HashSet newZones = null; + personService.createPerson(createDefaultProperties("null", "null", "null", "null", "null", rootNodeRef), newZones); + assertEquals(0, authorityService.getAuthorityZones("null").size()); + + newZones = new HashSet(); + personService.createPerson(createDefaultProperties("empty", "empty", "empty", "empty", "empty", rootNodeRef), newZones); + assertEquals(0, authorityService.getAuthorityZones("empty").size()); + + newZones.add("One"); + personService.createPerson(createDefaultProperties("1", "1", "1", "1", "1", rootNodeRef), newZones); + assertEquals(1, authorityService.getAuthorityZones("1").size()); + + newZones.add("Two"); + personService.createPerson(createDefaultProperties("2", "2", "2", "2", "2", rootNodeRef), newZones); + assertEquals(2, authorityService.getAuthorityZones("2").size()); + + newZones.add("Three"); + personService.createPerson(createDefaultProperties("3", "3", "3", "3", "3", rootNodeRef), newZones); + assertEquals(3, authorityService.getAuthorityZones("3").size()); + + HashSet toRemove = null; + authorityService.removeAuthorityFromZones("3", toRemove); + assertEquals(3, authorityService.getAuthorityZones("3").size()); + + toRemove = new HashSet(); + authorityService.removeAuthorityFromZones("3", toRemove); + assertEquals(3, authorityService.getAuthorityZones("3").size()); + + toRemove.add("Three"); + authorityService.removeAuthorityFromZones("3", toRemove); + assertEquals(2, authorityService.getAuthorityZones("3").size()); + + toRemove.add("Two"); + authorityService.removeAuthorityFromZones("3", toRemove); + assertEquals(1, authorityService.getAuthorityZones("3").size()); + + toRemove.add("One"); + authorityService.removeAuthorityFromZones("3", toRemove); + assertEquals(0, authorityService.getAuthorityZones("3").size()); + + authorityService.addAuthorityToZones("3", newZones); + assertEquals(3, authorityService.getAuthorityZones("3").size()); + assertEquals(3, authorityService.getAllAuthoritiesInZone("One", null).size()); + assertEquals(2, authorityService.getAllAuthoritiesInZone("Two", null).size()); + assertEquals(1, authorityService.getAllAuthoritiesInZone("Three", null).size()); + + } + public void xtestPerformance() { personService.setCreateMissingPeople(false); @@ -481,6 +544,8 @@ public class PersonTest extends BaseSpringTest } // It should work in a write transaction, though transactionService.getRetryingTransactionHelper().doInTransaction(getMissingPersonWork, false, true); + + transactionService.getRetryingTransactionHelper().doInTransaction(deletePersonWork, false, true); } public void testSplitPersonCleanup() throws Exception diff --git a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java index 52e28d4023..d3b98b2cc4 100644 --- a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java +++ b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java @@ -26,6 +26,7 @@ package org.alfresco.repo.security.sync; import java.text.DateFormat; import java.util.Date; +import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -162,21 +163,25 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize public void synchronize(boolean force) { Set visitedZoneIds = new TreeSet(); - for (String zoneId : this.applicationContextManager.getInstanceIds()) + for (String id : this.applicationContextManager.getInstanceIds()) { - ApplicationContext context = this.applicationContextManager.getApplicationContext(zoneId); + StringBuilder builder = new StringBuilder(32); + builder.append(AuthorityService.ZONE_AUTH_EXT_PREFIX); + builder.append(id); + String zoneId = builder.toString(); + ApplicationContext context = this.applicationContextManager.getApplicationContext(id); try { UserRegistry plugin = (UserRegistry) context.getBean(this.sourceBeanName); if (!(plugin instanceof ActivateableBean) || ((ActivateableBean) plugin).isActive()) { ChainingUserRegistrySynchronizer.logger.info("Synchronizing users and groups with user registry '" - + zoneId + "'"); + + id + "'"); if (force) { ChainingUserRegistrySynchronizer.logger .warn("Forced synchronization with user registry '" - + zoneId + + id + "'; some users and groups previously created by synchronization with this user registry may be removed."); } int personsProcessed = syncPersonsWithPlugin(zoneId, plugin, force, visitedZoneIds); @@ -243,10 +248,11 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize else { // The person does not exist in this zone, but may exist in another zone - String zone = this.authorityService.getAuthorityZone(personName); - if (zone != null) + Set zones = this.authorityService.getAuthorityZones(personName); + if (zones != null) { - if (visitedZoneIds.contains(zone)) + zones.retainAll(visitedZoneIds); + if (zones.size() > 0) { // A person that exists in a different zone with higher precedence continue; @@ -263,7 +269,7 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize // The person did not exist at all ChainingUserRegistrySynchronizer.logger.info("Creating user '" + personName + "'"); } - this.personService.createPerson(personProperties, zoneId); + this.personService.createPerson(personProperties, getZones(zoneId)); } // Increment the count of processed people processedCount++; @@ -294,7 +300,7 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize return processedCount; } - + /** * Synchronizes local groups (authorities) with a {@link UserRegistry} for a particular zone. * @@ -360,10 +366,11 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize else { String groupShortName = this.authorityService.getShortName(groupName); - String groupZone = this.authorityService.getAuthorityZone(groupName); - if (groupZone != null) + Set groupZones = this.authorityService.getAuthorityZones(groupName); + if (groupZones != null) { - if (visitedZoneIds.contains(groupZone)) + groupZones.retainAll(visitedZoneIds); + if (groupZones.size() > 0) { // A group that exists in a different zone with higher precedence continue; @@ -382,7 +389,7 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize // create the group this.authorityService.createAuthority(AuthorityType.getAuthorityType(groupName), groupShortName, - (String) groupProperties.get(ContentModel.PROP_AUTHORITY_DISPLAY_NAME), zoneId); + (String) groupProperties.get(ContentModel.PROP_AUTHORITY_DISPLAY_NAME), getZones(zoneId)); Set children = group.getChildAssociations(); if (!children.isEmpty()) { @@ -476,4 +483,12 @@ public class ChainingUserRegistrySynchronizer implements UserRegistrySynchronize } this.attributeService.setAttribute(path, zoneId, new LongAttributeValue(lastModifiedMillis)); } + + private Set getZones(String zoneId) + { + HashSet zones = new HashSet(2, 1.0f); + zones.add(AuthorityService.ZONE_APP_DEFAULT); + zones.add(zoneId); + return zones; + } } diff --git a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizerTest.java b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizerTest.java index 54f1c3be5f..074f823d3c 100644 --- a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizerTest.java +++ b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizerTest.java @@ -347,7 +347,7 @@ public class ChainingUserRegistrySynchronizerTest extends BaseSpringTest assertTrue(this.authorityService.authorityExists(longName)); // Check in correct zone - assertEquals(zone, this.authorityService.getAuthorityZone(longName)); + assertTrue(this.authorityService.getAuthorityZones(longName).contains(AuthorityService.ZONE_AUTH_EXT_PREFIX+zone)); if (AuthorityType.getAuthorityType(longName).equals(AuthorityType.GROUP)) { // Check groups have expected members @@ -378,7 +378,7 @@ public class ChainingUserRegistrySynchronizerTest extends BaseSpringTest assertFalse(this.authorityService.authorityExists(longName)); // Check there is no zone - assertNull(this.authorityService.getAuthorityZone(longName)); + assertNull(this.authorityService.getAuthorityZones(longName)); if (!AuthorityType.getAuthorityType(longName).equals(AuthorityType.GROUP)) { // Check person does not exist diff --git a/source/java/org/alfresco/repo/site/SiteServiceImpl.java b/source/java/org/alfresco/repo/site/SiteServiceImpl.java index 39e5ffff4a..af3479d1a2 100644 --- a/source/java/org/alfresco/repo/site/SiteServiceImpl.java +++ b/source/java/org/alfresco/repo/site/SiteServiceImpl.java @@ -26,6 +26,7 @@ package org.alfresco.repo.site; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; @@ -103,6 +104,8 @@ public class SiteServiceImpl implements SiteService, SiteModel private static final int GROUP_PREFIX_LENGTH = PermissionService.GROUP_PREFIX.length(); private static final int GROUP_SITE_PREFIX_LENGTH = GROUP_SITE_PREFIX.length(); + private static final Set ZONES; + /** Site home ref cache (Tennant aware) */ private Map siteHomeRefs = new ConcurrentHashMap(4); @@ -139,6 +142,13 @@ public class SiteServiceImpl implements SiteService, SiteModel private RetryingTransactionHelper retryingTransactionHelper; private Comparator roleComparator ; + static + { + HashSet zones = new HashSet(2, 1.0f); + zones.add(AuthorityService.ZONE_APP_SHARE); + zones.add(AuthorityService.ZONE_AUTH_ALFRESCO); + ZONES = Collections.unmodifiableSet(zones); + } /** * Set the path to the location of the sites root folder. For example: @@ -361,13 +371,13 @@ public class SiteServiceImpl implements SiteService, SiteModel { // Create the site's groups String siteGroup = authorityService - .createAuthority(AuthorityType.GROUP, getSiteGroup(shortName, false)); + .createAuthority(AuthorityType.GROUP, getSiteGroup(shortName, false), getSiteGroup(shortName, false), ZONES); Set permissions = permissionService.getSettablePermissions(SiteModel.TYPE_SITE); for (String permission : permissions) { // Create a group for the permission String permissionGroup = authorityService.createAuthority(AuthorityType.GROUP, getSiteRoleGroup( - shortName, permission, false)); + shortName, permission, false), getSiteRoleGroup(shortName, permission, false), ZONES); authorityService.addAuthority(siteGroup, permissionGroup); // Assign the group the relevant permission on the site diff --git a/source/java/org/alfresco/service/cmr/security/AuthorityService.java b/source/java/org/alfresco/service/cmr/security/AuthorityService.java index e45993d450..acda9dd928 100644 --- a/source/java/org/alfresco/service/cmr/security/AuthorityService.java +++ b/source/java/org/alfresco/service/cmr/security/AuthorityService.java @@ -27,9 +27,9 @@ package org.alfresco.service.cmr.security; import java.util.Set; import org.alfresco.service.Auditable; +import org.alfresco.service.NotAuditable; import org.alfresco.service.PublicService; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.namespace.QName; /** * The service that encapsulates authorities granted to users. @@ -47,13 +47,32 @@ import org.alfresco.service.namespace.QName; */ @PublicService public interface AuthorityService -{ +{ + /** + * The default application zone. + */ + public static String ZONE_APP_DEFAULT = "APP.DEFAULT"; /** - * The default zone that owns all authorities for which a zone is not explicitly specified in the authorityZone - * property + * The WCM application zone. */ - public static final String DEFAULT_ZONE = ""; + public static String ZONE_APP_WCM = "APP.WCM"; + + /** + * The SHARE application zone. + */ + public static String ZONE_APP_SHARE = "APP.SHARE"; + + /** + * Default authentication + */ + public static String ZONE_AUTH_ALFRESCO = "AUTH.ALF"; + + /** + * Prefix for external auth ids + */ + public static String ZONE_AUTH_EXT_PREFIX = "AUTH.EXT."; + /** * Check of the current user has admin authority. @@ -160,8 +179,8 @@ public interface AuthorityService * @return the full name of the authority (this will be the prefix, if any associated with the type appended with * the short name) */ - @Auditable(parameters = {"type", "shortName", "authorityDisplayName", "authorityZone"}) - public String createAuthority(AuthorityType type, String shortName, String authorityDisplayName, String authorityZone); + @Auditable(parameters = {"type", "shortName", "authorityDisplayName", "authorityZones"}) + public String createAuthority(AuthorityType type, String shortName, String authorityDisplayName, Set authorityZones); /** * Set an authority to include another authority. For example, adding a @@ -312,7 +331,7 @@ public interface AuthorityService * authority exists but has no zone, or null if the authority does not exist. */ @Auditable(parameters = {"name"}) - public String getAuthorityZone(String name); + public Set getAuthorityZones(String name); /** * Gets the names of all authorities in a zone, optionally filtered by type. @@ -325,4 +344,39 @@ public interface AuthorityService */ @Auditable(parameters = {"zoneName", "type"}) public Set getAllAuthoritiesInZone(String zoneName, AuthorityType type); + + /** + * Gets the names of all authorities in a zone, optionally filtered by type. + * + * @param zoneName + * the zone name + * @param type + * the authority type to filter by or null for all authority types + * @return the names of all authorities in a zone, optionally filtered by type + */ + @Auditable(parameters = {"zoneName", "type"}) + public Set getAllRootAuthoritiesInZone(String zoneName, AuthorityType type); + + /** + * Add a zone to an authority. + * @param authorityName + * @param zone + */ + @Auditable(parameters = {"authorityName", "zones"}) + public void addAuthorityToZones(String authorityName, Set zones); + + /** + * Remove a zone from an authority + * @param authorityName + * @param zone + */ + @Auditable(parameters = {"authorityName", "zones"}) + public void removeAuthorityFromZones(String authorityName, Set zones); + + /** + * Get the name of the default zone. + * @return the default zone + */ + @NotAuditable + public Set getDefaultZones(); } diff --git a/source/java/org/alfresco/service/cmr/security/PersonService.java b/source/java/org/alfresco/service/cmr/security/PersonService.java index 0328ef5b1f..0979ad3e76 100644 --- a/source/java/org/alfresco/service/cmr/security/PersonService.java +++ b/source/java/org/alfresco/service/cmr/security/PersonService.java @@ -146,13 +146,12 @@ public interface PersonService * * @param properties * the properties - * @param zone - * an identifier for the external user registry owning the person information, or null if - * not applicable. + * @param zones + * a set if zones including the identifier for the external user registry owning the person information, or null or an empty set * @return the node ref */ - @Auditable(parameters = {"properties", "zone"}) - public NodeRef createPerson(Map properties, String zone); + @Auditable(parameters = {"properties", "zones"}) + public NodeRef createPerson(Map properties, Set zones); /** * Delete the person identified by the given user name. diff --git a/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java b/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java index c1c943ab91..9c1379467b 100644 --- a/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java +++ b/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java @@ -25,6 +25,7 @@ package org.alfresco.wcm.sandbox; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; @@ -64,6 +65,8 @@ import org.apache.commons.logging.LogFactory; */ public final class SandboxFactory extends WCMUtil { + private static final Set ZONES; + public static final String[] PERMISSIONS = new String[] { PermissionService.WCM_CONTENT_MANAGER, PermissionService.WCM_CONTENT_PUBLISHER, @@ -80,6 +83,14 @@ public final class SandboxFactory extends WCMUtil private VirtServerRegistry virtServerRegistry; private AuthorityService authorityService; + static + { + HashSet zones = new HashSet(2, 1.0f); + zones.add(AuthorityService.ZONE_APP_WCM); + zones.add(AuthorityService.ZONE_AUTH_ALFRESCO); + ZONES = Collections.unmodifiableSet(zones); + } + public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; @@ -365,7 +376,7 @@ public final class SandboxFactory extends WCMUtil String group = authorityService.getName(AuthorityType.GROUP, shortName); if (!authorityService.authorityExists(group)) { - authorityService.createAuthority(AuthorityType.GROUP, shortName); + authorityService.createAuthority(AuthorityType.GROUP, shortName, shortName, ZONES); } if (!isPermissionSet(dirRef, group, permission)) { @@ -399,7 +410,7 @@ public final class SandboxFactory extends WCMUtil String group = authorityService.getName(AuthorityType.GROUP, shortName); if (!authorityService.authorityExists(group)) { - authorityService.createAuthority(AuthorityType.GROUP, shortName); + authorityService.createAuthority(AuthorityType.GROUP, shortName, shortName, ZONES); } Set members = authorityService.getContainedAuthorities(AuthorityType.USER, group, true); if (!members.contains(user))