mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
- 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:
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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<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);
|
||||
}
|
||||
|
@@ -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<String> 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)
|
||||
|
@@ -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<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)
|
||||
|
@@ -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<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>();
|
||||
@@ -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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user