TSK-1634: Endpoint in AccessIdController to search users and members of groups configured with TASKANA user role
This commit is contained in:
parent
4c94281a64
commit
38363b81d6
|
@ -14,6 +14,7 @@ taskana.ldap.userFirstnameAttribute=givenName
|
||||||
taskana.ldap.userLastnameAttribute=sn
|
taskana.ldap.userLastnameAttribute=sn
|
||||||
taskana.ldap.userFullnameAttribute=cn
|
taskana.ldap.userFullnameAttribute=cn
|
||||||
taskana.ldap.userIdAttribute=uid
|
taskana.ldap.userIdAttribute=uid
|
||||||
|
taskana.ldap.userMemberOfGroupAttribute=
|
||||||
taskana.ldap.groupSearchBase=cn=groups
|
taskana.ldap.groupSearchBase=cn=groups
|
||||||
taskana.ldap.groupSearchFilterName=objectclass
|
taskana.ldap.groupSearchFilterName=objectclass
|
||||||
taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
|
taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
|
||||||
|
|
|
@ -68,6 +68,7 @@ taskana.ldap.userFirstnameAttribute=givenName
|
||||||
taskana.ldap.userLastnameAttribute=sn
|
taskana.ldap.userLastnameAttribute=sn
|
||||||
taskana.ldap.userFullnameAttribute=cn
|
taskana.ldap.userFullnameAttribute=cn
|
||||||
taskana.ldap.userIdAttribute=uid
|
taskana.ldap.userIdAttribute=uid
|
||||||
|
taskana.ldap.userMemberOfGroupAttribute=
|
||||||
taskana.ldap.groupSearchBase=
|
taskana.ldap.groupSearchBase=
|
||||||
taskana.ldap.groupSearchFilterName=objectclass
|
taskana.ldap.groupSearchFilterName=objectclass
|
||||||
taskana.ldap.groupSearchFilterValue=groupofuniquenames
|
taskana.ldap.groupSearchFilterValue=groupofuniquenames
|
||||||
|
|
|
@ -24,6 +24,7 @@ taskana.ldap.userFirstnameAttribute=givenName
|
||||||
taskana.ldap.userLastnameAttribute=sn
|
taskana.ldap.userLastnameAttribute=sn
|
||||||
taskana.ldap.userFullnameAttribute=cn
|
taskana.ldap.userFullnameAttribute=cn
|
||||||
taskana.ldap.userIdAttribute=uid
|
taskana.ldap.userIdAttribute=uid
|
||||||
|
taskana.ldap.userMemberOfGroupAttribute=
|
||||||
taskana.ldap.groupSearchBase=cn=groups
|
taskana.ldap.groupSearchBase=cn=groups
|
||||||
taskana.ldap.groupSearchFilterName=objectclass
|
taskana.ldap.groupSearchFilterName=objectclass
|
||||||
taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
|
taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
|
||||||
|
|
|
@ -19,6 +19,7 @@ taskana.ldap.userFirstnameAttribute=givenName
|
||||||
taskana.ldap.userLastnameAttribute=sn
|
taskana.ldap.userLastnameAttribute=sn
|
||||||
taskana.ldap.userFullnameAttribute=cn
|
taskana.ldap.userFullnameAttribute=cn
|
||||||
taskana.ldap.userIdAttribute=uid
|
taskana.ldap.userIdAttribute=uid
|
||||||
|
taskana.ldap.userMemberOfGroupAttribute=
|
||||||
taskana.ldap.groupSearchBase=
|
taskana.ldap.groupSearchBase=
|
||||||
taskana.ldap.groupSearchFilterName=objectclass
|
taskana.ldap.groupSearchFilterName=objectclass
|
||||||
taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
|
taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
|
||||||
|
|
|
@ -19,6 +19,7 @@ taskana.ldap.userFirstnameAttribute=givenName
|
||||||
taskana.ldap.userLastnameAttribute=sn
|
taskana.ldap.userLastnameAttribute=sn
|
||||||
taskana.ldap.userFullnameAttribute=cn
|
taskana.ldap.userFullnameAttribute=cn
|
||||||
taskana.ldap.userIdAttribute=uid
|
taskana.ldap.userIdAttribute=uid
|
||||||
|
taskana.ldap.userMemberOfGroupAttribute=
|
||||||
taskana.ldap.groupSearchBase=
|
taskana.ldap.groupSearchBase=
|
||||||
taskana.ldap.groupSearchFilterName=objectclass
|
taskana.ldap.groupSearchFilterName=objectclass
|
||||||
taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
|
taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
|
||||||
|
|
|
@ -62,6 +62,47 @@ public class AccessIdController {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This endpoint searches users for a provided name or Access Id. It will only search and return
|
||||||
|
* users and members of groups which are configured with the requested TASKANA role. This
|
||||||
|
* search will only work if the users in the configured LDAP have an attribute that shows their
|
||||||
|
* group memberships, e.g. "memberOf"
|
||||||
|
*
|
||||||
|
* @title Search for Access Id (users) in TASKANA user role
|
||||||
|
* @param nameOrAccessId the name or Access Id which should be searched for.
|
||||||
|
* @param role the role for which all users should be searched for
|
||||||
|
* @return a list of all found Access Ids (users)
|
||||||
|
* @throws InvalidArgumentException if the provided search for Access Id is shorter than the
|
||||||
|
* configured one.
|
||||||
|
*/
|
||||||
|
@GetMapping(path = RestEndpoints.URL_USER)
|
||||||
|
public ResponseEntity<List<AccessIdRepresentationModel>> searchUsersByNameOrAccessIdForRole(
|
||||||
|
@RequestParam("search-for") String nameOrAccessId, @RequestParam("role") String role)
|
||||||
|
throws InvalidArgumentException {
|
||||||
|
|
||||||
|
LOGGER.debug(
|
||||||
|
"Entry to searchUsersByNameOrAccessIdForRole(search-for= {}, role= {})",
|
||||||
|
nameOrAccessId,
|
||||||
|
role);
|
||||||
|
|
||||||
|
if (role.equals("user")) {
|
||||||
|
List<AccessIdRepresentationModel> accessIdUsers =
|
||||||
|
ldapClient.searchUsersByNameOrAccessIdInUserRole(nameOrAccessId);
|
||||||
|
ResponseEntity<List<AccessIdRepresentationModel>> response = ResponseEntity.ok(accessIdUsers);
|
||||||
|
|
||||||
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
LOGGER.debug(
|
||||||
|
"Exit from searchUsersByNameOrAccessIdForRole(), returning {}", response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} else {
|
||||||
|
throw new InvalidArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Requested users for not supported role %s. Only role 'user' is supported'", role));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This endpoint retrieves all groups a given Access Id belongs to.
|
* This endpoint retrieves all groups a given Access Id belongs to.
|
||||||
*
|
*
|
||||||
|
|
|
@ -17,6 +17,7 @@ public final class RestEndpoints {
|
||||||
|
|
||||||
// access id endpoints
|
// access id endpoints
|
||||||
public static final String URL_ACCESS_ID = API_V1 + "access-ids";
|
public static final String URL_ACCESS_ID = API_V1 + "access-ids";
|
||||||
|
public static final String URL_USER = API_V1 + "users";
|
||||||
public static final String URL_ACCESS_ID_GROUPS = API_V1 + "access-ids/groups";
|
public static final String URL_ACCESS_ID_GROUPS = API_V1 + "access-ids/groups";
|
||||||
|
|
||||||
// import / export endpoints
|
// import / export endpoints
|
||||||
|
|
|
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
@ -23,6 +24,8 @@ import org.springframework.ldap.filter.WhitespaceWildcardsFilter;
|
||||||
import org.springframework.ldap.support.LdapNameBuilder;
|
import org.springframework.ldap.support.LdapNameBuilder;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import pro.taskana.TaskanaEngineConfiguration;
|
||||||
|
import pro.taskana.common.api.TaskanaRole;
|
||||||
import pro.taskana.common.api.exceptions.InvalidArgumentException;
|
import pro.taskana.common.api.exceptions.InvalidArgumentException;
|
||||||
import pro.taskana.common.api.exceptions.SystemException;
|
import pro.taskana.common.api.exceptions.SystemException;
|
||||||
import pro.taskana.common.rest.models.AccessIdRepresentationModel;
|
import pro.taskana.common.rest.models.AccessIdRepresentationModel;
|
||||||
|
@ -34,6 +37,7 @@ public class LdapClient {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(LdapClient.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(LdapClient.class);
|
||||||
private static final String CN = "cn";
|
private static final String CN = "cn";
|
||||||
|
|
||||||
|
private final TaskanaEngineConfiguration taskanaEngineConfiguration;
|
||||||
private final Environment env;
|
private final Environment env;
|
||||||
private final LdapTemplate ldapTemplate;
|
private final LdapTemplate ldapTemplate;
|
||||||
private boolean active = false;
|
private boolean active = false;
|
||||||
|
@ -42,9 +46,13 @@ public class LdapClient {
|
||||||
private String message;
|
private String message;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LdapClient(Environment env, LdapTemplate ldapTemplate) {
|
public LdapClient(
|
||||||
|
Environment env,
|
||||||
|
LdapTemplate ldapTemplate,
|
||||||
|
TaskanaEngineConfiguration taskanaEngineConfiguration) {
|
||||||
this.env = env;
|
this.env = env;
|
||||||
this.ldapTemplate = ldapTemplate;
|
this.ldapTemplate = ldapTemplate;
|
||||||
|
this.taskanaEngineConfiguration = taskanaEngineConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,6 +91,49 @@ public class LdapClient {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<AccessIdRepresentationModel> searchUsersByNameOrAccessIdInUserRole(
|
||||||
|
final String nameOrAccessId) throws InvalidArgumentException {
|
||||||
|
|
||||||
|
LOGGER.debug(
|
||||||
|
"entry to searchUsersByNameOrAccessIdInUserRoleGroups(nameOrAccessId = {}).",
|
||||||
|
nameOrAccessId);
|
||||||
|
|
||||||
|
isInitOrFail();
|
||||||
|
testMinSearchForLength(nameOrAccessId);
|
||||||
|
|
||||||
|
final OrFilter userDetailsOrFilter = new OrFilter();
|
||||||
|
userDetailsOrFilter.or(
|
||||||
|
new WhitespaceWildcardsFilter(getUserFirstnameAttribute(), nameOrAccessId));
|
||||||
|
userDetailsOrFilter.or(
|
||||||
|
new WhitespaceWildcardsFilter(getUserLastnameAttribute(), nameOrAccessId));
|
||||||
|
userDetailsOrFilter.or(
|
||||||
|
new WhitespaceWildcardsFilter(getUserFullnameAttribute(), nameOrAccessId));
|
||||||
|
userDetailsOrFilter.or(new WhitespaceWildcardsFilter(getUserIdAttribute(), nameOrAccessId));
|
||||||
|
|
||||||
|
Set<String> userGroups = taskanaEngineConfiguration.getRoleMap().get(TaskanaRole.USER);
|
||||||
|
|
||||||
|
final OrFilter groupMembershipOrFilter = new OrFilter();
|
||||||
|
userGroups.forEach(
|
||||||
|
group ->
|
||||||
|
groupMembershipOrFilter.or(new EqualsFilter(getUserMemberOfGroupAttribute(), group)));
|
||||||
|
|
||||||
|
final AndFilter andFilter = new AndFilter();
|
||||||
|
andFilter.and(userDetailsOrFilter);
|
||||||
|
andFilter.and(groupMembershipOrFilter);
|
||||||
|
|
||||||
|
final List<AccessIdRepresentationModel> accessIds =
|
||||||
|
ldapTemplate.search(
|
||||||
|
getUserSearchBase(),
|
||||||
|
andFilter.encode(),
|
||||||
|
SearchControls.SUBTREE_SCOPE,
|
||||||
|
getLookUpUserAttributesToReturn(),
|
||||||
|
new UserContextMapper());
|
||||||
|
LOGGER.debug(
|
||||||
|
"exit from searchUsersByNameOrAccessIdInUserRoleGroups. Retrieved the following users: {}.",
|
||||||
|
accessIds);
|
||||||
|
return accessIds;
|
||||||
|
}
|
||||||
|
|
||||||
public List<AccessIdRepresentationModel> searchUsersByNameOrAccessId(final String name)
|
public List<AccessIdRepresentationModel> searchUsersByNameOrAccessId(final String name)
|
||||||
throws InvalidArgumentException {
|
throws InvalidArgumentException {
|
||||||
LOGGER.debug("entry to searchUsersByNameOrAccessId(name = {}).", name);
|
LOGGER.debug("entry to searchUsersByNameOrAccessId(name = {}).", name);
|
||||||
|
@ -278,6 +329,10 @@ public class LdapClient {
|
||||||
return LdapSettings.TASKANA_LDAP_USER_ID_ATTRIBUTE.getValueFromEnv(env);
|
return LdapSettings.TASKANA_LDAP_USER_ID_ATTRIBUTE.getValueFromEnv(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getUserMemberOfGroupAttribute() {
|
||||||
|
return LdapSettings.TASKANA_LDAP_USER_MEMBER_OF_GROUP_ATTRIBUTE.getValueFromEnv(env);
|
||||||
|
}
|
||||||
|
|
||||||
public String getGroupSearchBase() {
|
public String getGroupSearchBase() {
|
||||||
return LdapSettings.TASKANA_LDAP_GROUP_SEARCH_BASE.getValueFromEnv(env);
|
return LdapSettings.TASKANA_LDAP_GROUP_SEARCH_BASE.getValueFromEnv(env);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ enum LdapSettings {
|
||||||
TASKANA_LDAP_USER_LASTNAME_ATTRIBUTE("taskana.ldap.userLastnameAttribute"),
|
TASKANA_LDAP_USER_LASTNAME_ATTRIBUTE("taskana.ldap.userLastnameAttribute"),
|
||||||
TASKANA_LDAP_USER_FULLNAME_ATTRIBUTE("taskana.ldap.userFullnameAttribute"),
|
TASKANA_LDAP_USER_FULLNAME_ATTRIBUTE("taskana.ldap.userFullnameAttribute"),
|
||||||
TASKANA_LDAP_USER_ID_ATTRIBUTE("taskana.ldap.userIdAttribute"),
|
TASKANA_LDAP_USER_ID_ATTRIBUTE("taskana.ldap.userIdAttribute"),
|
||||||
|
TASKANA_LDAP_USER_MEMBER_OF_GROUP_ATTRIBUTE("taskana.ldap.userMemberOfGroupAttribute"),
|
||||||
TASKANA_LDAP_GROUP_SEARCH_BASE("taskana.ldap.groupSearchBase"),
|
TASKANA_LDAP_GROUP_SEARCH_BASE("taskana.ldap.groupSearchBase"),
|
||||||
TASKANA_LDAP_BASE_DN("taskana.ldap.baseDn"),
|
TASKANA_LDAP_BASE_DN("taskana.ldap.baseDn"),
|
||||||
TASKANA_LDAP_GROUP_SEARCH_FILTER_NAME("taskana.ldap.groupSearchFilterName"),
|
TASKANA_LDAP_GROUP_SEARCH_FILTER_NAME("taskana.ldap.groupSearchFilterName"),
|
||||||
|
|
|
@ -11,7 +11,10 @@ import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
@ -23,6 +26,8 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.ldap.core.LdapTemplate;
|
import org.springframework.ldap.core.LdapTemplate;
|
||||||
|
|
||||||
|
import pro.taskana.TaskanaEngineConfiguration;
|
||||||
|
import pro.taskana.common.api.TaskanaRole;
|
||||||
import pro.taskana.common.api.exceptions.SystemException;
|
import pro.taskana.common.api.exceptions.SystemException;
|
||||||
import pro.taskana.common.rest.models.AccessIdRepresentationModel;
|
import pro.taskana.common.rest.models.AccessIdRepresentationModel;
|
||||||
|
|
||||||
|
@ -33,6 +38,8 @@ class LdapClientTest {
|
||||||
|
|
||||||
@Mock LdapTemplate ldapTemplate;
|
@Mock LdapTemplate ldapTemplate;
|
||||||
|
|
||||||
|
@Mock TaskanaEngineConfiguration taskanaEngineConfiguration;
|
||||||
|
|
||||||
@InjectMocks LdapClient cut;
|
@InjectMocks LdapClient cut;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -90,6 +97,27 @@ class LdapClientTest {
|
||||||
assertThat(accessIds.get(3).getAccessId()).isNull();
|
assertThat(accessIds.get(3).getAccessId()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void should_ReturnAllUsersAndMembersOfGroupsWithTaskanaUserRole() throws Exception {
|
||||||
|
|
||||||
|
setUpEnvMock();
|
||||||
|
cut.init();
|
||||||
|
|
||||||
|
AccessIdRepresentationModel user = new AccessIdRepresentationModel("testU", "testUId");
|
||||||
|
|
||||||
|
Set<String> groupsOfUserRole = new HashSet<>();
|
||||||
|
Map<TaskanaRole, Set<String>> roleMap = new HashMap<>();
|
||||||
|
roleMap.put(TaskanaRole.USER, groupsOfUserRole);
|
||||||
|
|
||||||
|
when(taskanaEngineConfiguration.getRoleMap()).thenReturn(roleMap);
|
||||||
|
|
||||||
|
when(ldapTemplate.search(
|
||||||
|
any(String.class), any(), anyInt(), any(), any(LdapClient.UserContextMapper.class)))
|
||||||
|
.thenReturn(List.of(user));
|
||||||
|
|
||||||
|
assertThat(cut.searchUsersByNameOrAccessIdInUserRole("test")).hasSize(1).containsExactly(user);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testLdap_getNameWithoutBaseDn() {
|
void testLdap_getNameWithoutBaseDn() {
|
||||||
|
|
||||||
|
@ -159,6 +187,7 @@ class LdapClientTest {
|
||||||
{"taskana.ldap.groupSearchFilterName", "objectclass"},
|
{"taskana.ldap.groupSearchFilterName", "objectclass"},
|
||||||
{"taskana.ldap.groupSearchBase", "ou=groups"},
|
{"taskana.ldap.groupSearchBase", "ou=groups"},
|
||||||
{"taskana.ldap.userIdAttribute", "uid"},
|
{"taskana.ldap.userIdAttribute", "uid"},
|
||||||
|
{"taskana.ldap.userMemberOfGroupAttribute", "memberOf"},
|
||||||
{"taskana.ldap.userLastnameAttribute", "sn"},
|
{"taskana.ldap.userLastnameAttribute", "sn"},
|
||||||
{"taskana.ldap.userFirstnameAttribute", "givenName"},
|
{"taskana.ldap.userFirstnameAttribute", "givenName"},
|
||||||
{"taskana.ldap.userFullnameAttribute", "cn"},
|
{"taskana.ldap.userFullnameAttribute", "cn"},
|
||||||
|
|
|
@ -23,6 +23,7 @@ taskana.ldap.userFirstnameAttribute=givenName
|
||||||
taskana.ldap.userLastnameAttribute=sn
|
taskana.ldap.userLastnameAttribute=sn
|
||||||
taskana.ldap.userFullnameAttribute=cn
|
taskana.ldap.userFullnameAttribute=cn
|
||||||
taskana.ldap.userIdAttribute=uid
|
taskana.ldap.userIdAttribute=uid
|
||||||
|
taskana.ldap.userMemberOfGroupAttribute=
|
||||||
taskana.ldap.groupSearchBase=
|
taskana.ldap.groupSearchBase=
|
||||||
taskana.ldap.groupSearchFilterName=objectclass
|
taskana.ldap.groupSearchFilterName=objectclass
|
||||||
taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
|
taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
|
||||||
|
|
Loading…
Reference in New Issue