multi tenant LDAP user isolation

Hi there,

I'm using nuxeo 5.8HF10 in combination with LDAP.

I'm experiencing the following situation:

usera - tenantA
userb - tenantB

usera is a tenantA administrator. When searching in the admin center (users&groups) userb appears in the list.

How can we isolate the users?

I'm using the following LDAP configuration:

<fieldMapping name="username">email</fieldMapping>
<fieldMapping name="password">userpass</fieldMapping>
<fieldMapping name="firstName">name</fieldMapping>
<fieldMapping name="lastName">secondname</fieldMapping>
<fieldMapping name="company">organisation</fieldMapping>
<fieldMapping name="tenantId">organisation</fieldMapping>
<fieldMapping name="email">email</fieldMapping>

I think it is somewhere in the LDAP part, as running on a local machine without the LDAP it seems to work fine.

Do I need to configure the LDAP somehow different?

Thanks in advance, Bauke Roo


I've started working on this again and made some progress. It seems it is not needed to implement a new usermanager. The first change I made is a new operation based SuggestUserEntries.java, adding a filter in the run method. The code is at the bottom of this post.

I'm still experiencing an issue in the admin panel when searching for users these seem to be multi-tenant fit yet. the following ajax call is made to /nuxeo/view_admin.faces:

AJAX:EVENTS_COUNT   1
AJAXREQUEST usersListingView:search_users_region
autoScroll  
javax.faces.ViewState   j_id7
usersListingView:searchFo...    usersListingView:searchForm
usersListingView:searchFo...    usersListingView:searchForm
usersListingView:searchFo...    Search
usersListingView:searchFo...    test

I cannot find in which class this call/method is executed, can someone please help?


update The search seems to be executed in the org.nuxeo.ecm.platform.usermanager.providers.UsersPageProvider

My plan is to create a new page provider in order to add a filter in the methods. The question now is: How can I get the tenantId of the users in this pageProvider?

I've tried passing it in the pageproviders-contrib.xml:

 <extension target="org.nuxeo.ecm.platform.query.api.PageProviderService"
    point="providers">

    <genericPageProvider name="users_listing"
      class="org.nuxeo.capgemini.LDAPMultiTenancyPageProvider">
      <pageSize>20</pageSize>
      <property name="tenantId">#{currentUser.tenantId}</property>
    </genericPageProvider>
   </extension>

However this just returns #{currentUser.tenantId} in the java code.

Is there a way to get the userInfo in a pageprovider?


code below

