- 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
This commit is contained in:
Jan Vonka
2007-08-02 10:56:30 +00:00
parent 56a0b7e164
commit 65f660c26c
11 changed files with 141 additions and 22 deletions

View File

@@ -79,6 +79,9 @@
<property name="nodeService">
<ref bean="nodeService" />
</property>
<property name="tenantService">
<ref bean="tenantService"/>
</property>
<property name="dictionaryService">
<ref bean="dictionaryService" />
</property>
@@ -179,6 +182,9 @@
<property name="nodeService">
<ref bean="nodeService" />
</property>
<property name="tenantService">
<ref bean="tenantService"/>
</property>
<property name="searchService">
<ref bean="admSearchService" />
</property>

View File

@@ -22,6 +22,9 @@
<property name="nodeService">
<ref bean="nodeService" />
</property>
<property name="tenantService">
<ref bean="tenantService"/>
</property>
<property name="authorityDAO">
<ref bean="authorityDAO" />
</property>

View File

@@ -39,6 +39,9 @@
<property name="nodeService">
<ref bean="nodeService" />
</property>
<property name="tenantService">
<ref bean="tenantService"/>
</property>
<property name="dictionaryService">
<ref bean="dictionaryService" />
</property>

View File

@@ -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);
}
}
/**

View File

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

View File

@@ -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,9 +153,34 @@ 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
*

View File

@@ -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<QName, Serializable> properties = new HashMap<QName, Serializable>();
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<ChildAssociationRef> results = nodeService.getChildAssocs(rootNode, RegexQNamePattern.MATCH_ALL,
qnameAssocSystem);
NodeRef sysNodeRef = null;

View File

@@ -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;
@@ -50,6 +51,8 @@ public class AuthorityServiceImpl implements AuthorityService
private NodeService nodeService;
private TenantService tenantService;
private AuthorityDAO authorityDAO;
private PermissionServiceSPI permissionServiceSPI;
@@ -74,6 +77,11 @@ public class AuthorityServiceImpl implements AuthorityService
this.nodeService = nodeService;
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
public void setPersonService(PersonService personService)
{
this.personService = personService;
@@ -133,7 +141,13 @@ public class AuthorityServiceImpl implements AuthorityService
public Set<String> getAuthoritiesForUser(String currentUserName)
{
Set<String> authorities = new HashSet<String>();
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);
}

View File

@@ -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;
@@ -59,6 +60,9 @@ public class SimpleAuthorityServiceImpl implements AuthorityService
private AuthenticationComponent authenticationComponent;
private TenantService tenantService;
public SimpleAuthorityServiceImpl()
{
super();
@@ -74,6 +78,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
* 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)

View File

@@ -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
*/
@@ -142,6 +147,11 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
this.nodeService = nodeService;
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
public void setPermissionsDaoComponent(PermissionsDaoComponent permissionsDaoComponent)
{
this.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<String> getAuthorisations(Authentication auth, NodeRef nodeRef)
{
nodeRef = tenantService.getName(nodeRef);
HashSet<String> auths = new HashSet<String>();
// 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)

View File

@@ -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;
@@ -80,6 +81,8 @@ public class PersonServiceImpl implements PersonService,
private NodeService nodeService;
private TenantService tenantService;
private SearchService searchService;
private AuthorityService authorityService;
@@ -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<QName, Serializable> properties = new HashMap<QName, Serializable>();
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<NodeRef> 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<NodeRef> nodes = new LinkedHashSet<NodeRef>();
@@ -735,6 +738,11 @@ public class PersonServiceImpl implements PersonService,
this.nodeService = nodeService;
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;