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();
