AMBARI-18813. Optionally force username from LDAP authentication data to be 
lowercase in Ambari (rlevas)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/3bf40d0d
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/3bf40d0d
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/3bf40d0d

Branch: refs/heads/branch-feature-AMBARI-18634
Commit: 3bf40d0d4693ece985cbe050c3027e9272998c7c
Parents: 99f6956
Author: Robert Levas <[email protected]>
Authored: Wed Nov 9 15:00:16 2016 -0500
Committer: Robert Levas <[email protected]>
Committed: Wed Nov 9 15:00:16 2016 -0500

----------------------------------------------------------------------
 ambari-server/docs/configuration/index.md       |  1 +
 .../server/configuration/Configuration.java     | 10 ++++++++
 .../AmbariLdapBindAuthenticator.java            | 15 +++++++++--
 .../authorization/LdapServerProperties.java     | 26 ++++++++++++++++++++
 .../AmbariLdapBindAuthenticatorTest.java        | 17 +++++++++++--
 5 files changed, 65 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/3bf40d0d/ambari-server/docs/configuration/index.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/configuration/index.md 
b/ambari-server/docs/configuration/index.md
index ae6019c..9d793ff 100644
--- a/ambari-server/docs/configuration/index.md
+++ b/ambari-server/docs/configuration/index.md
@@ -99,6 +99,7 @@ The following are the properties which can be used to 
configure Ambari.
 | authentication.ldap.userBase | The filter used when searching for users in 
LDAP. |`ou=people,dc=ambari,dc=apache,dc=org` | 
 | authentication.ldap.userObjectClass | The class to which user objects in 
LDAP belong. |`person` | 
 | authentication.ldap.userSearchFilter | A filter used to lookup a user in 
LDAP based on the Ambari user name<br/><br/>The following are examples of valid 
values:<ul><li>`(&({usernameAttribute}={0})(objectClass={userObjectClass}))`</ul>
 |`(&({usernameAttribute}={0})(objectClass={userObjectClass}))` | 
+| authentication.ldap.username.forceLowercase | Declares whether to force the 
ldap user name to be lowercase or leave as-is. This is useful when local user 
names are expected to be lowercase but the LDAP user names are not. |`false` | 
 | authentication.ldap.usernameAttribute | The attribute used for determining 
the user name, such as `uid`. |`uid` | 
 | authorization.ldap.adminGroupMappingRules | A comma-separate list of groups 
which would give a user administrative access to Ambari when syncing from LDAP. 
This is only used when `authorization.ldap.groupSearchFilter` is 
blank.<br/><br/>The following are examples of valid 
values:<ul><li>`administrators`<li>`Hadoop Admins,Hadoop Admins.*,DC 
Admins,.*Hadoop Operators`</ul> |`Ambari Administrators` | 
 | authorization.ldap.groupSearchFilter | The DN to use when searching for LDAP 
groups. | | 

