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)
{