Roman Zabaluev 2 gadi atpakaļ
vecāks
revīzija
c58a7c03ba

+ 24 - 0
kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/auth/LdapProperties.java

@@ -0,0 +1,24 @@
+package com.provectus.kafka.ui.config.auth;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties("spring.ldap")
+@Data
+public class LdapProperties {
+
+  private String urls;
+  private String dnPattern;
+  private String adminUser;
+  private String adminPassword;
+  private String userFilterSearchBase;
+  private String userFilterSearchFilter;
+  private String groupSearchBase;
+
+  @Value("${oauth2.ldap.activeDirectory}")
+  private boolean isActiveDirectory;
+  @Value("${oauth2.ldap.aсtiveDirectory.domain}")
+  private String activeDirectoryDomain;
+
+}

+ 50 - 95
kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/auth/LdapSecurityConfig.java

@@ -1,106 +1,82 @@
 package com.provectus.kafka.ui.config.auth;
 
+import static com.provectus.kafka.ui.config.auth.AbstractAuthSecurityConfig.AUTH_WHITELIST;
+
+import com.provectus.kafka.ui.service.rbac.AccessControlService;
 import com.provectus.kafka.ui.service.rbac.extractor.RbacLdapAuthoritiesExtractor;
 import java.util.Collection;
-import java.util.List;
+import javax.annotation.Nullable;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
-import org.springframework.context.annotation.Primary;
 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;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
 import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
 import org.springframework.security.config.web.server.ServerHttpSecurity;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.userdetails.UserDetails;
-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.ad.ActiveDirectoryLdapAuthenticationProvider;
-import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
-import org.springframework.security.ldap.search.LdapUserSearch;
-import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
 import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
-import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
 import org.springframework.security.web.server.SecurityWebFilterChain;
 
 @Configuration
 @EnableWebFluxSecurity
 @ConditionalOnProperty(value = "auth.type", havingValue = "LDAP")
 @Import(LdapAutoConfiguration.class)
+@EnableConfigurationProperties(LdapProperties.class)
+@RequiredArgsConstructor
 @Slf4j
