From 65f660c26cea8260049065917009df524dce201c Mon Sep 17 00:00:00 2001 From: Jan Vonka Date: Thu, 2 Aug 2007 10:56:30 +0000 Subject: [PATCH] - add TenantService hooks to org.alfresco.repo.security services - Authentication, Person, Permission, Authority - add user/tenant-based logging via log4j NDC (nested diagnostic context) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@6399 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../authentication-services-context.xml | 6 ++++ .../alfresco/authority-services-context.xml | 3 ++ .../public-services-security-context.xml | 3 ++ .../AbstractAuthenticationComponent.java | 5 ++++ .../AuthenticationServiceImpl.java | 4 +++ .../authentication/AuthenticationUtil.java | 27 +++++++++++++++++ .../RepositoryAuthenticationDao.java | 30 +++++++++++++++---- .../authority/AuthorityServiceImpl.java | 16 +++++++++- .../authority/SimpleAuthorityServiceImpl.java | 17 ++++++++++- .../impl/PermissionServiceImpl.java | 30 ++++++++++++++----- .../security/person/PersonServiceImpl.java | 22 +++++++++----- 11 files changed, 141 insertions(+), 22 deletions(-) diff --git a/config/alfresco/authentication-services-context.xml b/config/alfresco/authentication-services-context.xml index 7e3f528d25..ad984c2688 100644 --- a/config/alfresco/authentication-services-context.xml +++ b/config/alfresco/authentication-services-context.xml @@ -79,6 +79,9 @@ + + + @@ -179,6 +182,9 @@ + + + diff --git a/config/alfresco/authority-services-context.xml b/config/alfresco/authority-services-context.xml index f62d644e25..f4880d53ce 100644 --- a/config/alfresco/authority-services-context.xml +++ b/config/alfresco/authority-services-context.xml @@ -22,6 +22,9 @@ + + + diff --git a/config/alfresco/public-services-security-context.xml b/config/alfresco/public-services-security-context.xml index 8a1fbb0d6b..6ce5623fe2 100644 --- a/config/alfresco/public-services-security-context.xml +++ b/config/alfresco/public-services-security-context.xml @@ -39,6 +39,9 @@ + + + diff --git a/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java b/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java index 0667bd1d79..c4f0f2663a 100644 --- a/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java +++ b/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java @@ -107,6 +107,11 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC { throw new AuthenticationException(ae.getMessage(), ae); } + finally + { + // Support for logging tenantdomain / username (via log4j NDC) + AuthenticationUtil.logNDC(userName); + } } /** diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java index b9ca07a1fd..f6cf9034d9 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java @@ -109,6 +109,8 @@ public class AuthenticationServiceImpl implements AuthenticationService { try { + // clear context - to avoid MT concurrency issue (causing domain mismatch) - see also 'validate' below + clearCurrentSecurityContext(); authenticationComponent.authenticate(userName, password); } catch(AuthenticationException ae) @@ -142,6 +144,8 @@ public class AuthenticationServiceImpl implements AuthenticationService { try { + // clear context - to avoid MT concurrency issue (causing domain mismatch) - see also 'authenticate' above + clearCurrentSecurityContext(); authenticationComponent.setCurrentUser(ticketComponent.validateTicket(ticket)); } catch(AuthenticationException ae) diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java index 47fb1c0086..280a00f7e5 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java @@ -35,7 +35,9 @@ import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; import net.sf.acegisecurity.providers.dao.User; +import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.security.PermissionService; +import org.apache.log4j.NDC; public abstract class AuthenticationUtil { @@ -151,8 +153,33 @@ public abstract class AuthenticationUtil } authentication.setAuthenticated(true); sc.setAuthentication(authentication); + + // Support for logging tenant domain / username (via log4j NDC) + String userName = SYSTEM_USER_NAME; + if (authentication.getPrincipal() instanceof UserDetails) + { + userName = ((UserDetails) authentication.getPrincipal()).getUsername(); + } + + logNDC(userName); + return authentication; } + + public static void logNDC(String userName) + { + NDC.remove(); + + int idx = userName.indexOf(TenantService.SEPARATOR); + if ((idx != -1) && (idx < (userName.length()-1))) + { + NDC.push("Tenant:"+userName.substring(idx+1)+" User:"+userName.substring(0,idx)); + } + else + { + NDC.push("User:"+userName); + } + } /** * Get the current authentication context diff --git a/source/java/org/alfresco/repo/security/authentication/RepositoryAuthenticationDao.java b/source/java/org/alfresco/repo/security/authentication/RepositoryAuthenticationDao.java index e9f0deff97..d15726c165 100644 --- a/source/java/org/alfresco/repo/security/authentication/RepositoryAuthenticationDao.java +++ b/source/java/org/alfresco/repo/security/authentication/RepositoryAuthenticationDao.java @@ -39,7 +39,7 @@ import net.sf.acegisecurity.providers.encoding.PasswordEncoder; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; -import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; +import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; @@ -60,6 +60,7 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao private static final StoreRef STOREREF_USERS = new StoreRef("user", "alfrescoUserStore"); private NodeService nodeService; + private TenantService tenantService; private NamespacePrefixResolver namespacePrefixResolver; @@ -97,6 +98,11 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao this.nodeService = nodeService; } + public void setTenantService(TenantService tenantService) + { + this.tenantService = tenantService; + } + public void setPasswordEncoder(PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; @@ -146,7 +152,16 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao SearchParameters sp = new SearchParameters(); sp.setLanguage(SearchService.LANGUAGE_LUCENE); sp.setQuery("@usr\\:username:\"" + searchUserName + "\""); - sp.addStore(STOREREF_USERS); + + try + { + sp.addStore(tenantService.getName(searchUserName, STOREREF_USERS)); + } + catch (AlfrescoRuntimeException e) + { + return null; // no such tenant or tenant not enabled + } + sp.excludeDataInTheCurrentTransaction(false); ResultSet rs = null; @@ -210,12 +225,14 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao public void createUser(String caseSensitiveUserName, char[] rawPassword) throws AuthenticationException { + tenantService.checkDomainUser(caseSensitiveUserName); + NodeRef userRef = getUserOrNull(caseSensitiveUserName); if (userRef != null) { throw new AuthenticationException("User already exists: " + caseSensitiveUserName); } - NodeRef typesNode = getUserFolderLocation(); + NodeRef typesNode = getUserFolderLocation(caseSensitiveUserName); Map properties = new HashMap(); properties.put(ContentModel.PROP_USER_USERNAME, caseSensitiveUserName); String salt = null; // GUID.generate(); @@ -230,12 +247,15 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao } - private NodeRef getUserFolderLocation() + private NodeRef getUserFolderLocation(String caseSensitiveUserName) { QName qnameAssocSystem = QName.createQName("sys", "system", namespacePrefixResolver); QName qnameAssocUsers = QName.createQName("sys", "people", namespacePrefixResolver); // see + + StoreRef userStoreRef = tenantService.getName(caseSensitiveUserName, new StoreRef(STOREREF_USERS.getProtocol(), STOREREF_USERS.getIdentifier())); + // AR-527 - NodeRef rootNode = nodeService.getRootNode(STOREREF_USERS); + NodeRef rootNode = nodeService.getRootNode(userStoreRef); List results = nodeService.getChildAssocs(rootNode, RegexQNamePattern.MATCH_ALL, qnameAssocSystem); NodeRef sysNodeRef = null; diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java b/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java index 542af517fc..310963b600 100644 --- a/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java +++ b/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java @@ -31,6 +31,7 @@ import java.util.Set; import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.permissions.PermissionServiceSPI; +import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; @@ -49,6 +50,8 @@ public class AuthorityServiceImpl implements AuthorityService private PersonService personService; private NodeService nodeService; + + private TenantService tenantService; private AuthorityDAO authorityDAO; @@ -73,6 +76,11 @@ public class AuthorityServiceImpl implements AuthorityService { this.nodeService = nodeService; } + + public void setTenantService(TenantService tenantService) + { + this.tenantService = tenantService; + } public void setPersonService(PersonService personService) { @@ -133,7 +141,13 @@ public class AuthorityServiceImpl implements AuthorityService public Set getAuthoritiesForUser(String currentUserName) { Set authorities = new HashSet(); - if (adminUsers.contains(currentUserName)) + + // note: for multi-tenancy, this currently relies on a naming convention which assumes that all tenant admins will + // have the same base name as the default non-tenant specific admin. Typically "admin" is the default required admin user, + // although, if for example "bob" is also listed as an admin then all tenant-specific bob's will also have admin authority + + if (adminUsers.contains(currentUserName) || + adminUsers.contains(tenantService.getBaseNameUser(currentUserName))) { authorities.addAll(adminSet); } diff --git a/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceImpl.java b/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceImpl.java index b705a508df..5e548c331d 100644 --- a/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceImpl.java +++ b/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceImpl.java @@ -30,6 +30,7 @@ import java.util.Set; import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; @@ -58,6 +59,9 @@ public class SimpleAuthorityServiceImpl implements AuthorityService private Set adminUsers; private AuthenticationComponent authenticationComponent; + + private TenantService tenantService; + public SimpleAuthorityServiceImpl() { @@ -73,6 +77,12 @@ public class SimpleAuthorityServiceImpl implements AuthorityService { this.personService = personService; } + + public void setTenantService(TenantService tenantService) + { + this.tenantService = tenantService; + } + /** * Currently the admin authority is granted only to the ALFRESCO_ADMIN_USER @@ -81,7 +91,12 @@ public class SimpleAuthorityServiceImpl implements AuthorityService public boolean hasAdminAuthority() { String currentUserName = authenticationComponent.getCurrentUserName(); - return ((currentUserName != null) && adminUsers.contains(currentUserName)); + + // note: for MT, this currently relies on a naming convention which assumes that all tenant admins will + // have the same base name as the default non-tenant specific admin. Typically "admin" is the default required admin user, + // although, if for example "bob" is also listed as an admin then all tenant-specific bob's will also have admin authority + + return ((currentUserName != null) && (adminUsers.contains(currentUserName) || adminUsers.contains(tenantService.getBaseNameUser(currentUserName)))); } /* (non-Javadoc) diff --git a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java index 602eea7c0d..90db9c5712 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java @@ -45,7 +45,7 @@ import org.alfresco.repo.security.permissions.NodePermissionEntry; import org.alfresco.repo.security.permissions.PermissionEntry; import org.alfresco.repo.security.permissions.PermissionReference; import org.alfresco.repo.security.permissions.PermissionServiceSPI; -import org.alfresco.repo.security.permissions.impl.model.PermissionModel; +import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; @@ -93,6 +93,11 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing */ private NodeService nodeService; + /* + * Access to the tenant service + */ + private TenantService tenantService; + /* * Access to the data dictionary */ @@ -141,6 +146,11 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing { this.nodeService = nodeService; } + + public void setTenantService(TenantService tenantService) + { + this.tenantService = tenantService; + } public void setPermissionsDaoComponent(PermissionsDaoComponent permissionsDaoComponent) { @@ -304,7 +314,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing public NodePermissionEntry getSetPermissions(NodeRef nodeRef) { - return permissionsDaoComponent.getPermissions(nodeRef); + return permissionsDaoComponent.getPermissions(tenantService.getName(nodeRef)); } public AccessStatus hasPermission(NodeRef nodeRef, PermissionReference perm) @@ -317,6 +327,8 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing return AccessStatus.ALLOWED; } + nodeRef = tenantService.getName(nodeRef); + // If the permission is null we deny if (perm == null) { @@ -414,6 +426,8 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing */ private Set getAuthorisations(Authentication auth, NodeRef nodeRef) { + nodeRef = tenantService.getName(nodeRef); + HashSet auths = new HashSet(); // No authenticated user then no permissions if (auth == null) @@ -452,7 +466,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing public void deletePermissions(NodeRef nodeRef) { - permissionsDaoComponent.deletePermissions(nodeRef); + permissionsDaoComponent.deletePermissions(tenantService.getName(nodeRef)); accessCache.clear(); } @@ -475,19 +489,19 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing public void deletePermission(NodeRef nodeRef, String authority, PermissionReference perm) { - permissionsDaoComponent.deletePermission(nodeRef, authority, perm); + permissionsDaoComponent.deletePermission(tenantService.getName(nodeRef), authority, perm); accessCache.clear(); } public void clearPermission(NodeRef nodeRef, String authority) { - permissionsDaoComponent.deletePermissions(nodeRef, authority); + permissionsDaoComponent.deletePermissions(tenantService.getName(nodeRef), authority); accessCache.clear(); } public void setPermission(NodeRef nodeRef, String authority, PermissionReference perm, boolean allow) { - permissionsDaoComponent.setPermission(nodeRef, authority, perm, allow); + permissionsDaoComponent.setPermission(tenantService.getName(nodeRef), authority, perm, allow); accessCache.clear(); } @@ -505,7 +519,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing public void setInheritParentPermissions(NodeRef nodeRef, boolean inheritParentPermissions) { - permissionsDaoComponent.setInheritParentPermissions(nodeRef, inheritParentPermissions); + permissionsDaoComponent.setInheritParentPermissions(tenantService.getName(nodeRef), inheritParentPermissions); accessCache.clear(); } @@ -514,7 +528,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing */ public boolean getInheritParentPermissions(NodeRef nodeRef) { - return permissionsDaoComponent.getInheritParentPermissions(nodeRef); + return permissionsDaoComponent.getInheritParentPermissions(tenantService.getName(nodeRef)); } public PermissionReference getPermissionReference(QName qname, String permissionName) diff --git a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java index 785cabae61..0064f46e16 100644 --- a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java +++ b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java @@ -40,6 +40,7 @@ import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.security.permissions.PermissionServiceSPI; +import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; @@ -79,6 +80,8 @@ public class PersonServiceImpl implements PersonService, private StoreRef storeRef; private NodeService nodeService; + + private TenantService tenantService; private SearchService searchService; @@ -224,7 +227,7 @@ public class PersonServiceImpl implements PersonService, SearchParameters sp = new SearchParameters(); sp.setLanguage(SearchService.LANGUAGE_LUCENE); sp.setQuery("@cm\\:userName:\"" + searchUserName + "\""); - sp.addStore(storeRef); + sp.addStore(tenantService.getName(storeRef)); sp.excludeDataInTheCurrentTransaction(false); ResultSet rs = null; @@ -342,7 +345,7 @@ public class PersonServiceImpl implements PersonService, SearchParameters sp = new SearchParameters(); sp.setLanguage(SearchService.LANGUAGE_LUCENE); sp.setQuery("@cm\\:userName:\"" + searchUserName + "\""); - sp.addStore(storeRef); + sp.addStore(tenantService.getName(storeRef)); sp.excludeDataInTheCurrentTransaction(false); ResultSet rs = null; @@ -392,7 +395,7 @@ public class PersonServiceImpl implements PersonService, SearchParameters sp = new SearchParameters(); sp.setLanguage(SearchService.LANGUAGE_LUCENE); sp.setQuery("@cm\\:userName:\"" + searchUserName + "\""); - sp.addStore(storeRef); + sp.addStore(tenantService.getName(storeRef)); sp.excludeDataInTheCurrentTransaction(false); ResultSet rs = null; @@ -444,7 +447,7 @@ public class PersonServiceImpl implements PersonService, SearchParameters sp = new SearchParameters(); sp.setLanguage(SearchService.LANGUAGE_LUCENE); sp.setQuery("@cm\\:userName:\"" + searchUserName + "\""); - sp.addStore(storeRef); + sp.addStore(tenantService.getName(storeRef)); sp.excludeDataInTheCurrentTransaction(false); if (lastIsBest) { @@ -599,7 +602,7 @@ public class PersonServiceImpl implements PersonService, { HashMap properties = new HashMap(); properties.put(ContentModel.PROP_USERNAME, userName); - properties.put(ContentModel.PROP_FIRSTNAME, userName); + properties.put(ContentModel.PROP_FIRSTNAME, tenantService.getBaseNameUser(userName)); properties.put(ContentModel.PROP_LASTNAME, ""); properties.put(ContentModel.PROP_EMAIL, ""); properties.put(ContentModel.PROP_ORGID, ""); @@ -618,7 +621,7 @@ public class PersonServiceImpl implements PersonService, public NodeRef getPeopleContainer() { - NodeRef rootNodeRef = nodeService.getRootNode(storeRef); + NodeRef rootNodeRef = nodeService.getRootNode(tenantService.getName(storeRef)); List results = searchService.selectNodes(rootNodeRef, PEOPLE_FOLDER, null, namespacePrefixResolver, false); if (results.size() == 0) @@ -657,7 +660,7 @@ public class PersonServiceImpl implements PersonService, SearchParameters sp = new SearchParameters(); sp.setLanguage(SearchService.LANGUAGE_LUCENE); sp.setQuery("TYPE:\"" + ContentModel.TYPE_PERSON + "\""); - sp.addStore(storeRef); + sp.addStore(tenantService.getName(storeRef)); sp.excludeDataInTheCurrentTransaction(false); LinkedHashSet nodes = new LinkedHashSet(); @@ -734,6 +737,11 @@ public class PersonServiceImpl implements PersonService, { this.nodeService = nodeService; } + + public void setTenantService(TenantService tenantService) + { + this.tenantService = tenantService; + } public void setSearchService(SearchService searchService) {