Custom method for the new operation based on SuggestUserEntries.java:

 @OperationMethod
    public Blob run() throws ClientException {

        if(prefix.isEmpty())
        {
            prefix = searchTerm;
        }
        JSONArray result = new JSONArray();
        boolean isGroupRestriction = !StringUtils.isBlank(groupRestriction);
        boolean groupOnly = false;
        boolean userOnly = isGroupRestriction;

        if (!isGroupRestriction && searchType != null && !searchType.isEmpty()) {
            if (searchType.equals(Select2Common.USER_TYPE)) {
                userOnly = true;
            } else if (searchType.equals(Select2Common.GROUP_TYPE)) {
                groupOnly = true;
            }
        }
        try {
            ArrayList<DocumentModel> userList = new ArrayList<DocumentModel>();
            DocumentModelList groupList = null;
            if (!groupOnly) {
                log.info("userManager: "+userManager.getUserSchemaName());
                Schema schema = schemaManager.getSchema(userManager.getUserSchemaName());

                //changed this
                MultiTenantPrincipal principal = (MultiTenantPrincipal) ctx.getPrincipal();
                String tenantId = principal.getTenantId();

                for (String field : FULLTEXT_FIELDS) {
                    Map<String, Serializable> filter = new HashMap<String, Serializable>();
                    filter.put(field, prefix);

                    if (!StringUtils.isBlank(tenantId)) {
                        filter.put("tenantId", tenantId);
                    }

                    userList.addAll(userManager.searchUsers(filter, filter.keySet()));

                }
                userList = removeDuplicates(userList);
                //changed this


                Directory userDir = directoryService.getDirectory(userManager.getUserDirectoryName());
                for (DocumentModel user : userList) {
                    JSONObject obj = new JSONObject();
                    for (Field field : schema.getFields()) {
                        QName fieldName = field.getName();
                        String key = fieldName.getLocalName();
                        Serializable value = user.getPropertyValue(fieldName.getPrefixedName());
                        if (key.equals(userDir.getPasswordField())) {
                            continue;
                        }
                        obj.element(key, value);
                    }
                    String userId = user.getId();
                    obj.put(Select2Common.ID, userId);
                    obj.put(Select2Common.TYPE_KEY_NAME,
                            Select2Common.USER_TYPE);
                    obj.put(Select2Common.PREFIXED_ID_KEY_NAME,
                            NuxeoPrincipal.PREFIX + userId);
                    Select2Common.computeUserLabel(obj, firstLabelField,
                            secondLabelField, thirdLabelField, hideFirstLabel,
                            hideSecondLabel, hideThirdLabel,
                            displayEmailInSuggestion, userId);
                    Select2Common.computeUserGroupIcon(obj, hideIcon);
                    if (isGroupRestriction) {
                        // We need to load all data about the user particularly
                        // its
                        // groups.
                        user = userManager.getUserModel(userId);
                        UserAdapter userAdapter = user.getAdapter(UserAdapter.class);
                        List<String> groups = userAdapter.getGroups();
                        if (groups != null && groups.contains(groupRestriction)) {
                            result.add(obj);
                        }
                    } else {
                        result.add(obj);
                    }
                }
            }
            if (!userOnly) {
                Schema schema = schemaManager.getSchema(userManager.getGroupSchemaName());
                groupList = userManager.searchGroups(prefix);
                for (DocumentModel group : groupList) {
                    JSONObject obj = new JSONObject();
                    for (Field field : schema.getFields()) {
                        QName fieldName = field.getName();
                        String key = fieldName.getLocalName();
                        Serializable value = group.getPropertyValue(fieldName.getPrefixedName());
                        obj.element(key, value);
                    }
                    String groupId = group.getId();
                    obj.put(Select2Common.ID, groupId);
                    // If the group hasn't an label, let's put the groupid
                    Select2Common.computeGroupLabel(obj, groupId,
                            userManager.getGroupLabelField(), hideFirstLabel);
                    obj.put(Select2Common.TYPE_KEY_NAME,
                            Select2Common.GROUP_TYPE);
                    obj.put(Select2Common.PREFIXED_ID_KEY_NAME,
                            NuxeoGroup.PREFIX + groupId);
                    Select2Common.computeUserGroupIcon(obj, hideIcon);
                    result.add(obj);
                }
            }

            // Limit size results.
            int userSize = userList != null ? userList.size() : 0;
            int groupSize = groupList != null ? groupList.size() : 0;
            int totalSize = userSize + groupSize;
            if (userSuggestionMaxSearchResults != null
                    && userSuggestionMaxSearchResults > 0) {
                if (userSize > userSuggestionMaxSearchResults
                        || groupSize > userSuggestionMaxSearchResults
                        || totalSize > userSuggestionMaxSearchResults) {
                    throw new SizeLimitExceededException();
                }
            }

        } catch (SizeLimitExceededException e) {
            return searchOverflowMessage();
        }

        return new StringBlob(result.toString(), "application/json");
    }
3 votes

0 answers

1683 views

ANSWER

no reply, why?
04/14/2014

I'm interested in the answer as well, any clue?
10/07/2014

For now it seems it is not possible. I believe that in order to make this work a new usermanagerImpl class has to be written.
10/07/2014

thanks for your feedback
10/07/2014

I'm new to Nuxeo and also interested in this question and since it's already almost 3 years old, I wonder if anything has changed? Can I use a different Active Directory server for each tenant (without writing custom implementations from scratch)? Thanks!
01/24/2017