登录表单用户凭据而不是 LDAP Spring Security 中的硬编码 UserDn 和密码
Posted
技术标签:
【中文标题】登录表单用户凭据而不是 LDAP Spring Security 中的硬编码 UserDn 和密码【英文标题】:Login form user credentials instead of hard-coded UserDn and Password in LDAP Spring Security 【发布时间】:2018-09-12 08:35:36 【问题描述】:我已经使用 Spring Boot 通过 LDAP 实现了 spring 安全性。我能够成功地与我的公司 LDAP 服务器绑定,但使用硬编码的值。这是我可以与我的公司 LDAP 服务器绑定并继续进行的唯一方法,因为我不知道要成功绑定的管理员/通用 UserDN 或密码。由于某些机密原因,该公司没有向我提供管理员凭据。
我想使用用户在登录表单中输入的用户名和密码设置 ContextSource 的 UserDn 和密码。但是这里的问题是在启动 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 但我不得不再次检查硬编码的用户名和密码:(
【问题讨论】:
嗨,我觉得这应该对@SpringBootApplication(exclude = SecurityAutoConfiguration.class )
有帮助
嗨@Jayesh,添加这个会禁用Spring Security,对吗?这是否会达到不在 SecurityConfig 类中设置硬编码值的目的?我是 SpringBoot 的新手,因此对此有点怀疑。
无论如何我尝试排除 SecurityAutoConfig 并且在启动 tomcat 时出现异常。它说 SecurityConfig Bean 无法初始化..有关 ObjectPostProcessor bean 的一些依赖错误
您是否为安全创建了自己的 bean?我的代码 sn-p 只会阻止自动配置为您创建默认配置。
不,我没有,我正在使用 spring security 并尝试使用 LDAP 来允许同事使用他们公司的 LDAP 凭据登录到应用程序
【参考方案1】:
我终于让它工作了.. :) 我找到了我想要的东西 here 。 (阿里·米斯基恩的回答)
我尝试使用 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);
希望这会有所帮助 :) 编码愉快...
【讨论】:
以上是关于登录表单用户凭据而不是 LDAP Spring Security 中的硬编码 UserDn 和密码的主要内容,如果未能解决你的问题,请参考以下文章
无法使用具有正确凭据的 Spring 3.1 验证 LDAP 帐户
带有表单登录的 Spring Security OAuth 2