Java 不带全名的Spring Security Active Directory LDAP身份验证
我使用SpringSecurity3.2配置了ActiveDirectoryLdapAuthenticationProvider。我能够使用全名示例进行身份验证sharon@mydomain.com但是,当我尝试仅使用用户名“sharon”进行身份验证时,我得到以下错误Java 不带全名的Spring Security Active Directory LDAP身份验证,java,spring-security,active-directory,spring-ldap,spring-security-ldap,Java,Spring Security,Active Directory,Spring Ldap,Spring Security Ldap,我使用SpringSecurity3.2配置了ActiveDirectoryLdapAuthenticationProvider。我能够使用全名示例进行身份验证sharon@mydomain.com但是,当我尝试仅使用用户名“sharon”进行身份验证时,我得到以下错误 2015-12-21_17:07:00.752 DEBUG o.s.s.l.a.a.ActiveDirectoryLdapAuthenticationProvider - authenticate - Processing
2015-12-21_17:07:00.752 DEBUG o.s.s.l.a.a.ActiveDirectoryLdapAuthenticationProvider - authenticate - Processing authentication request for user: sharon
2015-12-21_17:07:00.793 DEBUG o.s.s.l.SpringSecurityLdapTemplate - searchForSingleEntryInternal - Searching for entry under DN '', base = 'dc=mydomain,dc=com', filter = '(&(objectClass=user)(userPrincipalName={0}))'
2015-12-21_17:07:00.793 INFO o.s.s.l.SpringSecurityLdapTemplate - searchForSingleEntryInternal - Ignoring PartialResultException
2015-12-21_17:07:00.794 DEBUG o.s.s.l.a.LdapAuthenticationProvider - authenticate - Processing authentication request for user: gdcadmin
2015-12-21_17:07:00.796 DEBUG o.s.s.l.a.BindAuthenticator - bindWithDn - Attempting to bind as cn=gdcadmin,cn=Users,dc=mydomain,dc=com,dc=springframework,dc=org
2015-12-21_17:07:00.796 DEBUG o.s.s.l.DefaultSpringSecurityContextSource - setupEnvironment - Removing pooling flag for user cn=gdcadmin,cn=Users,dc=mydomain,dc=com,dc=springframework,dc=org
2015-12-21_17:07:00.858 DEBUG o.a.m.f.codec.ProtocolCodecFilter - messageReceived - Processing a MESSAGE_RECEIVED for session 1
2015-12-21_17:07:00.859 DEBUG o.a.d.shared.asn1.ber.Asn1Decoder - decode - >>>==========================================
.....
.....
.....
015-12-21_17:07:00.905 DEBUG o.s.s.l.a.BindAuthenticator - handleBindException - Failed to bind as cn=gdcadmin,CN=Users,DC=mydomain,DC=com: org.springframework.ldap.AuthenticationException: [LDAP: error code 49 - cannot bind the principalDn.]; nested exception is javax.naming.AuthenticationException: [LDAP: error code 49 - cannot bind the principalDn.]
根据spring安全文档:
例如,名为“Sharon”的用户将能够进行身份验证
通过输入用户名sharon或完整的Active Directory
userPrincipalName,即sharon@mydomain.com
我的配置
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
auth.eraseCredentials(false);
auth.ldapAuthentication().userDnPatterns("cn={0},CN=Users,DC=mydomain,DC=com");
}
@Bean
public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(env.getProperty("mydomain.com"),
env.getProperty("ldap://hmidir01.mydomain.com:389/"));
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setUserDetailsContextMapper(userDetailsContextMapper);
return provider;
}
我的配置有什么错误
您可以以给定的方式实现:
1)而不将数据持久化到我们的数据库中
java
@配置
@启用WebMVC安全性
公共类WebSecurityConfig扩展了WebSecurityConfigureAdapter{
@豆子
公共ActiveDirectoryLdapAuthenticationProvider ActiveDirectoryLdapAuthenticationProvider(){
ActiveDirectoryLdapAuthenticationProvider=新的ActiveDirectoryLdapAuthenticationProvider(,);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
退货供应商;
}
@豆子
公共LoggerListener LoggerListener(){
返回新的LoggerListener();
}
@凌驾
受保护的无效配置(AuthenticationManagerBuilder auth)引发异常{
auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
}
@凌驾
受保护的无效配置(HttpSecurity http)引发异常{
http
.授权请求()
.antMatchers(“/admin/**”).hasAnyAuthority(“admin”)
.antMatchers(“/user/**”).hasAnyAuthority(“管理员”、“用户”)
.antMatchers(“/rest/**”,“/css/**”,“/font/**”,“/images/**”,“/js/**”).permitAll()
.anyRequest().authenticated()
.及()
.formLogin()
.loginPage(“/”).failureUrl(“/?错误”).successHandler(“/home”).permitAll()
.usernameParameter(“emailId”).passwordParameter(“密码”)
.及()
.logout()
.logoutUrl(“/logout”).logoutSuccessUrl(“/”).permitAll()
.及()
.exceptionHandling().accessDeniedPage(“/home”)
.及()
.csrf()
.及()
.httpBasic();
}
}
2)将数据持久化到我们的数据库中
WebSecurityConfig.java
@配置
@启用WebMVC安全性
公共类WebSecurityConfig扩展了WebSecurityConfigureAdapter{
@凌驾
受保护的无效配置(HttpSecurity http)引发异常{
http
.授权请求()
.antMatchers(“/admin/**”).hasAnyAuthority(“admin”)
.antMatchers(“/user/**”).hasAnyAuthority(“管理员”、“用户”)
.antMatchers(“/rest/**”,“/css/**”,“/font/**”,“/images/**”,“/js/**”).permitAll()
.anyRequest().authenticated()
.及()
.formLogin()
.loginPage(“/”).failureUrl(“/?错误”).successHandler(“/home”).permitAll()
.usernameParameter(“emailId”).passwordParameter(“密码”)
.及()
.logout()
.logoutUrl(“/logout”).logoutSuccessUrl(“/”).permitAll()
.及()
.exceptionHandling().accessDeniedPage(“/home”)
.及()
.csrf()
.及()
.httpBasic();
}
@自动连线
public void configureGlobal(AuthenticationManagerBuilder auth)引发异常{
认证
.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
}
@豆子
公共ActiveDirectoryLdapAuthenticationProvider ActiveDirectoryLdapAuthenticationProvider(){
ActiveDirectoryLdapAuthenticationProvider=新的ActiveDirectoryLdapAuthenticationProvider((null),);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
setUserDetailsContextMapper(userDetailsContextMapper());
退货供应商;
}
@豆子
公共UserDetailsContextMapper UserDetailsContextMapper(){
返回新属性LdapUserDetailsContextMapper();
}
}
AttributesLDAPUserDetailsContextMapper.java
公共类属性LDAPUserDetailsContextMapper实现UserDetailsContextMapper{
@自动连线
私人用户服务;
私有InetOrgPersonContextMapper ldapUserDetailsMapper=新的InetOrgPersonContextMapper();
@凌驾
public UserDetails mapUserFromContext(DirContextOperations DirContextOperations,字符串用户名,集合与spring security 5.2.1:
您可以使用setSearchFilter()
函数
LDAP身份验证过程有两个主要步骤:绑定,它使用ActiveDirectoryLdapAuthenticationProvider()
中的域参数(第一个)形成如下用户名:myUser@sub.domain.com
给定凭据:username=myUser;password myPassword。
如果这不正确,您将得到错误的凭证错误(AcceptSecurityContext错误,数据52e)
然后,下一步是在ldap目录中查找用户。
如果您的用户没有名为username的属性,该属性为=myUser@sub.domain.com,ldap服务器将返回未找到的错误(这将作为忽略部分结果异常从用户名NotFoundException:在目录中找不到用户myUser中弹出。
异常。为此,您可以使用searchFilter选项。
提供的用户名将插入{1}
点
@Configuration
@EnableWebSecurity
@AllArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception{
http.cors().and().csrf().disable().authorizeRequests()
.anyRequest().fullyAuthenticated().and().httpBasic(); //this will invoke an auth popup in browser
}
@Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(activeDirectoryLdapAuthenticationProvider());
}
@Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new
ActiveDirectoryLdapAuthenticationProvider("sub.domain.com","ldap://url");
provider.setSearchFilter("mailNickname={1}"); //here is the trick
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
return provider;
}
}
你能解释一下吗?我看不出你的代码和我的代码有什么区别。我的要求是用用户名而不是电子邮件/完整用户名进行身份验证。
@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasAnyAuthority("ADMIN")
.antMatchers("/user/**").hasAnyAuthority("ADMIN", "USER")
.antMatchers("/rest/**", "/css/**", "/fonts/**", "/images/**", "/js/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/").failureUrl("/?error").successHandler("/home").permitAll()
.usernameParameter("emailId").passwordParameter("password")
.and()
.logout()
.logoutUrl("/logout").logoutSuccessUrl("/").permitAll()
.and()
.exceptionHandling().accessDeniedPage("/home")
.and()
.csrf()
.and()
.httpBasic();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)throws Exception {
auth
.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
}
@Bean
public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(<ldap-domain>(null), <ldap-url>);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setUserDetailsContextMapper(userDetailsContextMapper());
return provider;
}
@Bean
public UserDetailsContextMapper userDetailsContextMapper() {
return new AttributesLDAPUserDetailsContextMapper();
}
}
public class AttributesLDAPUserDetailsContextMapper implements UserDetailsContextMapper {
@Autowired
private UserService service;
private InetOrgPersonContextMapper ldapUserDetailsMapper = new InetOrgPersonContextMapper();
@Override
public UserDetails mapUserFromContext(DirContextOperations dirContextOperations, String userName, Collection<? extends GrantedAuthority> collection) {
InetOrgPerson userLdap = (InetOrgPerson) ldapUserDetailsMapper.mapUserFromContext(dirContextOperations, userName, collection);
User user = service.findOne(userLdap.getUsername());
if (user == null) {
user = new Usere();
user.setName(StringUtils.defaultString(userLdap.getDisplayName()).trim());
user.setEmailId(StringUtils.defaultString(userLdap.getUsername()).trim());
user.setdescription(StringUtils.defaultString(userLdap.getDescription()).trim());
user.setIsAdmin(false);
user.setIsEmployee(true);
service.save(user);
}
return new LdapSecuredUser(user);
}
@Override
public void mapUserToContext(UserDetails userDetails, DirContextAdapter dirContextAdapter) {
ldapUserDetailsMapper.mapUserToContext(userDetails, dirContextAdapter);
}
}
public class LdapSecuredUser extends User implements LdapUserDetails {
private static final long serialVersionUID = -8997460180274787521L;
public LdapSecuredUser(User user) {
if (user != null) {
this.setId(user.getId());
this.setEmailId(user.getEmailId());
this.setName(user.getName());
this.setdescription(user.getDescription());
this.setIsAdmin(user.getIsAdmin());
this.setIsEmployee(user.getIsEmployee());
}
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("USER"));
if(super.getIsAdmin())
authorities.add(new SimpleGrantedAuthority("ADMIN"));
return authorities;
}
@Override
public String getUsername() {
return super.getEmailId();
}
@Override
public String getPassword() {
return null;
}
@Override
public String getDn() {
return null;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
}
@Configuration
@EnableWebSecurity
@AllArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception{
http.cors().and().csrf().disable().authorizeRequests()
.anyRequest().fullyAuthenticated().and().httpBasic(); //this will invoke an auth popup in browser
}
@Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(activeDirectoryLdapAuthenticationProvider());
}
@Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new
ActiveDirectoryLdapAuthenticationProvider("sub.domain.com","ldap://url");
provider.setSearchFilter("mailNickname={1}"); //here is the trick
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
return provider;
}
}