This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git


The following commit(s) were added to refs/heads/master by this push:
     new 00c51c98ae [FIX] Enable dynamic translation of LDAP entries (#1932)
00c51c98ae is described below

commit 00c51c98ae002bce3cb346c2163ebe429f74db95
Author: Benoit TELLIER <[email protected]>
AuthorDate: Mon Jan 22 16:40:28 2024 +0100

    [FIX] Enable dynamic translation of LDAP entries (#1932)
---
 .../user/ldap/LdapRepositoryConfiguration.java     | 25 ++++++++++++++++++----
 .../james/user/ldap/ReadOnlyLDAPUsersDAO.java      | 25 +++++++++++++++-------
 2 files changed, 38 insertions(+), 12 deletions(-)

diff --git 
a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/LdapRepositoryConfiguration.java
 
b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/LdapRepositoryConfiguration.java
index 4548d5d01d..33ba7aaa92 100644
--- 
a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/LdapRepositoryConfiguration.java
+++ 
b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/LdapRepositoryConfiguration.java
@@ -58,6 +58,7 @@ public class LdapRepositoryConfiguration {
         private Optional<String> userIdAttribute;
         private Optional<String> resolveLocalPartAttribute;
         private Optional<String> userObjectClass;
+        private Optional<String> usernameAttribute;
         private Optional<Integer> poolSize;
         private Optional<Boolean> trustAllCerts;
         private ImmutableMap.Builder<Domain, String> perDomainBaseDN;
@@ -71,6 +72,7 @@ public class LdapRepositoryConfiguration {
             userIdAttribute = Optional.empty();
             resolveLocalPartAttribute = Optional.empty();
             userObjectClass = Optional.empty();
+            usernameAttribute = Optional.empty();
             poolSize = Optional.empty();
             trustAllCerts = Optional.empty();
             perDomainBaseDN = ImmutableMap.builder();
@@ -147,6 +149,7 @@ public class LdapRepositoryConfiguration {
                 userListBase.orElse(userBase.get()),
                 userIdAttribute.get(),
                 resolveLocalPartAttribute,
+                usernameAttribute,
                 userObjectClass.get(),
                 NO_CONNECTION_TIMEOUT,
                 NO_READ_TIME_OUT,
@@ -180,6 +183,7 @@ public class LdapRepositoryConfiguration {
             .orElse(userBase);
         String userIdAttribute = configuration.getString("[@userIdAttribute]");
         Optional<String> resolveLocalPartAttribute = 
Optional.ofNullable(configuration.getString("[@resolveLocalPartAttribute]", 
null));
+        Optional<String> usernameAttribute = 
Optional.ofNullable(configuration.getString("[@usernameAttribute]", null));
         String userObjectClass = configuration.getString("[@userObjectClass]");
         // Default is to use connection pooling
         int connectionTimeout = configuration.getInt("[@connectionTimeout]", 
NO_CONNECTION_TIMEOUT);
@@ -223,6 +227,7 @@ public class LdapRepositoryConfiguration {
             userBase,
             userListBase, userIdAttribute,
             resolveLocalPartAttribute,
+            usernameAttribute,
             userObjectClass,
             connectionTimeout,
             readTimeout,
@@ -282,10 +287,16 @@ public class LdapRepositoryConfiguration {
     /**
      * The value of this field is taken from the configuration attribute
      * &quot;userIdAttribute&quot;. This is the LDAP attribute type which holds
-     * the userId value. Note that this is not the same as the email address
-     * attribute.
+     * the userId value. This value is used to identify the LDAP entry used 
for authentication,
+     * and by default is used to retrieve the associated username.
      */
     private final String userIdAttribute;
+    /**
+     * The value of this field is taken from the configuration attribute
+     * &quot;userIdAttribute&quot;. This is the LDAP attribute is used to, 
given a LDAP entry,
+     * retrieve the associated username. Defaults to 'userIdAttribute' value.
+     */
+    private final Optional<String> usernameAttribute;
 
     /**
      * The value of this field is taken from the configuration attribute
@@ -337,7 +348,7 @@ public class LdapRepositoryConfiguration {
     private final ImmutableMap<Domain, String> perDomainBaseDN;
 
     private LdapRepositoryConfiguration(List<URI> ldapHosts, String principal, 
String credentials, String userBase, String userListBase, String 
userIdAttribute,
-                                        Optional<String> 
resolveLocalPartAttribute, String userObjectClass, int connectionTimeout, int 
readTimeout,
+                                        Optional<String> 
resolveLocalPartAttribute, Optional<String> usernameAttribute, String 
userObjectClass, int connectionTimeout, int readTimeout,
                                         boolean supportsVirtualHosting, int 
poolSize, ReadOnlyLDAPGroupRestriction restriction, String filter,
                                         Optional<String> administratorId, 
boolean trustAllCerts,
                                         ImmutableMap<Domain, String> 
perDomainBaseDN) throws ConfigurationException {
@@ -348,6 +359,7 @@ public class LdapRepositoryConfiguration {
         this.userListBase = userListBase;
         this.userIdAttribute = userIdAttribute;
         this.resolveLocalPartAttribute = resolveLocalPartAttribute;
+        this.usernameAttribute = usernameAttribute;
         this.userObjectClass = userObjectClass;
         this.connectionTimeout = connectionTimeout;
         this.readTimeout = readTimeout;
@@ -402,6 +414,10 @@ public class LdapRepositoryConfiguration {
         return resolveLocalPartAttribute;
     }
 
+    public Optional<String> getUsernameAttribute() {
+        return usernameAttribute;
+    }
+
     public String getUserObjectClass() {
         return userObjectClass;
     }
@@ -463,6 +479,7 @@ public class LdapRepositoryConfiguration {
                 && Objects.equals(this.poolSize, that.poolSize)
                 && Objects.equals(this.administratorId, that.administratorId)
                 && Objects.equals(this.trustAllCerts, that.trustAllCerts)
+                && Objects.equals(this.usernameAttribute, 
that.usernameAttribute)
                 && Objects.equals(this.perDomainBaseDN, that.perDomainBaseDN);
         }
         return false;
@@ -472,6 +489,6 @@ public class LdapRepositoryConfiguration {
     public final int hashCode() {
         return Objects.hash(ldapHosts, principal, credentials, userBase, 
userListBase, userIdAttribute, resolveLocalPartAttribute, userObjectClass,
             connectionTimeout, readTimeout, supportsVirtualHosting, 
restriction, filter, administratorId, poolSize,
-            trustAllCerts, perDomainBaseDN);
+            trustAllCerts, perDomainBaseDN, usernameAttribute);
     }
 }
diff --git 
a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyLDAPUsersDAO.java
 
b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyLDAPUsersDAO.java
index f75ca91056..f6ece9d141 100644
--- 
a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyLDAPUsersDAO.java
+++ 
b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyLDAPUsersDAO.java
@@ -131,7 +131,6 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, 
Configurable {
      *             specified LDAP host.
      */
     public void init() throws Exception {
-
         if (LOGGER.isDebugEnabled()) {
             LOGGER.debug(this.getClass().getName() + ".init()" + '\n' + "LDAP 
hosts: " + ldapConfiguration.getLdapHosts()
                 + '\n' + "User baseDN: " + ldapConfiguration.getUserBase() + 
'\n' + "userIdAttribute: "
@@ -236,7 +235,7 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, 
Configurable {
         return 
username.getDomainPart().map(this::userBase).orElse(ldapConfiguration.getUserBase());
     }
 
-    private Set<DN> getAllUsersDNFromLDAP() throws LDAPException {
+    private Set<DN> getAllUsersDNFromLDAP() {
         return allDNs()
             .flatMap(Throwing.<String, 
Stream<SearchResultEntry>>function(this::entriesFromDN).sneakyThrow())
             .map(Throwing.function(Entry::getParsedDN))
@@ -265,9 +264,10 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, 
Configurable {
     }
 
     private Stream<Username> getAllUsernamesFromLDAP() throws LDAPException {
+        String usernameAttribute = 
ldapConfiguration.getUsernameAttribute().orElse(ldapConfiguration.getUserIdAttribute());
         return allDNs()
-            .flatMap(Throwing.<String, Stream<SearchResultEntry>>function(s -> 
entriesFromDN(s, ldapConfiguration.getUserIdAttribute())).sneakyThrow())
-            .flatMap(entry -> 
Optional.ofNullable(entry.getAttribute(ldapConfiguration.getUserIdAttribute())).stream())
+            .flatMap(Throwing.<String, Stream<SearchResultEntry>>function(s -> 
entriesFromDN(s, usernameAttribute)).sneakyThrow())
+            .flatMap(entry -> 
Optional.ofNullable(entry.getAttribute(usernameAttribute)).stream())
             .map(Attribute::getValue)
             .map(Username::of)
             .distinct();
@@ -300,12 +300,11 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, 
Configurable {
 
     private Optional<ReadOnlyLDAPUser> searchAndBuildUser(Username 
retrievalName) throws LDAPException {
         Optional<String> resolveLocalPartAttribute = 
ldapConfiguration.getResolveLocalPartAttribute();
-        String[] returnedAttributes = { ldapConfiguration.getUserIdAttribute() 
};
 
         SearchResult searchResult = 
ldapConnectionPool.search(userBase(retrievalName),
             SearchScope.SUB,
             createFilter(retrievalName.asString(), 
evaluateLdapUserRetrievalAttribute(retrievalName, resolveLocalPartAttribute)),
-            returnedAttributes);
+            getReturnedAttributes());
 
         SearchResultEntry result = searchResult.getSearchEntries()
             .stream()
@@ -319,12 +318,21 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, 
Configurable {
         if (!ldapConfiguration.getRestriction().isActivated()
             || userInGroupsMembershipList(result.getParsedDN(), 
ldapConfiguration.getRestriction().getGroupMembershipLists(ldapConnectionPool)))
 {
 
-            Username translatedUsername = 
Username.of(result.getAttributeValue(ldapConfiguration.getUserIdAttribute()));
+            String usernameAttribute = 
ldapConfiguration.getUsernameAttribute().orElse(ldapConfiguration.getUserIdAttribute());
+            Username translatedUsername = 
Username.of(result.getAttributeValue(usernameAttribute));
             return Optional.of(new ReadOnlyLDAPUser(translatedUsername, 
result.getParsedDN(), ldapConnectionPool));
         }
         return Optional.empty();
     }
 
+    private String[] getReturnedAttributes() {
+        if (ldapConfiguration.getUsernameAttribute().isPresent()) {
+            return new String[]{ldapConfiguration.getUserIdAttribute(), 
ldapConfiguration.getUsernameAttribute().get()};
+        } else {
+            return new String[]{ldapConfiguration.getUserIdAttribute()};
+        }
+    }
+
     private String evaluateLdapUserRetrievalAttribute(Username retrievalName, 
Optional<String> resolveLocalPartAttribute) {
         if (retrievalName.asString().contains("@")) {
             return ldapConfiguration.getUserIdAttribute();
@@ -335,7 +343,8 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, 
Configurable {
 
     private Optional<ReadOnlyLDAPUser> buildUser(DN userDN) throws 
LDAPException {
         SearchResultEntry userAttributes = 
ldapConnectionPool.getEntry(userDN.toString());
-        Optional<String> userName = 
Optional.ofNullable(userAttributes.getAttributeValue(ldapConfiguration.getUserIdAttribute()));
+        String usernameAttribute = 
ldapConfiguration.getUsernameAttribute().orElse(ldapConfiguration.getUserIdAttribute());
+        Optional<String> userName = 
Optional.ofNullable(userAttributes.getAttributeValue(usernameAttribute));
         return userName
             .map(Username::of)
             .map(username -> new ReadOnlyLDAPUser(username, userDN, 
ldapConnectionPool));


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to