http://git-wip-us.apache.org/repos/asf/ambari/blob/3bf40d0d/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index f9557a5..83e8dac 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -965,6 +965,15 @@ public class Configuration {
       "authentication.ldap.usernameAttribute", "uid");
 
   /**
+   * Declares whether to force the ldap user name to be lowercase or leave 
as-is. This is useful when
+   * local user names are expected to be lowercase but the LDAP user names are 
not.
+   */
+  @Markdown(description = "Declares whether to force the ldap user name to be 
lowercase or leave as-is." +
+      " This is useful when local user names are expected to be lowercase but 
the LDAP user names are not.")
+  public static final ConfigurationProperty<String> 
LDAP_USERNAME_FORCE_LOWERCASE = new ConfigurationProperty<>(
+      "authentication.ldap.username.forceLowercase", "false");
+
+  /**
    * The filter used when searching for users in LDAP.
    */
   @Markdown(description = "The filter used when searching for users in LDAP.")
@@ -3742,6 +3751,7 @@ public class Configuration {
 
     ldapServerProperties.setBaseDN(getProperty(LDAP_BASE_DN));
     
ldapServerProperties.setUsernameAttribute(getProperty(LDAP_USERNAME_ATTRIBUTE));
+    
ldapServerProperties.setForceUsernameToLowercase(Boolean.parseBoolean(getProperty(LDAP_USERNAME_FORCE_LOWERCASE)));
     ldapServerProperties.setUserBase(getProperty(LDAP_USER_BASE));
     
ldapServerProperties.setUserObjectClass(getProperty(LDAP_USER_OBJECT_CLASS));
     ldapServerProperties.setDnAttribute(getProperty(LDAP_DN_ATTRIBUTE));

http://git-wip-us.apache.org/repos/asf/ambari/blob/3bf40d0d/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapBindAuthenticator.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapBindAuthenticator.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapBindAuthenticator.java
index 917471b..b34ef6a 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapBindAuthenticator.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapBindAuthenticator.java
@@ -71,9 +71,20 @@ public class AmbariLdapBindAuthenticator extends 
BindAuthenticator {
       // if authenticated user name is different from ldap user name than user 
has logged in
       // with a login name that is different (e.g. user principal name) from 
the ambari user name stored in
       // ambari db. In this case add the user login name  as login alias for 
ambari user name.
-      LOG.info("User with {}='{}' logged in with login alias '{}'", 
ldapUserName, loginName);
+      LOG.info("User with {}='{}' logged in with login alias '{}'", 
ldapServerProperties.getUsernameAttribute(), ldapUserName, loginName);
+
+      // If the ldap username needs to be processed (like converted to all 
lowercase characters),
+      // process it before setting it in the session via 
AuthorizationHelper#addLoginNameAlias
+      String processedLdapUserName;
+      if(ldapServerProperties.isForceUsernameToLowercase()) {
+        processedLdapUserName = ldapUserName.toLowerCase();
+        LOG.info("Forcing ldap username to be lowercase characters: {} ==> 
{}", ldapUserName, processedLdapUserName);
+      }
+      else {
+        processedLdapUserName = ldapUserName;
+      }
 
-      AuthorizationHelper.addLoginNameAlias(ldapUserName, loginName);
+      AuthorizationHelper.addLoginNameAlias(processedLdapUserName, loginName);
     }
 
     return user;

http://git-wip-us.apache.org/repos/asf/ambari/blob/3bf40d0d/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/LdapServerProperties.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/LdapServerProperties.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/LdapServerProperties.java
index a3086693..e76e944 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/LdapServerProperties.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/LdapServerProperties.java
@@ -50,6 +50,7 @@ public class LdapServerProperties {
   private String userBase;
   private String userObjectClass;
   private String usernameAttribute;
+  private boolean forceUsernameToLowercase = false;
   private String userSearchBase = "";
 
   private String syncGroupMemberReplacePattern = "";
@@ -165,6 +166,28 @@ public class LdapServerProperties {
     this.usernameAttribute = usernameAttribute;
   }
 
+  /**
+   * Sets whether the username retrieved from the LDAP server during 
authentication is to be forced
+   * to all lowercase characters before assigning to the authenticated user.
+   *
+   * @param forceUsernameToLowercase true to force the username to be 
lowercase; false to leave as
+   *                                 it was when retrieved from the LDAP server
+   */
+  public void setForceUsernameToLowercase(boolean forceUsernameToLowercase) {
+    this.forceUsernameToLowercase = forceUsernameToLowercase;
+  }
+
+  /**
+   * Gets whether the username retrieved from the LDAP server during 
authentication is to be forced
+   * to all lowercase characters before assigning to the authenticated user.
+   *
+   * @return true to force the username to be lowercase; false to leave as it 
was when retrieved from
+   * the LDAP server
+   */
+  public boolean isForceUsernameToLowercase() {
+    return forceUsernameToLowercase;
+  }
+
   public String getGroupBase() {
     return groupBase;
   }
@@ -331,6 +354,8 @@ public class LdapServerProperties {
       return false;
     if (usernameAttribute != null ? 
!usernameAttribute.equals(that.usernameAttribute) : that.usernameAttribute != 
null)
       return false;
+    if (forceUsernameToLowercase != that.forceUsernameToLowercase)
+      return false;
     if (groupBase != null ? !groupBase.equals(that.groupBase) :
         that.groupBase != null) return false;
     if (groupObjectClass != null ? 
!groupObjectClass.equals(that.groupObjectClass) :
@@ -379,6 +404,7 @@ public class LdapServerProperties {
     result = 31 * result + (userBase != null ? userBase.hashCode() : 0);
     result = 31 * result + (userObjectClass != null ? 
userObjectClass.hashCode() : 0);
     result = 31 * result + (usernameAttribute != null ? 
usernameAttribute.hashCode() : 0);
+    result = 31 * result + (forceUsernameToLowercase ? 1 : 0);
     result = 31 * result + (groupBase != null ? groupBase.hashCode() : 0);
     result = 31 * result + (groupObjectClass != null ? 
groupObjectClass.hashCode() : 0);
     result = 31 * result + (groupMembershipAttr != null ? 
groupMembershipAttr.hashCode() : 0);

http://git-wip-us.apache.org/repos/asf/ambari/blob/3bf40d0d/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapBindAuthenticatorTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapBindAuthenticatorTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapBindAuthenticatorTest.java
index 6e4b836..cea4b66 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapBindAuthenticatorTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapBindAuthenticatorTest.java
@@ -84,7 +84,16 @@ public class AmbariLdapBindAuthenticatorTest extends 
AmbariLdapAuthenticationPro
   }
 
   @Test
-  public void testAuthenticateWithLoginAlias() throws Exception {
+  public void testAuthenticateWithLoginAliasDefault() throws Exception {
+    testAuthenticateWithLoginAlias(false);
+  }
+
+  @Test
+  public void testAuthenticateWithLoginAliasForceToLower() throws Exception {
+    testAuthenticateWithLoginAlias(true);
+  }
+
+  private void testAuthenticateWithLoginAlias(boolean forceUsernameToLower) 
throws Exception {
     // Given
 
     LdapContextSource ldapCtxSource = new LdapContextSource();
@@ -101,6 +110,10 @@ public class AmbariLdapBindAuthenticatorTest extends 
AmbariLdapAuthenticationPro
     properties.setProperty(Configuration.SHARED_RESOURCES_DIR.getKey(), 
"src/test/resources/");
     properties.setProperty(Configuration.LDAP_BASE_DN.getKey(), 
"dc=ambari,dc=apache,dc=org");
 
+    if(forceUsernameToLower) {
+      
properties.setProperty(Configuration.LDAP_USERNAME_FORCE_LOWERCASE.getKey(), 
"true");
+    }
+
     Configuration configuration = new Configuration(properties);
 
     AmbariLdapBindAuthenticator bindAuthenticator = new 
AmbariLdapBindAuthenticator(ldapCtxSource, configuration);
@@ -116,7 +129,7 @@ public class AmbariLdapBindAuthenticatorTest extends 
AmbariLdapAuthenticationPro
 
     RequestContextHolder.setRequestAttributes(servletRequestAttributes);
 
-    servletRequestAttributes.setAttribute(eq(loginAlias), eq(userName), 
eq(RequestAttributes.SCOPE_SESSION));
+    servletRequestAttributes.setAttribute(eq(loginAlias), 
eq(forceUsernameToLower ? userName.toLowerCase(): userName), 
eq(RequestAttributes.SCOPE_SESSION));
     expectLastCall().once();
 
     replayAll();

Reply via email to