diff --git a/pom.xml b/pom.xml
index 52d8ca033..29dcea80f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -75,6 +75,9 @@
0.13.0
3.2.4
3.2.4
+
+ 1.9.7
+ 1.9.7
2.0.5
2.2
3.1.12
diff --git a/rest/taskana-rest-spring/pom.xml b/rest/taskana-rest-spring/pom.xml
index bbfefa2a3..38d74ffdf 100644
--- a/rest/taskana-rest-spring/pom.xml
+++ b/rest/taskana-rest-spring/pom.xml
@@ -139,6 +139,30 @@
${version.spring.restdocs}
test
+
+ org.mockito
+ mockito-core
+ ${version.mockito}
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ ${version.junit.mockito}
+ test
+
+
+ net.bytebuddy
+ byte-buddy
+ ${version.byte-buddy}
+ test
+
+
+ net.bytebuddy
+ byte-buddy-agent
+ ${version.byte-buddy-agent}
+ test
+
com.h2database
h2
diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/ldap/LdapClient.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/ldap/LdapClient.java
index 49de6975c..51aa85f4b 100644
--- a/rest/taskana-rest-spring/src/main/java/pro/taskana/ldap/LdapClient.java
+++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/ldap/LdapClient.java
@@ -1,6 +1,7 @@
package pro.taskana.ldap;
import java.util.List;
+import java.util.regex.Pattern;
import javax.annotation.PostConstruct;
import javax.naming.directory.SearchControls;
import org.slf4j.Logger;
@@ -64,6 +65,8 @@ public class LdapClient {
private String groupsOfUser;
+ private String baseDn;
+
private int minSearchForLength;
private int maxNumberOfReturnedAccessIds;
@@ -182,16 +185,22 @@ public class LdapClient {
throw new SystemException(
"LdapClient was called but is not active due to missing configuration: " + message);
}
-
+ // Obviously Spring LdapTemplate does have a inconsistency and always adds the base name to the
+ // given DN.
+ // https://stackoverflow.com/questions/55285743/spring-ldaptemplate-how-to-lookup-fully-qualified-dn-with-configured-base-dn
+ // Therefore we have to remove the base name from the dn before performing the lookup
+ // (?i) --> case insensitive replacement
+ String nameWithoutBaseDn = name.replaceAll("(?i)" + Pattern.quote("," + baseDn), "");
+ LOGGER.debug(
+ "Removes baseDN {} from given DN. New DN to be used: {}", baseDn, nameWithoutBaseDn);
String[] groupAttributesToReturn;
if (CN.equals(groupNameAttribute)) {
groupAttributesToReturn = new String[] {CN};
} else {
groupAttributesToReturn = new String[] {getGroupNameAttribute(), CN};
}
-
final AccessIdResource accessId =
- ldapTemplate.lookup(name, groupAttributesToReturn, new GroupContextMapper());
+ ldapTemplate.lookup(nameWithoutBaseDn, groupAttributesToReturn, new GroupContextMapper());
LOGGER.debug("Exit from searchGroupByDn. Retrieved the following group: {}", accessId);
return accessId;
}
@@ -261,6 +270,10 @@ public class LdapClient {
return env.getProperty("taskana.ldap.groupSearchBase");
}
+ public String getBaseDn() {
+ return env.getProperty("taskana.ldap.baseDn");
+ }
+
public String getGroupSearchFilterName() {
return env.getProperty("taskana.ldap.groupSearchFilterName");
}
@@ -298,7 +311,7 @@ public class LdapClient {
}
@PostConstruct
- private void init() {
+ void init() {
LOGGER.debug("Entry to init()");
String strMinSearchForLength = getMinSearchForLengthAsString();
if (strMinSearchForLength == null || strMinSearchForLength.isEmpty()) {
@@ -326,6 +339,7 @@ public class LdapClient {
groupSearchFilterValue = getGroupSearchFilterValue();
groupNameAttribute = getGroupNameAttribute();
groupsOfUser = getGroupsOfUser();
+ baseDn = getBaseDn();
ldapTemplate.setDefaultCountLimit(maxNumberOfReturnedAccessIds);
@@ -364,6 +378,9 @@ public class LdapClient {
if (groupsOfUser == null) {
message += " taskana.ldap.groupsOfUser is not configured.";
}
+ if (baseDn == null) {
+ message += " taskana.ldap.baseDn is not configured.";
+ }
if (!message.equals(emptyMessage)) {
throw new SystemException(message);
}
@@ -383,7 +400,7 @@ public class LdapClient {
}
/** Context Mapper for user entries. */
- private class UserContextMapper extends AbstractContextMapper {
+ class UserContextMapper extends AbstractContextMapper {
@Override
public AccessIdResource doMapFromContext(final DirContextOperations context) {
@@ -397,7 +414,7 @@ public class LdapClient {
}
/** Context Mapper for user entries. */
- private class GroupContextMapper extends AbstractContextMapper {
+ class GroupContextMapper extends AbstractContextMapper {
@Override
public AccessIdResource doMapFromContext(final DirContextOperations context) {
diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/ldap/LdapClientTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/ldap/LdapClientTest.java
new file mode 100644
index 000000000..afaf4d8a7
--- /dev/null
+++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/ldap/LdapClientTest.java
@@ -0,0 +1,63 @@
+package pro.taskana.ldap;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.verify;
+
+import java.util.stream.Stream;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.springframework.core.env.Environment;
+import org.springframework.ldap.core.LdapTemplate;
+
+@MockitoSettings
+class LdapClientTest {
+
+ @Mock Environment environment;
+
+ @Mock LdapTemplate ldapTemplate;
+
+ @InjectMocks LdapClient cut;
+
+ @Test
+ void testLdap() {
+
+ setUpEnvMock();
+ cut.init();
+
+ cut.searchGroupByDn("cn=developersgroup,ou=groups,o=taskanatest");
+
+ verify(ldapTemplate)
+ .lookup(
+ eq("cn=developersgroup,ou=groups"), any(), any(LdapClient.GroupContextMapper.class));
+ }
+
+ private void setUpEnvMock() {
+ Stream.of(
+ new String[][] {
+ {"taskana.ldap.useLdap", "true"},
+ {"taskana.ldap.baseDn", "o=TaskanaTest"},
+ {"taskana.ldap.userSearchBase", "ou=people"},
+ {"taskana.ldap.userSearchFilterName", "objectclass"},
+ {"taskana.ldap.groupsOfUser", "memberUid"},
+ {"taskana.ldap.groupNameAttribute", "cn"},
+ {"taskana.ldap.groupSearchFilterValue", "groupOfUniqueNames"},
+ {"taskana.ldap.groupSearchFilterName", "objectclass"},
+ {"taskana.ldap.groupSearchBase", "ou=groups"},
+ {"taskana.ldap.userIdAttribute", "uid"},
+ {"taskana.ldap.userLastnameAttribute", "sn"},
+ {"taskana.ldap.userFirstnameAttribute", "givenName"},
+ {"taskana.ldap.userFirstnameAttribute", "givenName"},
+ {"taskana.ldap.userSearchFilterValue", "person"},
+ {"taskana.ldap.bindDn", "uid=admin,ou=system"},
+ {"taskana.ldap.bindPassword", "secret"},
+ {"taskana.ldap.serverUrl", "ldap://localhost:10389"},
+ })
+ .forEach(
+ strings ->
+ lenient().when(this.environment.getProperty(strings[0])).thenReturn(strings[1]));
+ }
+}