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