-public class LdapSecurityConfig extends AbstractAuthSecurityConfig {
-
-  @Value("${spring.ldap.urls}") // TODO properties
-  private String ldapUrls;
-  @Value("${spring.ldap.dn.pattern:#{null}}")
-  private String ldapUserDnPattern;
-  @Value("${spring.ldap.adminUser:#{null}}")
-  private String adminUser;
-  @Value("${spring.ldap.adminPassword:#{null}}")
-  private String adminPassword;
-  @Value("${spring.ldap.userFilter.searchBase:#{null}}")
-  private String userFilterSearchBase;
-  @Value("${spring.ldap.userFilter.searchFilter:#{null}}")
-  private String userFilterSearchFilter;
-
-  @Value("${oauth2.ldap.activeDirectory:false}")
-  private boolean isActiveDirectory;
-  @Value("${oauth2.ldap.aсtiveDirectory.domain:#{null}}")
-  private String activeDirectoryDomain;
+public class LdapSecurityConfig {
 
-  @Bean
-  public ReactiveAuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource,
-                                                             ApplicationContext context) {
-    BindAuthenticator ba = new BindAuthenticator(contextSource);
-    if (ldapUserDnPattern != null) {
-      ba.setUserDnPatterns(new String[] {ldapUserDnPattern});
-    }
-    if (userFilterSearchFilter != null) {
-      LdapUserSearch userSearch =
-          new FilterBasedLdapUserSearch(userFilterSearchBase, userFilterSearchFilter, contextSource);
-      ba.setUserSearch(userSearch);
+  private final LdapProperties props;
+
+  @Autowired
+  public void authenticationManager(AuthenticationManagerBuilder builder, ApplicationContext context,
+                                    @Nullable AccessControlService acs) throws Exception {
+    var configurer = builder.ldapAuthentication();
+
+    if (props.isActiveDirectory()) {
+      builder.authenticationProvider(activeDirectoryAuthenticationProvider());
     }
 
-    AbstractLdapAuthenticationProvider authenticationProvider;
-    if (!isActiveDirectory) {
-      authenticationProvider = new LdapAuthenticationProvider(ba, authoritiesPopulator(context));
-      authenticationProvider.setUserDetailsContextMapper(userDetailsContextMapper());
+    if (acs != null && acs.isRbacEnabled()) {
+      configurer.ldapAuthoritiesPopulator(new RbacLdapAuthoritiesExtractor(context));
     } else {
-      authenticationProvider = new ActiveDirectoryLdapAuthenticationProvider(activeDirectoryDomain, ldapUrls);
-      authenticationProvider.setUseAuthenticationRequestCredentials(true);
+      configurer.groupSearchBase(props.getGroupSearchBase());
     }
 
-    AuthenticationManager am = new ProviderManager(List.of(authenticationProvider));
+    configurer.userDetailsContextMapper(new UserDetailsMapper());
 
-    return new ReactiveAuthenticationManagerAdapter(am);
+    configurer
+        .userDnPatterns(props.getDnPattern())
+        .userSearchBase(props.getUserFilterSearchBase())
+        .userSearchFilter(props.getUserFilterSearchFilter())
+        .contextSource()
+        .url(props.getUrls())
+        .managerDn(props.getAdminUser())
+        .managerPassword(props.getAdminPassword());
   }
 
   @Bean
-  @Primary
-  public BaseLdapPathContextSource contextSource() {
-    LdapContextSource ctx = new LdapContextSource();
-    ctx.setUrl(ldapUrls);
-    ctx.setUserDn(adminUser);
-    ctx.setPassword(adminPassword);
-    ctx.afterPropertiesSet();
-    return ctx;
+  public AuthenticationManager authenticationManager(AuthenticationConfiguration conf) throws Exception {
+    conf.authenticationManagerBuilder()
+    return conf.getAuthenticationManager();
   }
 
   @Bean
   public SecurityWebFilterChain configureLdap(ServerHttpSecurity http) {
     log.info("Configuring LDAP authentication.");
-    if (isActiveDirectory) {
+    if (props.isActiveDirectory()) {
       log.info("Active Directory support for LDAP has been enabled.");
     }
 
@@ -123,42 +99,21 @@ public class LdapSecurityConfig extends AbstractAuthSecurityConfig {
   }
 
   @Bean
-  public UserDetailsContextMapper userDetailsContextMapper() {
-    return new LdapUserDetailsMapper() {
-      @Override
-      public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
-        UserDetails userDetails = super.mapUserFromContext(ctx, username, authorities);
-        return new RbacLdapUser(userDetails);
-      }
-    };
+  @ConditionalOnProperty(value = "oauth2.ldap.activeDirectory", havingValue = "true")
+  public AuthenticationProvider activeDirectoryAuthenticationProvider() {
+    var provider = new ActiveDirectoryLdapAuthenticationProvider(props.getActiveDirectoryDomain(), props.getUrls());
+    provider.setUseAuthenticationRequestCredentials(true);
+    return provider;
   }
 
-  @Bean
-  LdapAuthoritiesPopulator authoritiesPopulator(ApplicationContext context) {
-    RbacLdapAuthoritiesExtractor extractor = new RbacLdapAuthoritiesExtractor(context);
-    extractor.setRolePrefix("");
-    return extractor;
-  }
-
-/*  @Autowired
-  public void configure(AuthenticationManagerBuilder auth) throws Exception {
-    var a = auth
-        .ldapAuthentication()
-        .userDnPatterns("uid={0},ou=people")
-        .groupSearchBase("ou=groups")
-        .contextSource()
-        .url()
-        .managerDn()
-        .managerPassword()
-        .and()
-//        .passwordCompare()
-//        .passwordEncoder(new BCryptPasswordEncoder())
-//        .passwordAttribute("userPassword");
-    ;
-    if (isActiveDirectory) {
-      a.authenticationProvider()
+  private static class UserDetailsMapper extends LdapUserDetailsMapper {
+    @Override
+    public UserDetails mapUserFromContext(DirContextOperations ctx, String username,
+                                          Collection<? extends GrantedAuthority> authorities) {
+      UserDetails userDetails = super.mapUserFromContext(ctx, username, authorities);
+      return new RbacLdapUser(userDetails);
     }
-  }*/
+  }
 
 }
 

+ 21 - 0
kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/auth/condition/ActiveDirectoryCondition.java

@@ -0,0 +1,21 @@
+package com.provectus.kafka.ui.config.auth.condition;
+
+import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+
+public class ActiveDirectoryCondition extends AllNestedConditions {
+
+  public ActiveDirectoryCondition(ConfigurationPhase configurationPhase) {
+    super(configurationPhase);
+  }
+
+  @ConditionalOnProperty(value = "auth.type", havingValue = "LDAP")
+  static class onAuthType {
+
+  }
+
+  @ConditionalOnProperty(value = "oauth2.ldap.activeDirectory", havingValue = "true")
+  static class onActiveDirectory {
+
+  }
+}

+ 1 - 1
kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/rbac/extractor/RbacLdapAuthoritiesExtractor.java

@@ -25,7 +25,7 @@ public class RbacLdapAuthoritiesExtractor extends DefaultLdapAuthoritiesPopulato
 
   private final Function<Map<String, List<String>>, GrantedAuthority> authorityMapper = (record) -> {
     String role = record.get(getGroupRoleAttribute()).get(0);
-    return new SimpleGrantedAuthority(getRolePrefix() + role);
+    return new SimpleGrantedAuthority(role);
   };
 
   public RbacLdapAuthoritiesExtractor(ApplicationContext context) {