首页 文章

登录表单用户凭据,而不是LDAP Spring Security中的硬编码UserDn和密码

提问于
浏览
2

我使用Spring Boot实现了使用LDAP的spring安全性 . 我能够成功绑定我的公司LDAP服务器,但具有硬编码值 . 这是我可以与公司LDAP服务器绑定并进一步继续的唯一方法,因为我不知道管理员/通用UserDN或密码来成功绑定 . 由于某些保密原因,该公司未向我提供管理员凭证 .

我想 set the UserDn and Password of the ContextSource with the username and password entered by the user in the login form . 但问题是在Tomcat服务器启动时扫描SecurityConfig类,在登录过程之后,控件根本不会进入SecurityConfig类 . 我怎么解决这个问题?需要一些帮助 .

这是我的 SecurityConfig 课程:

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationFailureHandler customAuthFailureHandler;

    @Autowired
    private CustomAuthenticationSuccessHandler customAuthSuccessHandler;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

        httpSecurity
            .authorizeRequests()
                .anyRequest().fullyAuthenticated()
                .and()
            .formLogin()
                .loginPage("/login").permitAll()
                .loginProcessingUrl("/sign-in")
                .usernameParameter("userid")
                .passwordParameter("password")
                .successHandler(customAuthSuccessHandler)
                .failureHandler(customAuthFailureHandler)
                .permitAll()
                .and()
            .logout()
                .logoutSuccessUrl("/logout")
                .permitAll()
                .and()
            .csrf().disable();

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.authenticationProvider(ldapAuthProvider());

    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationProvider ldapAuthProvider() throws Exception {

        DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldaps://some.domain.com:3269/");
        contextSource.setUserDn("username@domain.com"); // Here I want to set the username from Login screen
        contextSource.setPassword("password"); // also password from login screen
        contextSource.afterPropertiesSet();
        String userSearchFilter = "(sAMAccountName=username)"; // Here too I need to set username from login screen
        LdapUserSearch ldapUserSearch = new FilterBasedLdapUserSearch("dc=domain,dc=com", userSearchFilter, contextSource);
        BindAuthenticator bindAuth = new BindAuthenticator(contextSource);
        bindAuth.setUserSearch(ldapUserSearch);
        LdapAuthenticationProvider ldapAuthProvider = new LdapAuthenticationProvider(bindAuth);

        return ldapAuthProvider;
    }
}

我已经创建了一个AuthenticationProvider bean方法,我在AuthenticationManagerBuilder中设置它 . 我也试过创建一个 CustomAuthenticationProvider 但我又要用硬编码的用户名和密码检查:(

1 回答

  • 0

    我终于搞定了.. :)我找到了我想要的东西here . (Ali Miskeen的回答)

    我尝试了 CustomAuthenticationProvider 方法本身,但这一次,我使用传统的JNDI LDAP方法检查了身份验证 . 我还想检查3个不同的LDAP服务器,因此这种方法最适合我的应用程序 .

    这是我完整的CustomAuthenticationProvider实现:

    @Component
    public class CustomAuthenticationProvider implements AuthenticationProvider {
    
        private static final String AT_DOMAIN_COM = "@domain.com";
    
        private static final String SINGLE_SPACE = " ";
    
        @Value("${ldap.url.for.server1}")
        private String ldapUrlForServer1; // url set in application.properties
    
        @Value("${ldap.url.for.server2}")
        private String ldapUrlForServer2;
    
        @Value("${ldap.url.for.server3}")
        private String ldapUrlForServer3;
    
        @Value("${ldap.jndi.context.factory}")
        private String ldapContextFactory;
    
        @Value("${ldap.authentication.type}")
        private String ldapAuthenticationType; // auth type is "simple"
    
        @Override
        public Authentication authenticate(Authentication auth) throws AuthenticationException {
    
            String username = auth.getName();
            String password = auth.getCredentials().toString();
    
            if (isLdapRegisteredUser(username, password)) {
                // use the credentials and authenticate against a third-party system
                return new UsernamePasswordAuthenticationToken(username, password, new ArrayList<>());
            } else {
                return null;
            }
    
        }
    
        boolean isLdapRegisteredUser(String username, String password) {
    
            boolean result = false;
            Hashtable<String, String> env = new Hashtable<>();
            LdapContext ctx = null;
    
            try {
    
                env.put(Context.INITIAL_CONTEXT_FACTORY, ldapContextFactory);
                env.put(Context.SECURITY_AUTHENTICATION, ldapAuthenticationType);
                env.put(Context.SECURITY_PRINCIPAL, username + AT_DOMAIN_COM);
                env.put(Context.SECURITY_CREDENTIALS, password);
                // here I'm checking for 3 different LDAP servers
                env.put(Context.PROVIDER_URL,  ldapUrlForServer1 + SINGLE_SPACE + ldapUrlForServer2 + SINGLE_SPACE + ldapUrlForServer3); 
    
                ctx = new InitialLdapContext(env, null);
    
                if (ctx != null) {
                    result = true;
                    String selectedLdapUrl = ctx.getEnvironment().get(Context.PROVIDER_URL).toString();
                    // do further operations with "ctx" if needed
                    System.out.println("selected LDAP url is: " + selectedLdapUrl);
                    System.out.println("Connection Successful!");
                }
    
            } catch(NamingException nex) {
                nex.printStackTrace();
            } finally {
                if (ctx != null) {
                    try {
                        ctx.close();
                    } catch (Exception ex) {
                    }
                }
            }
    
            return result;
    
        }
    
    
        @Override
        public boolean supports(Class<?> auth) {
            return auth.equals(UsernamePasswordAuthenticationToken.class);
        }
    
    }
    

    这是我的SecurityConfig实现:

    @EnableWebSecurity
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private CustomAuthenticationProvider customAuthProvider;
    
        @Autowired
        private CustomAuthenticationFailureHandler customAuthFailureHandler;
    
        @Autowired
        private CustomAuthenticationSuccessHandler customAuthSuccessHandler;
    
        @Override
        protected void configure(HttpSecurity httpSecurity) throws Exception {
    
            httpSecurity
                .authorizeRequests()
                    .antMatchers("/css/**").permitAll()
                    .antMatchers("/fonts/**").permitAll()
                    .antMatchers("/images/**").permitAll()
                    .antMatchers("/js/**").permitAll()
                    .anyRequest().fullyAuthenticated()
                    .and()
                .formLogin()
                    .loginPage("/login").permitAll()
                    .loginProcessingUrl("/sign-in")
                    .usernameParameter("userid")
                    .passwordParameter("password")
                    .successHandler(customAuthSuccessHandler)
                    .failureHandler(customAuthFailureHandler)
                    .permitAll()
                    .and()
                .logout()
                    .clearAuthentication(true)
                    .logoutSuccessUrl("/login").permitAll()
                    .deleteCookies("JSESSIONID")
                    .invalidateHttpSession(true)
                    .and()
                .csrf().disable();
    
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    
            auth.authenticationProvider(customAuthProvider);
    
        }
    }
    

    希望这会有所帮助:)快乐编码......

相关问题