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

oleewere pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 990724c  AMBARI-24662. Log Search: add simple LDAP authentication 
support (#2347)
990724c is described below

commit 990724ccde27574e2c87e852a3d4b6fb95d056bb
Author: Olivér Szabó <[email protected]>
AuthorDate: Wed Sep 19 21:35:43 2018 +0200

    AMBARI-24662. Log Search: add simple LDAP authentication support (#2347)
    
    * AMBARI-24662. Log Search: add simple LDAP authentication support
    
    * AMBARI-24662. Handle referrals.
---
 ambari-logsearch/ambari-logsearch-server/pom.xml   |   7 +-
 .../common/LogSearchLdapAuthorityMapper.java       |  99 ++++++++
 .../ambari/logsearch/conf/AuthPropsConfig.java     |  17 +-
 .../logsearch/conf/LogSearchLdapAuthConfig.java    | 282 +++++++++++++++++++++
 .../ambari/logsearch/conf/SecurityConfig.java      |  72 ++++++
 .../LogsearchAbstractAuthenticationProvider.java   |   2 +-
 .../security/LogsearchAuthenticationProvider.java  |   5 +
 .../LogsearchLdapAuthenticationProvider.java       |  66 +++++
 .../src/main/resources/log4j.xml                   |   1 +
 .../src/main/resources/logsearch.properties        |   8 +-
 .../common/LogSearchLdapAuthorityMapperTest.java   |  95 +++++++
 .../logsearch/logsearch-https.properties           |   8 +-
 .../test-config/logsearch/logsearch-sso.properties |   8 +-
 .../test-config/logsearch/logsearch.properties     |  10 +-
 14 files changed, 659 insertions(+), 21 deletions(-)

diff --git a/ambari-logsearch/ambari-logsearch-server/pom.xml 
b/ambari-logsearch/ambari-logsearch-server/pom.xml
index 46b328e..783fba3 100755
--- a/ambari-logsearch/ambari-logsearch-server/pom.xml
+++ b/ambari-logsearch/ambari-logsearch-server/pom.xml
@@ -29,7 +29,7 @@
   <properties>
     <spring.version>4.3.17.RELEASE</spring.version>
     <spring.security.version>4.2.4.RELEASE</spring.security.version>
-    <spring.ldap.version>2.2.0.RELEASE</spring.ldap.version>
+    <spring.ldap.version>2.3.2.RELEASE</spring.ldap.version>
     <jersey.version>2.25.1</jersey.version>
     <jetty.version>9.4.11.v20180605</jetty.version>
     <swagger.version>1.5.16</swagger.version>
@@ -205,6 +205,11 @@
       <artifactId>spring-security-config</artifactId>
       <version>${spring.security.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.springframework.security</groupId>
+      <artifactId>spring-security-ldap</artifactId>
+      <version>${spring.security.version}</version>
+    </dependency>
 
     <dependency>
       <groupId>org.springframework.security.kerberos</groupId>
diff --git 
a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/common/LogSearchLdapAuthorityMapper.java
 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/common/LogSearchLdapAuthorityMapper.java
new file mode 100644
index 0000000..e5d6d7f
--- /dev/null
+++ 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/common/LogSearchLdapAuthorityMapper.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ambari.logsearch.common;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import 
org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class to map multiple LDAP groups to Log Search authorities. (definied in a 
map)
+ * Examples:
+ * LDAP person -> ROLE_USER
+ * LDAP user -> ROLE_USER
+ * LDAP admin -> ROLE_ADMIN
+ * ROLE_LDAP_ADMIN -> ROLE_ADMIN
+ */
+public class LogSearchLdapAuthorityMapper implements GrantedAuthoritiesMapper {
+
+  private static final String ROLE_PREFIX = "ROLE_";
+
+  private final Map<String, String> groupRoleMap;
+
+  public LogSearchLdapAuthorityMapper(Map<String, String> groupRoleMap) {
+    this.groupRoleMap = groupRoleMap;
+  }
+
+  @Override
+  public Collection<? extends GrantedAuthority> mapAuthorities(Collection<? 
extends GrantedAuthority> authorities) {
+    if (!groupRoleMap.isEmpty() && !authorities.isEmpty()) {
+      List<SimpleGrantedAuthority> newAuthorities = new ArrayList<>();
+      for (GrantedAuthority authority : authorities) {
+        String withoutRoleStringLowercase = 
StringUtils.removeStart(authority.toString(), ROLE_PREFIX).toLowerCase();
+        String withoutRoleStringUppercase = 
StringUtils.removeStart(authority.toString(), ROLE_PREFIX).toUpperCase();
+        String simpleRoleLowercaseString = authority.toString().toLowerCase();
+        String simpleRoleUppercaseString = authority.toString().toUpperCase();
+        if (addAuthoritiy(newAuthorities, withoutRoleStringLowercase))
+          continue;
+        if (addAuthoritiy(newAuthorities, withoutRoleStringUppercase))
+          continue;
+        if (addAuthoritiy(newAuthorities, simpleRoleLowercaseString))
+          continue;
+        addAuthoritiy(newAuthorities, simpleRoleUppercaseString);
+      }
+      return newAuthorities;
+    }
+    return authorities;
+  }
+
+  private boolean addAuthoritiy(List<SimpleGrantedAuthority> newAuthorities, 
String roleKey) {
+    if (groupRoleMap.containsKey(roleKey)) {
+      String role = groupRoleMap.get(roleKey);
+      if (role.contains(ROLE_PREFIX)) {
+        if (!containsAuthority(role.toUpperCase(), newAuthorities)) {
+          newAuthorities.add(new SimpleGrantedAuthority(role.toUpperCase()));
+        }
+      } else {
+        String finalRole = ROLE_PREFIX + role.toUpperCase();
+        if (!containsAuthority(finalRole, newAuthorities)) {
+          newAuthorities.add(new SimpleGrantedAuthority(finalRole));
+        }
+      }
+      return true;
+    }
+    return false;
+  }
+
+  private boolean containsAuthority(String authorityStr, 
List<SimpleGrantedAuthority> authorities) {
+    boolean result = false;
+    for (SimpleGrantedAuthority authority : authorities) {
+      if (authorityStr.equals(authority.toString())) {
+        result = true;
+        break;
+      }
+    }
+    return result;
+  }
+}
diff --git 
a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/conf/AuthPropsConfig.java
 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/conf/AuthPropsConfig.java
index 1b8c578..2b1ce35 100644
--- 
a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/conf/AuthPropsConfig.java
+++ 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/conf/AuthPropsConfig.java
@@ -21,6 +21,8 @@ package org.apache.ambari.logsearch.conf;
 import org.apache.ambari.logsearch.config.api.LogSearchPropertyDescription;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Configuration;
+
+import javax.inject.Inject;
 import java.util.List;
 
 import static 
org.apache.ambari.logsearch.common.LogSearchConstants.LOGSEARCH_PROPERTIES_FILE;
@@ -235,9 +237,9 @@ public class AuthPropsConfig {
   )
   private List<String> proxyIp;
 
-  @Value("${logsearch.authr.file.enable:false}")
+  @Value("${logsearch.authr.file.enabled:false}")
   @LogSearchPropertyDescription(
-    name = "logsearch.authr.file",
+    name = "logsearch.authr.file.enabled",
     description = "A boolean property to enable/disable file based 
authorization",
     examples = {"true"},
     defaultValue = "false",
@@ -255,6 +257,9 @@ public class AuthPropsConfig {
   )
   private String roleFile;
 
+  @Inject
+  private LogSearchLdapAuthConfig ldapAuthConfig;
+
   public boolean isAuthFileEnabled() {
     return authFileEnabled;
   }
@@ -438,4 +443,12 @@ public class AuthPropsConfig {
   public void setRoleFile(String roleFile) {
     this.roleFile = roleFile;
   }
+
+  public LogSearchLdapAuthConfig getLdapAuthConfig() {
+    return ldapAuthConfig;
+  }
+
+  public void setLdapAuthConfig(LogSearchLdapAuthConfig ldapAuthConfig) {
+    this.ldapAuthConfig = ldapAuthConfig;
+  }
 }
diff --git 
a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/conf/LogSearchLdapAuthConfig.java
 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/conf/LogSearchLdapAuthConfig.java
new file mode 100644
index 0000000..6e633b4
--- /dev/null
+++ 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/conf/LogSearchLdapAuthConfig.java
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ambari.logsearch.conf;
+
+import org.apache.ambari.logsearch.config.api.LogSearchPropertyDescription;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Map;
+
+import static 
org.apache.ambari.logsearch.common.LogSearchConstants.LOGSEARCH_PROPERTIES_FILE;
+
+@Configuration
+public class LogSearchLdapAuthConfig {
+  @Value("${logsearch.auth.ldap.url:ldap://localhost:389}";)
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.url",
+    description = "URL of LDAP database.",
+    examples = {"ldap://localhost:389"},
+    defaultValue = "",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private String ldapUrl;
+
+  @Value("${logsearch.auth.ldap.manager.dn:cn=admin,dc=planetexpress,dc=com}")
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.manager.dn",
+    description = "DN of the LDAP manger user (it is a must if LDAP groups are 
used).",
+    examples = {"cn=admin,dc=apache,dc=org"},
+    defaultValue = "",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private String ldapManagerDn;
+
+  @Value("${logsearch.auth.ldap.manager.password:}")
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.manager.password",
+    description = "Password of the LDAP manager user.",
+    examples = {"mypassword"},
+    defaultValue = "",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private String ldapManagerPassword;
+
+  @Value("${logsearch.auth.ldap.base.dn:}")
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.base.dn",
+    description = "Base DN of LDAP database.",
+    examples = {"dc=apache,dc=org"},
+    defaultValue = "",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private String ldapBaseDn;
+
+  @Value("${logsearch.auth.ldap.user.dn.pattern:}")
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.user.dn.pattern",
+    description = "DN pattern that is used during login (dn should contain the 
username), can be used instead of user filter",
+    examples = {"uid={0},ou=people"},
+    defaultValue = "",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private String ldapUserDnPattern;
+
+  @Value("${logsearch.auth.ldap.user.search.base:}")
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.user.search.base",
+    description = "User search base for user search filter",
+    examples = {"ou=people"},
+    defaultValue = "",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private String ldapUserSearchBase;
+
+  @Value("${logsearch.auth.ldap.user.search.filter:}")
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.user.search.filter",
+    description = "Used for get a user based on on LDAP search (username is 
the input), if it is empty, user dn pattern is used.",
+    examples = {"uid={0}"},
+    defaultValue = "",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private String ldapUserSearchFilter;
+
+  @Value("${logsearch.auth.ldap.group.search.base:ou=people}")
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.group.search.base",
+    description = "Group search base - defines where to find LDAP groups. 
Won't do any authority/role mapping if this field is empty.",
+    examples = {"ou=people"},
+    defaultValue = "",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private String ldapGroupSearchBase;
+
+  @Value("${logsearch.auth.ldap.group.search.filter:(member={0})}")
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.group.search.filter",
+    description = "Group search filter which is used to get membership data 
for a specific user",
+    examples = {"(memberUid={0})"},
+    defaultValue = "",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private String ldapGroupSearchFilter;
+
+  @Value("${logsearch.auth.ldap.group.role.attribute:cn}")
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.group.role.attribute",
+    description = "Attribute for identifying LDAP groups (group name)",
+    examples = {"cn"},
+    defaultValue = "cn",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private String ldapGroupRoleAttribute;
+
+  @Value("${logsearch.auth.ldap.role.prefix:ROLE_}")
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.role.prefix",
+    description = "Role prefix that is added for LDAP groups (as authorities)",
+    examples = {"ROLE_"},
+    defaultValue = "ROLE_",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private String ldapRolePrefix;
+
+  @Value("${logsearch.auth.ldap.password.attribute:userPassword}")
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.password.attribute",
+    description = "Password attribute for LDAP authentication",
+    examples = {"password"},
+    defaultValue = "userPassword",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private String ldapPasswordAttribute;
+
+  
@Value("#{propertiesSplitter.parseMap('${logsearch.auth.ldap.group.role.map:ship_crew:ROLE_USER}')}")
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.group.role.map",
+    description = "Map of LDAP groups to Log Search roles",
+    examples = {"ROLE_CUSTOM1:ROLE_USER,ROLE_CUSTOM2:ROLE_ADMIN"},
+    defaultValue = "",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private Map<String, String> ldapGroupRoleMap;
+
+  @Value("${logsearch.auth.ldap.referral.method:ignore}")
+  @LogSearchPropertyDescription(
+    name = "logsearch.auth.ldap.referral.method",
+    description = "Set the method to handle referrals for LDAP",
+    examples = {"follow"},
+    defaultValue = "ignore",
+    sources = {LOGSEARCH_PROPERTIES_FILE}
+  )
+  private String referralMethod;
+
+  public String getLdapUrl() {
+    return ldapUrl;
+  }
+
+  public void setLdapUrl(String ldapUrl) {
+    this.ldapUrl = ldapUrl;
+  }
+
+  public String getLdapBaseDn() {
+    return ldapBaseDn;
+  }
+
+  public void setLdapBaseDn(String ldapBaseDn) {
+    this.ldapBaseDn = ldapBaseDn;
+  }
+
+  public String getLdapUserDnPattern() {
+    return ldapUserDnPattern;
+  }
+
+  public void setLdapUserDnPattern(String ldapUserDnPattern) {
+    this.ldapUserDnPattern = ldapUserDnPattern;
+  }
+
+  public String getLdapUserSearchBase() {
+    return ldapUserSearchBase;
+  }
+
+  public void setLdapUserSearchBase(String ldapUserSearchBase) {
+    this.ldapUserSearchBase = ldapUserSearchBase;
+  }
+
+  public String getLdapUserSearchFilter() {
+    return ldapUserSearchFilter;
+  }
+
+  public void setLdapUserSearchFilter(String ldapUserSearchFilter) {
+    this.ldapUserSearchFilter = ldapUserSearchFilter;
+  }
+
+  public String getLdapGroupSearchBase() {
+    return ldapGroupSearchBase;
+  }
+
+  public void setLdapGroupSearchBase(String ldapGroupSearchBase) {
+    this.ldapGroupSearchBase = ldapGroupSearchBase;
+  }
+
+  public String getLdapGroupSearchFilter() {
+    return ldapGroupSearchFilter;
+  }
+
+  public void setLdapGroupSearchFilter(String ldapGroupSearchFilter) {
+    this.ldapGroupSearchFilter = ldapGroupSearchFilter;
+  }
+
+  public String getLdapGroupRoleAttribute() {
+    return ldapGroupRoleAttribute;
+  }
+
+  public void setLdapGroupRoleAttribute(String ldapGroupRoleAttribute) {
+    this.ldapGroupRoleAttribute = ldapGroupRoleAttribute;
+  }
+
+  public String getLdapRolePrefix() {
+    return ldapRolePrefix;
+  }
+
+  public void setLdapRolePrefix(String ldapRolePrefix) {
+    this.ldapRolePrefix = ldapRolePrefix;
+  }
+
+  public String getLdapPasswordAttribute() {
+    return ldapPasswordAttribute;
+  }
+
+  public void setLdapPasswordAttribute(String ldapPasswordAttribute) {
+    this.ldapPasswordAttribute = ldapPasswordAttribute;
+  }
+
+  public String getLdapManagerDn() {
+    return ldapManagerDn;
+  }
+
+  public void setLdapManagerDn(String ldapManagerDn) {
+    this.ldapManagerDn = ldapManagerDn;
+  }
+
+  public String getLdapManagerPassword() {
+    return ldapManagerPassword;
+  }
+
+  public void setLdapManagerPassword(String ldapManagerPassword) {
+    this.ldapManagerPassword = ldapManagerPassword;
+  }
+
+  public Map<String, String> getLdapGroupRoleMap() {
+    return ldapGroupRoleMap;
+  }
+
+  public void setLdapGroupRoleMap(Map<String, String> ldapGroupRoleMap) {
+    this.ldapGroupRoleMap = ldapGroupRoleMap;
+  }
+
+  public String getReferralMethod() {
+    return referralMethod;
+  }
+
+  public void setReferralMethod(String referralMethod) {
+    this.referralMethod = referralMethod;
+  }
+}
diff --git 
a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/conf/SecurityConfig.java
 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/conf/SecurityConfig.java
index 6f6d912..87dc22f 100644
--- 
a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/conf/SecurityConfig.java
+++ 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/conf/SecurityConfig.java
@@ -27,6 +27,7 @@ import java.util.List;
 import javax.inject.Inject;
 import javax.inject.Named;
 
+import org.apache.ambari.logsearch.common.LogSearchLdapAuthorityMapper;
 import org.apache.ambari.logsearch.common.StatusMessage;
 import org.apache.ambari.logsearch.conf.global.LogLevelFilterManagerState;
 import org.apache.ambari.logsearch.conf.global.LogSearchConfigState;
@@ -46,11 +47,19 @@ import 
org.apache.ambari.logsearch.web.filters.LogsearchSecurityContextFormation
 import org.apache.ambari.logsearch.web.filters.LogsearchTrustedProxyFilter;
 import 
org.apache.ambari.logsearch.web.filters.LogsearchUsernamePasswordAuthenticationFilter;
 import 
org.apache.ambari.logsearch.web.security.LogsearchAuthenticationProvider;
+import 
org.apache.ambari.logsearch.web.security.LogsearchLdapAuthenticationProvider;
+import org.apache.commons.lang.StringUtils;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.ldap.core.support.LdapContextSource;
 import 
org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import 
org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import 
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.ldap.authentication.BindAuthenticator;
+import 
org.springframework.security.ldap.authentication.NullLdapAuthoritiesPopulator;
+import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
+import 
org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
+import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
 import 
org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
 import 
org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
 import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@@ -138,6 +147,69 @@ public class SecurityConfig extends 
WebSecurityConfigurerAdapter {
   }
 
   @Bean
+  public LdapContextSource ldapContextSource() {
+    if (authPropsConfig.isAuthLdapEnabled()) {
+      final LdapContextSource ldapContextSource = new LdapContextSource();
+      
ldapContextSource.setUrl(authPropsConfig.getLdapAuthConfig().getLdapUrl());
+      
ldapContextSource.setBase(authPropsConfig.getLdapAuthConfig().getLdapBaseDn());
+      if 
(StringUtils.isNotBlank(authPropsConfig.getLdapAuthConfig().getLdapManagerDn()))
 {
+        
ldapContextSource.setUserDn(authPropsConfig.getLdapAuthConfig().getLdapManagerDn());
+      }
+      if 
(StringUtils.isNotBlank(authPropsConfig.getLdapAuthConfig().getLdapManagerPassword()))
 {
+        
ldapContextSource.setPassword(authPropsConfig.getLdapAuthConfig().getLdapManagerPassword());
+      }
+      
ldapContextSource.setReferral(authPropsConfig.getLdapAuthConfig().getReferralMethod());
+      ldapContextSource.setAnonymousReadOnly(true);
+      ldapContextSource.afterPropertiesSet();
+      return ldapContextSource;
+    }
+    return null;
+  }
+
+  @Bean
+  public BindAuthenticator bindAuthenticator() {
+    if (authPropsConfig.isAuthLdapEnabled()) {
+      final BindAuthenticator bindAuthenticator = new 
BindAuthenticator(ldapContextSource());
+      if 
(StringUtils.isNotBlank(authPropsConfig.getLdapAuthConfig().getLdapUserDnPattern()))
 {
+        bindAuthenticator.setUserDnPatterns(new 
String[]{authPropsConfig.getLdapAuthConfig().getLdapUserDnPattern()});
+      }
+      if 
(StringUtils.isNotBlank(authPropsConfig.getLdapAuthConfig().getLdapUserSearchFilter()))
 {
+        bindAuthenticator.setUserSearch(new FilterBasedLdapUserSearch(
+          authPropsConfig.getLdapAuthConfig().getLdapUserSearchBase(),
+          authPropsConfig.getLdapAuthConfig().getLdapUserSearchFilter(),
+          ldapContextSource()));
+      }
+
+      return bindAuthenticator;
+    }
+    return null;
+  }
+
+  @Bean
+  public LdapAuthoritiesPopulator ldapAuthoritiesPopulator() {
+    if 
(StringUtils.isNotBlank(authPropsConfig.getLdapAuthConfig().getLdapGroupSearchBase()))
 {
+      final DefaultLdapAuthoritiesPopulator ldapAuthoritiesPopulator =
+        new DefaultLdapAuthoritiesPopulator(ldapContextSource(), 
authPropsConfig.getLdapAuthConfig().getLdapGroupSearchBase());
+      
ldapAuthoritiesPopulator.setGroupSearchFilter(authPropsConfig.getLdapAuthConfig().getLdapGroupSearchFilter());
+      
ldapAuthoritiesPopulator.setGroupRoleAttribute(authPropsConfig.getLdapAuthConfig().getLdapGroupRoleAttribute());
+      ldapAuthoritiesPopulator.setSearchSubtree(true);
+      ldapAuthoritiesPopulator.setConvertToUpperCase(true);
+      return ldapAuthoritiesPopulator;
+    }
+    return new NullLdapAuthoritiesPopulator();
+  }
+
+  @Bean
+  public LogsearchLdapAuthenticationProvider ldapAuthenticationProvider() {
+    if (authPropsConfig.isAuthLdapEnabled()) {
+      LogsearchLdapAuthenticationProvider provider = new 
LogsearchLdapAuthenticationProvider(bindAuthenticator(), 
ldapAuthoritiesPopulator());
+      provider.setAuthoritiesMapper(new 
LogSearchLdapAuthorityMapper(authPropsConfig.getLdapAuthConfig().getLdapGroupRoleMap()));
+      return provider;
+    }
+    return null;
+  }
+
+  @Bean
   public LogsearchCorsFilter logsearchCorsFilter() {
     return new LogsearchCorsFilter(logSearchHttpHeaderConfig);
   }
diff --git 
a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAbstractAuthenticationProvider.java
 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAbstractAuthenticationProvider.java
index 88f8c3b..43854f1 100644
--- 
a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAbstractAuthenticationProvider.java
+++ 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAbstractAuthenticationProvider.java
@@ -29,7 +29,7 @@ import 
org.springframework.security.core.authority.SimpleGrantedAuthority;
 abstract class LogsearchAbstractAuthenticationProvider implements 
AuthenticationProvider {
 
   protected enum AuthMethod {
-    FILE, EXTERNAL_AUTH, SIMPLE
+    FILE, EXTERNAL_AUTH, SIMPLE, LDAP
   };
 
   @Override
diff --git 
a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAuthenticationProvider.java
 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAuthenticationProvider.java
index a993fd3..cfa948d 100644
--- 
a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAuthenticationProvider.java
+++ 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAuthenticationProvider.java
@@ -29,6 +29,7 @@ import org.apache.log4j.Logger;
 import 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
+import 
org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
 import 
org.springframework.security.web.authentication.WebAuthenticationDetails;
 
 @Named
@@ -45,6 +46,9 @@ public class LogsearchAuthenticationProvider extends 
LogsearchAbstractAuthentica
   @Inject
   private LogsearchSimpleAuthenticationProvider simpleAuthenticationProvider;
 
+  @Inject
+  private LogsearchLdapAuthenticationProvider ldapAuthenticationProvider;
+
   @Override
   public Authentication authenticate(Authentication inAuthentication) throws 
AuthenticationException {
     logger.info("Authenticating user:" + inAuthentication.getName() + ", 
userDetail=" + inAuthentication.toString());
@@ -109,6 +113,7 @@ public class LogsearchAuthenticationProvider extends 
LogsearchAbstractAuthentica
   private Authentication doAuth(Authentication authentication, AuthMethod 
authMethod) {
     switch (authMethod) {
       case FILE: return 
fileAuthenticationProvider.authenticate(authentication);
+      case LDAP: return 
ldapAuthenticationProvider.authenticate(authentication);
       case EXTERNAL_AUTH: return 
externalServerAuthenticationProvider.authenticate(authentication);
       case SIMPLE: return 
simpleAuthenticationProvider.authenticate(authentication);
       default: logger.error("Invalid authentication method :" + 
authMethod.name());
diff --git 
a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchLdapAuthenticationProvider.java
 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchLdapAuthenticationProvider.java
new file mode 100644
index 0000000..5cf81db
--- /dev/null
+++ 
b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchLdapAuthenticationProvider.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ambari.logsearch.web.security;
+
+import org.apache.ambari.logsearch.conf.AuthPropsConfig;
+import org.apache.ambari.logsearch.dao.RoleDao;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.GrantedAuthority;
+import 
org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
+import org.springframework.security.ldap.authentication.LdapAuthenticator;
+import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
+
+import javax.inject.Inject;
+import java.util.Collection;
+
+public class LogsearchLdapAuthenticationProvider extends 
LdapAuthenticationProvider {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(LogsearchLdapAuthenticationProvider.class);
+
+  @Inject
+  private AuthPropsConfig authPropsConfig;
+
+  public LogsearchLdapAuthenticationProvider(LdapAuthenticator 
bindAuthenticator, LdapAuthoritiesPopulator ldapAuthoritiesPopulator) {
+    super(bindAuthenticator, ldapAuthoritiesPopulator);
+  }
+
+  @Override
+  public Authentication authenticate(Authentication authentication) throws 
AuthenticationException {
+    if (!authPropsConfig.isAuthLdapEnabled()) {
+      LOG.debug("LDAP auth is disabled.");
+      return authentication;
+    }
+    authentication = super.authenticate(authentication);
+    final Collection<? extends GrantedAuthority> authorities;
+    if 
(StringUtils.isBlank(authPropsConfig.getLdapAuthConfig().getLdapGroupSearchBase()))
 {
+      authorities = RoleDao.createDefaultAuthorities();
+    } else {
+      authorities = authentication.getAuthorities();
+    }
+
+    authentication = new 
UsernamePasswordAuthenticationToken(authentication.getPrincipal(), 
authentication.getCredentials(), authorities);
+    return authentication;
+  }
+
+}
diff --git 
a/ambari-logsearch/ambari-logsearch-server/src/main/resources/log4j.xml 
b/ambari-logsearch/ambari-logsearch-server/src/main/resources/log4j.xml
index 68b697f..40868fa 100644
--- a/ambari-logsearch/ambari-logsearch-server/src/main/resources/log4j.xml
+++ b/ambari-logsearch/ambari-logsearch-server/src/main/resources/log4j.xml
@@ -73,6 +73,7 @@
   </logger>
 
   <logger name="org.apache.ambari.logsearch" additivity="false">
+    <appender-ref ref="console"/>
     <appender-ref ref="rolling_file_json"/>
   </logger>
 
diff --git 
a/ambari-logsearch/ambari-logsearch-server/src/main/resources/logsearch.properties
 
b/ambari-logsearch/ambari-logsearch-server/src/main/resources/logsearch.properties
index 3a0f460..bea6172 100755
--- 
a/ambari-logsearch/ambari-logsearch-server/src/main/resources/logsearch.properties
+++ 
b/ambari-logsearch/ambari-logsearch-server/src/main/resources/logsearch.properties
@@ -27,12 +27,12 @@ 
logsearch.solr.audit.logs.config_set.folder=${LOGSEARCH_SERVER_RELATIVE_LOCATION
 logsearch.solr.collection.history=history
 logsearch.solr.history.config.name=history
 logsearch.collection.history.replication.factor=1
-logsearch.auth.file.enable=true
+logsearch.auth.file.enabled=true
 logsearch.login.credentials.file=user_pass.json
 
-logsearch.auth.ldap.enable=false
-logsearch.auth.simple.enable=false
-logsearch.auth.external_auth.enable=false
+logsearch.auth.ldap.enabled=false
+logsearch.auth.simple.enabled=false
+logsearch.auth.external_auth.enabled=false
 
 logsearch.protocol=http
 logsearch.config.zk_connect_string=localhost:2181
\ No newline at end of file
diff --git 
a/ambari-logsearch/ambari-logsearch-server/src/test/java/org/apache/ambari/logsearch/common/LogSearchLdapAuthorityMapperTest.java
 
b/ambari-logsearch/ambari-logsearch-server/src/test/java/org/apache/ambari/logsearch/common/LogSearchLdapAuthorityMapperTest.java
new file mode 100644
index 0000000..8d7d15a
--- /dev/null
+++ 
b/ambari-logsearch/ambari-logsearch-server/src/test/java/org/apache/ambari/logsearch/common/LogSearchLdapAuthorityMapperTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ambari.logsearch.common;
+
+import org.junit.Test;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class LogSearchLdapAuthorityMapperTest {
+
+  @Test
+  public void testSimpleMapping() {
+    // GIVE
+    Map<String, String> roleGroupMapping = new HashMap<>();
+    roleGroupMapping.put("apache1", "ROLE_USER");
+    LogSearchLdapAuthorityMapper underTest = new 
LogSearchLdapAuthorityMapper(roleGroupMapping);
+    // WHEN
+    List<GrantedAuthority> result = new 
ArrayList<>(underTest.mapAuthorities(generateAuthorities()));
+    // THEN
+    assertEquals("ROLE_USER", result.get(0).toString());
+  }
+
+  @Test
+  public void testSimpleMappingWithoutRolePrefix() {
+    // GIVE
+    Map<String, String> roleGroupMapping = new HashMap<>();
+    roleGroupMapping.put("apache1", "USER");
+    LogSearchLdapAuthorityMapper underTest = new 
LogSearchLdapAuthorityMapper(roleGroupMapping);
+    // WHEN
+    List<GrantedAuthority> result = new 
ArrayList<>(underTest.mapAuthorities(generateAuthorities()));
+    // THEN
+    assertEquals("ROLE_USER", result.get(0).toString());
+  }
+
+  @Test
+  public void testMultipleToTheSameMapping() {
+    // GIVE
+    Map<String, String> roleGroupMapping = new HashMap<>();
+    roleGroupMapping.put("apache1", "ROLE_USER");
+    roleGroupMapping.put("APACHE2", "ROLE_USER");
+    roleGroupMapping.put("role_apache3", "ROLE_USER");
+    roleGroupMapping.put("ROLE_APACHE4", "ROLE_USER");
+    LogSearchLdapAuthorityMapper underTest = new 
LogSearchLdapAuthorityMapper(roleGroupMapping);
+    // WHEN
+    List<GrantedAuthority> result = new 
ArrayList<>(underTest.mapAuthorities(generateAuthorities()));
+    // THEN
+    assertEquals("ROLE_USER", result.get(0).toString());
+    assertEquals(1, result.size());
+  }
+
+  @Test
+  public void testMultipleRoles() {
+    // GIVE
+    Map<String, String> roleGroupMapping = new HashMap<>();
+    roleGroupMapping.put("apache1", "ROLE_USER");
+    roleGroupMapping.put("APACHE2", "ROLE_ADMIN");
+    LogSearchLdapAuthorityMapper underTest = new 
LogSearchLdapAuthorityMapper(roleGroupMapping);
+    // WHEN
+    List<GrantedAuthority> result = new 
ArrayList<>(underTest.mapAuthorities(generateAuthorities()));
+    // THEN
+    assertEquals(2, result.size());
+  }
+
+  private List<SimpleGrantedAuthority> generateAuthorities() {
+    List<SimpleGrantedAuthority> list = new ArrayList<>();
+    list.add(new SimpleGrantedAuthority("apache1"));
+    list.add(new SimpleGrantedAuthority("APACHE2"));
+    list.add(new SimpleGrantedAuthority("role_apache3"));
+    list.add(new SimpleGrantedAuthority("ROLE_APACHE4"));
+    return list;
+  }
+}
diff --git 
a/ambari-logsearch/docker/test-config/logsearch/logsearch-https.properties 
b/ambari-logsearch/docker/test-config/logsearch/logsearch-https.properties
index a50677b..0dc502a 100644
--- a/ambari-logsearch/docker/test-config/logsearch/logsearch-https.properties
+++ b/ambari-logsearch/docker/test-config/logsearch/logsearch-https.properties
@@ -44,12 +44,12 @@ logsearch.solr.metrics.collector.hosts=
 logsearch.solr.jmx.port=18886
 
 # logsearch-admin.json
-logsearch.auth.file.enable=true
+logsearch.auth.file.enabled=true
 logsearch.login.credentials.file=user_pass.json
 
-logsearch.auth.ldap.enable=false
-logsearch.auth.simple.enable=false
-logsearch.auth.external_auth.enable=false
+logsearch.auth.ldap.enabled=false
+logsearch.auth.simple.enabled=false
+logsearch.auth.external_auth.enabled=false
 
 logsearch.https.port=61888
 logsearch.protocol=https
diff --git 
a/ambari-logsearch/docker/test-config/logsearch/logsearch-sso.properties 
b/ambari-logsearch/docker/test-config/logsearch/logsearch-sso.properties
index ad1946e..12243ac 100644
--- a/ambari-logsearch/docker/test-config/logsearch/logsearch-sso.properties
+++ b/ambari-logsearch/docker/test-config/logsearch/logsearch-sso.properties
@@ -44,12 +44,12 @@ logsearch.solr.metrics.collector.hosts=
 logsearch.solr.jmx.port=18886
 
 # logsearch-admin.json
-logsearch.auth.file.enable=true
+logsearch.auth.file.enabled=true
 logsearch.login.credentials.file=user_pass.json
 
-logsearch.auth.ldap.enable=false
-logsearch.auth.simple.enable=false
-logsearch.auth.external_auth.enable=false
+logsearch.auth.ldap.enabled=false
+logsearch.auth.simple.enabled=false
+logsearch.auth.external_auth.enabled=false
 
 logsearch.https.port=61888
 logsearch.protocol=http
diff --git a/ambari-logsearch/docker/test-config/logsearch/logsearch.properties 
b/ambari-logsearch/docker/test-config/logsearch/logsearch.properties
index ff180b1..05da507 100644
--- a/ambari-logsearch/docker/test-config/logsearch/logsearch.properties
+++ b/ambari-logsearch/docker/test-config/logsearch/logsearch.properties
@@ -48,14 +48,14 @@ logsearch.solr.metrics.collector.hosts=
 logsearch.solr.jmx.port=18886
 
 # logsearch-admin.json
-logsearch.auth.file.enable=true
+logsearch.auth.file.enabled=true
 logsearch.login.credentials.file=user_pass.json
 
-logsearch.authr.file.enable=true
+logsearch.authr.file.enabled=true
 
-logsearch.auth.ldap.enable=false
-logsearch.auth.simple.enable=false
-logsearch.auth.external_auth.enable=false
+logsearch.auth.ldap.enabled=false
+logsearch.auth.simple.enabled=false
+logsearch.auth.external_auth.enabled=false
 
 logsearch.protocol=http
 

Reply via email to