From 488f5b3aeb008ec91e39f3a3d485edb55ecaf002 Mon Sep 17 00:00:00 2001 From: Roman Zabaluev Date: Mon, 16 Dec 2024 22:40:28 +0800 Subject: [PATCH 1/6] LDAP security config refactoring --- .../ui/config/auth/LdapSecurityConfig.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java b/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java index 1b5a8ca87..29b063602 100644 --- a/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java +++ b/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java @@ -63,24 +63,32 @@ public ReactiveAuthenticationManager authenticationManager(LdapContextSource lda ba.setUserSearch(userSearch); } + var authenticationProvider = getAuthenticationProvider(authoritiesExtractor, rbacEnabled, ba); + + AuthenticationManager am = new ProviderManager(List.of(authenticationProvider)); + + return new ReactiveAuthenticationManagerAdapter(am); + } + + private AbstractLdapAuthenticationProvider getAuthenticationProvider(LdapAuthoritiesPopulator authoritiesExtractor, + boolean rbacEnabled, + BindAuthenticator bindAuthenticator) { AbstractLdapAuthenticationProvider authenticationProvider; + if (!props.isActiveDirectory()) { authenticationProvider = rbacEnabled - ? new LdapAuthenticationProvider(ba, authoritiesExtractor) - : new LdapAuthenticationProvider(ba); + ? new LdapAuthenticationProvider(bindAuthenticator, authoritiesExtractor) + : new LdapAuthenticationProvider(bindAuthenticator); } else { authenticationProvider = new ActiveDirectoryLdapAuthenticationProvider(props.getActiveDirectoryDomain(), - props.getUrls()); // TODO Issue #3741 + props.getUrls()); authenticationProvider.setUseAuthenticationRequestCredentials(true); } if (rbacEnabled) { authenticationProvider.setUserDetailsContextMapper(new UserDetailsMapper()); } - - AuthenticationManager am = new ProviderManager(List.of(authenticationProvider)); - - return new ReactiveAuthenticationManagerAdapter(am); + return authenticationProvider; } @Bean @@ -99,6 +107,10 @@ public DefaultLdapAuthoritiesPopulator ldapAuthoritiesExtractor(ApplicationConte AccessControlService acs) { var rbacEnabled = acs != null && acs.isRbacEnabled(); + if (props.isActiveDirectory()) { + return null; + } + DefaultLdapAuthoritiesPopulator extractor; if (rbacEnabled) { From 36a62bc8e46a06959c22e99e8b32d2848c1cf6e4 Mon Sep 17 00:00:00 2001 From: Roman Zabaluev Date: Mon, 16 Dec 2024 23:34:40 +0800 Subject: [PATCH 2/6] Support AD in LDAP authorities extractor. Resolves #54 --- .../service/rbac/extractor/RbacLdapAuthoritiesExtractor.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacLdapAuthoritiesExtractor.java b/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacLdapAuthoritiesExtractor.java index 3282ab1e2..4460655ed 100644 --- a/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacLdapAuthoritiesExtractor.java +++ b/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacLdapAuthoritiesExtractor.java @@ -16,6 +16,8 @@ @Slf4j public class RbacLdapAuthoritiesExtractor extends NestedLdapAuthoritiesPopulator { + private static final Set SUPPORTED_PROVIDERS = Set.of(Provider.LDAP, Provider.LDAP_AD); + private final AccessControlService acs; public RbacLdapAuthoritiesExtractor(ApplicationContext context, @@ -36,7 +38,7 @@ protected Set getAdditionalRoles(DirContextOperations user, St .stream() .filter(r -> r.getSubjects() .stream() - .filter(subject -> subject.getProvider().equals(Provider.LDAP)) + .filter(subject -> SUPPORTED_PROVIDERS.contains(subject.getProvider())) .filter(subject -> subject.getType().equals("group")) .anyMatch(subject -> ldapGroups.contains(subject.getValue())) ) From 9d257c9444c58bdc1894f5aaed0e702f111ea323 Mon Sep 17 00:00:00 2001 From: Roman Zabaluev Date: Tue, 17 Dec 2024 22:41:02 +0800 Subject: [PATCH 3/6] Review suggestions --- .../java/io/kafbat/ui/config/auth/LdapSecurityConfig.java | 4 ++-- .../java/io/kafbat/ui/service/AdminClientServiceImpl.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java b/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java index 29b063602..3efa73c7f 100644 --- a/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java +++ b/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java @@ -105,12 +105,12 @@ public LdapContextSource ldapContextSource() { public DefaultLdapAuthoritiesPopulator ldapAuthoritiesExtractor(ApplicationContext context, BaseLdapPathContextSource contextSource, AccessControlService acs) { - var rbacEnabled = acs != null && acs.isRbacEnabled(); - if (props.isActiveDirectory()) { return null; } + var rbacEnabled = acs != null && acs.isRbacEnabled(); + DefaultLdapAuthoritiesPopulator extractor; if (rbacEnabled) { diff --git a/api/src/main/java/io/kafbat/ui/service/AdminClientServiceImpl.java b/api/src/main/java/io/kafbat/ui/service/AdminClientServiceImpl.java index bc175b980..675b85426 100644 --- a/api/src/main/java/io/kafbat/ui/service/AdminClientServiceImpl.java +++ b/api/src/main/java/io/kafbat/ui/service/AdminClientServiceImpl.java @@ -53,7 +53,7 @@ private Mono createAdminClient(KafkaCluster cluster) { return AdminClient.create(properties); }).flatMap(ac -> ReactiveAdminClient.create(ac).doOnError(th -> ac.close())) .onErrorMap(th -> new IllegalStateException( - "Error while creating AdminClient for Cluster " + cluster.getName(), th)); + "Error while creating AdminClient for the cluster " + cluster.getName(), th)); } @Override From 50bae9fb3f635e4bb0554290ab5097dae0339f7a Mon Sep 17 00:00:00 2001 From: Roman Zabaluev Date: Fri, 27 Dec 2024 04:17:58 +0800 Subject: [PATCH 4/6] Impl AD role extractor, refactor configs --- .../ui/config/auth/LdapSecurityConfig.java | 105 +++++++++--------- ...acActiveDirectoryAuthoritiesExtractor.java | 47 ++++++++ .../RbacLdapAuthoritiesExtractor.java | 7 +- 3 files changed, 103 insertions(+), 56 deletions(-) create mode 100644 api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacActiveDirectoryAuthoritiesExtractor.java diff --git a/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java b/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java index 3efa73c7f..64bd4e078 100644 --- a/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java +++ b/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java @@ -1,8 +1,7 @@ package io.kafbat.ui.config.auth; -import static io.kafbat.ui.config.auth.AbstractAuthSecurityConfig.AUTH_WHITELIST; - import io.kafbat.ui.service.rbac.AccessControlService; +import io.kafbat.ui.service.rbac.extractor.RbacActiveDirectoryAuthoritiesExtractor; import io.kafbat.ui.service.rbac.extractor.RbacLdapAuthoritiesExtractor; import java.util.Collection; import java.util.List; @@ -17,7 +16,6 @@ import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.support.BaseLdapPathContextSource; import org.springframework.ldap.core.support.LdapContextSource; -import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.ReactiveAuthenticationManager; import org.springframework.security.authentication.ReactiveAuthenticationManagerAdapter; @@ -29,10 +27,11 @@ import org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider; import org.springframework.security.ldap.authentication.BindAuthenticator; import org.springframework.security.ldap.authentication.LdapAuthenticationProvider; +import org.springframework.security.ldap.authentication.NullLdapAuthoritiesPopulator; import org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider; +import org.springframework.security.ldap.authentication.ad.DefaultActiveDirectoryAuthoritiesPopulator; import org.springframework.security.ldap.search.FilterBasedLdapUserSearch; import org.springframework.security.ldap.search.LdapUserSearch; -import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator; import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator; import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper; import org.springframework.security.web.server.SecurityWebFilterChain; @@ -43,19 +42,47 @@ @EnableConfigurationProperties(LdapProperties.class) @RequiredArgsConstructor @Slf4j -public class LdapSecurityConfig { +public class LdapSecurityConfig extends AbstractAuthSecurityConfig { private final LdapProperties props; @Bean - public ReactiveAuthenticationManager authenticationManager(LdapContextSource ldapContextSource, - LdapAuthoritiesPopulator authoritiesExtractor, - AccessControlService acs) { + public ReactiveAuthenticationManager authenticationManager(AbstractLdapAuthenticationProvider authProvider) { + return new ReactiveAuthenticationManagerAdapter(new ProviderManager(List.of(authProvider))); + } + + @Bean + public AbstractLdapAuthenticationProvider authenticationProvider(LdapAuthoritiesPopulator authoritiesExtractor, + BindAuthenticator bindAuthenticator, + AccessControlService acs) { var rbacEnabled = acs.isRbacEnabled(); + + AbstractLdapAuthenticationProvider authProvider; + + if (!props.isActiveDirectory()) { + authProvider = new LdapAuthenticationProvider(bindAuthenticator, authoritiesExtractor); + } else { + authProvider = new ActiveDirectoryLdapAuthenticationProvider(props.getActiveDirectoryDomain(), + props.getUrls()); + authProvider.setUseAuthenticationRequestCredentials(true); + ((ActiveDirectoryLdapAuthenticationProvider) authProvider).setAuthoritiesPopulator(authoritiesExtractor); + } + + if (rbacEnabled) { + authProvider.setUserDetailsContextMapper(new RbacUserDetailsMapper()); + } + + return authProvider; + } + + @Bean + public BindAuthenticator ldapBindAuthentication(LdapContextSource ldapContextSource) { BindAuthenticator ba = new BindAuthenticator(ldapContextSource); + if (props.getBase() != null) { ba.setUserDnPatterns(new String[] {props.getBase()}); } + if (props.getUserFilterSearchFilter() != null) { LdapUserSearch userSearch = new FilterBasedLdapUserSearch(props.getUserFilterSearchBase(), props.getUserFilterSearchFilter(), @@ -63,32 +90,7 @@ public ReactiveAuthenticationManager authenticationManager(LdapContextSource lda ba.setUserSearch(userSearch); } - var authenticationProvider = getAuthenticationProvider(authoritiesExtractor, rbacEnabled, ba); - - AuthenticationManager am = new ProviderManager(List.of(authenticationProvider)); - - return new ReactiveAuthenticationManagerAdapter(am); - } - - private AbstractLdapAuthenticationProvider getAuthenticationProvider(LdapAuthoritiesPopulator authoritiesExtractor, - boolean rbacEnabled, - BindAuthenticator bindAuthenticator) { - AbstractLdapAuthenticationProvider authenticationProvider; - - if (!props.isActiveDirectory()) { - authenticationProvider = rbacEnabled - ? new LdapAuthenticationProvider(bindAuthenticator, authoritiesExtractor) - : new LdapAuthenticationProvider(bindAuthenticator); - } else { - authenticationProvider = new ActiveDirectoryLdapAuthenticationProvider(props.getActiveDirectoryDomain(), - props.getUrls()); - authenticationProvider.setUseAuthenticationRequestCredentials(true); - } - - if (rbacEnabled) { - authenticationProvider.setUserDetailsContextMapper(new UserDetailsMapper()); - } - return authenticationProvider; + return ba; } @Bean @@ -102,28 +104,27 @@ public LdapContextSource ldapContextSource() { } @Bean - public DefaultLdapAuthoritiesPopulator ldapAuthoritiesExtractor(ApplicationContext context, - BaseLdapPathContextSource contextSource, - AccessControlService acs) { - if (props.isActiveDirectory()) { - return null; - } + public LdapAuthoritiesPopulator authoritiesExtractor(ApplicationContext ctx, + BaseLdapPathContextSource ldapCtx, + AccessControlService acs) { + if (!props.isActiveDirectory()) { + if (!acs.isRbacEnabled()) { + return new NullLdapAuthoritiesPopulator(); + } - var rbacEnabled = acs != null && acs.isRbacEnabled(); + var extractor = new RbacLdapAuthoritiesExtractor(ctx, ldapCtx, props.getGroupFilterSearchBase()); - DefaultLdapAuthoritiesPopulator extractor; + Optional.ofNullable(props.getGroupFilterSearchFilter()).ifPresent(extractor::setGroupSearchFilter); + extractor.setRolePrefix(""); + extractor.setConvertToUpperCase(false); + extractor.setSearchSubtree(true); - if (rbacEnabled) { - extractor = new RbacLdapAuthoritiesExtractor(context, contextSource, props.getGroupFilterSearchBase()); + return extractor; } else { - extractor = new DefaultLdapAuthoritiesPopulator(contextSource, props.getGroupFilterSearchBase()); + return acs.isRbacEnabled() + ? new RbacActiveDirectoryAuthoritiesExtractor(ctx) + : new DefaultActiveDirectoryAuthoritiesPopulator(); } - - Optional.ofNullable(props.getGroupFilterSearchFilter()).ifPresent(extractor::setGroupSearchFilter); - extractor.setRolePrefix(""); - extractor.setConvertToUpperCase(false); - extractor.setSearchSubtree(true); - return extractor; } @Bean @@ -145,7 +146,7 @@ public SecurityWebFilterChain configureLdap(ServerHttpSecurity http) { .build(); } - private static class UserDetailsMapper extends LdapUserDetailsMapper { + private static class RbacUserDetailsMapper extends LdapUserDetailsMapper { @Override public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection authorities) { diff --git a/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacActiveDirectoryAuthoritiesExtractor.java b/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacActiveDirectoryAuthoritiesExtractor.java new file mode 100644 index 000000000..582a8b5fb --- /dev/null +++ b/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacActiveDirectoryAuthoritiesExtractor.java @@ -0,0 +1,47 @@ +package io.kafbat.ui.service.rbac.extractor; + +import io.kafbat.ui.model.rbac.Role; +import io.kafbat.ui.model.rbac.provider.Provider; +import io.kafbat.ui.service.rbac.AccessControlService; +import java.util.Collection; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.ldap.core.DirContextOperations; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.ldap.authentication.ad.DefaultActiveDirectoryAuthoritiesPopulator; +import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator; + +@Slf4j +public class RbacActiveDirectoryAuthoritiesExtractor implements LdapAuthoritiesPopulator { + + private final DefaultActiveDirectoryAuthoritiesPopulator populator = new DefaultActiveDirectoryAuthoritiesPopulator(); + private final AccessControlService acs; + + public RbacActiveDirectoryAuthoritiesExtractor(ApplicationContext context) { + this.acs = context.getBean(AccessControlService.class); + } + + @Override + public Collection getGrantedAuthorities(DirContextOperations userData, String username) { + var adGroups = populator.getGrantedAuthorities(userData, username) + .stream() + .map(GrantedAuthority::getAuthority) + .peek(group -> log.trace("Found AD group [{}] for user [{}]", group, username)) + .collect(Collectors.toSet()); + + return acs.getRoles() + .stream() + .filter(r -> r.getSubjects() + .stream() + .filter(subject -> subject.getProvider().equals(Provider.LDAP_AD)) + .filter(subject -> subject.getType().equals("group")) + .anyMatch(subject -> adGroups.contains(subject.getValue())) + ) + .map(Role::getName) + .peek(role -> log.trace("Mapped role [{}] for user [{}]", role, username)) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toSet()); + } +} diff --git a/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacLdapAuthoritiesExtractor.java b/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacLdapAuthoritiesExtractor.java index 4460655ed..ef47dcb01 100644 --- a/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacLdapAuthoritiesExtractor.java +++ b/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacLdapAuthoritiesExtractor.java @@ -16,12 +16,11 @@ @Slf4j public class RbacLdapAuthoritiesExtractor extends NestedLdapAuthoritiesPopulator { - private static final Set SUPPORTED_PROVIDERS = Set.of(Provider.LDAP, Provider.LDAP_AD); - private final AccessControlService acs; public RbacLdapAuthoritiesExtractor(ApplicationContext context, - BaseLdapPathContextSource contextSource, String groupFilterSearchBase) { + BaseLdapPathContextSource contextSource, + String groupFilterSearchBase) { super(contextSource, groupFilterSearchBase); this.acs = context.getBean(AccessControlService.class); } @@ -38,7 +37,7 @@ protected Set getAdditionalRoles(DirContextOperations user, St .stream() .filter(r -> r.getSubjects() .stream() - .filter(subject -> SUPPORTED_PROVIDERS.contains(subject.getProvider())) + .filter(subject -> subject.getProvider().equals(Provider.LDAP)) .filter(subject -> subject.getType().equals("group")) .anyMatch(subject -> ldapGroups.contains(subject.getValue())) ) From ad1c65e4ad918862d5d8e820b84cd6d818e81cd4 Mon Sep 17 00:00:00 2001 From: Roman Zabaluev Date: Mon, 30 Dec 2024 18:06:20 +0800 Subject: [PATCH 5/6] BE: RBAC: LDAP: Implement `user` subject type for LDAP & AD. Fixes #730 --- .../extractor/RbacActiveDirectoryAuthoritiesExtractor.java | 7 +++++-- .../rbac/extractor/RbacLdapAuthoritiesExtractor.java | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacActiveDirectoryAuthoritiesExtractor.java b/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacActiveDirectoryAuthoritiesExtractor.java index 582a8b5fb..cefef5a7e 100644 --- a/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacActiveDirectoryAuthoritiesExtractor.java +++ b/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacActiveDirectoryAuthoritiesExtractor.java @@ -36,8 +36,11 @@ public Collection getGrantedAuthorities(DirContextOp .filter(r -> r.getSubjects() .stream() .filter(subject -> subject.getProvider().equals(Provider.LDAP_AD)) - .filter(subject -> subject.getType().equals("group")) - .anyMatch(subject -> adGroups.contains(subject.getValue())) + .anyMatch(subject -> switch (subject.getType()) { + case "user" -> username.equalsIgnoreCase(subject.getValue()); + case "group" -> adGroups.contains(subject.getValue()); + default -> false; + }) ) .map(Role::getName) .peek(role -> log.trace("Mapped role [{}] for user [{}]", role, username)) diff --git a/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacLdapAuthoritiesExtractor.java b/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacLdapAuthoritiesExtractor.java index ef47dcb01..261b30cfe 100644 --- a/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacLdapAuthoritiesExtractor.java +++ b/api/src/main/java/io/kafbat/ui/service/rbac/extractor/RbacLdapAuthoritiesExtractor.java @@ -38,8 +38,11 @@ protected Set getAdditionalRoles(DirContextOperations user, St .filter(r -> r.getSubjects() .stream() .filter(subject -> subject.getProvider().equals(Provider.LDAP)) - .filter(subject -> subject.getType().equals("group")) - .anyMatch(subject -> ldapGroups.contains(subject.getValue())) + .anyMatch(subject -> switch (subject.getType()) { + case "user" -> username.equalsIgnoreCase(subject.getValue()); + case "group" -> ldapGroups.contains(subject.getValue()); + default -> false; + }) ) .map(Role::getName) .peek(role -> log.trace("Mapped role [{}] for user [{}]", role, username)) From 514c0531a2573827bc8016c476e3c7062db299d5 Mon Sep 17 00:00:00 2001 From: Roman Zabaluev Date: Mon, 30 Dec 2024 22:15:56 +0800 Subject: [PATCH 6/6] Review fixes: Make bind authenticator nullable for the AD case --- .../java/io/kafbat/ui/config/auth/LdapSecurityConfig.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java b/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java index 64bd4e078..90ffa17fe 100644 --- a/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java +++ b/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java @@ -8,6 +8,7 @@ import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; @@ -53,14 +54,14 @@ public ReactiveAuthenticationManager authenticationManager(AbstractLdapAuthentic @Bean public AbstractLdapAuthenticationProvider authenticationProvider(LdapAuthoritiesPopulator authoritiesExtractor, - BindAuthenticator bindAuthenticator, + @Autowired(required = false) BindAuthenticator ba, AccessControlService acs) { var rbacEnabled = acs.isRbacEnabled(); AbstractLdapAuthenticationProvider authProvider; if (!props.isActiveDirectory()) { - authProvider = new LdapAuthenticationProvider(bindAuthenticator, authoritiesExtractor); + authProvider = new LdapAuthenticationProvider(ba, authoritiesExtractor); } else { authProvider = new ActiveDirectoryLdapAuthenticationProvider(props.getActiveDirectoryDomain(), props.getUrls()); @@ -76,6 +77,7 @@ public AbstractLdapAuthenticationProvider authenticationProvider(LdapAuthorities } @Bean + @ConditionalOnProperty(value = "oauth2.ldap.activeDirectory", havingValue = "false") public BindAuthenticator ldapBindAuthentication(LdapContextSource ldapContextSource) { BindAuthenticator ba = new BindAuthenticator(ldapContextSource);