2017-05-30 169 views
0

我已经通过ActiveDirectoryLdapAuthenticationProvider将我的应用程序与LDAP集成在一起。当我用正确的凭据登录时,一切正常。问题发生在凭证错误:Spring Security和LDAP - java.io.NotSerializableException:com.sun.jndi.ldap.LdapCtx

org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.io.NotSerializableException: com.sun.jndi.ldap.LdapCtx 
    at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:68) 
    at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:35) 
    at org.springframework.session.data.mongo.JdkMongoSessionConverter.serializeAttributes(JdkMongoSessionConverter.java:105) 
    at org.springframework.session.data.mongo.JdkMongoSessionConverter.convert(JdkMongoSessionConverter.java:84) 
    at org.springframework.session.data.mongo.AbstractMongoSessionConverter.convert(AbstractMongoSessionConverter.java:110) 
    at org.springframework.session.data.mongo.MongoOperationsSessionRepository.convertToDBObject(MongoOperationsSessionRepository.java:141) 
    at org.springframework.session.data.mongo.MongoOperationsSessionRepository.save(MongoOperationsSessionRepository.java:77) 
    at org.springframework.session.data.mongo.MongoOperationsSessionRepository.save(MongoOperationsSessionRepository.java:44) 
    at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.commitSession(SessionRepositoryFilter.java:245) 
    at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.access$100(SessionRepositoryFilter.java:217) 
    at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:170) 
    at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:80) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) 
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 
    at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106) 
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) 
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) 
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) 
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) 
    at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:677) 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) 
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) 
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) 
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) 
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) 
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 
    at java.lang.Thread.run(Thread.java:745) 
Caused by: java.io.NotSerializableException: com.sun.jndi.ldap.LdapCtx 
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) 
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) 
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509) 
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) 
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) 
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) 
    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441) 
    at java.lang.Throwable.writeObject(Throwable.java:985) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1028) 
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496) 
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) 
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) 
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) 
    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441) 
    at java.lang.Throwable.writeObject(Throwable.java:985) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1028) 
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496) 
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) 
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) 
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) 
    at java.util.HashMap.internalWriteEntries(HashMap.java:1777) 
    at java.util.HashMap.writeObject(HashMap.java:1354) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1028) 
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496) 
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) 
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) 
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) 
    at org.springframework.core.serializer.DefaultSerializer.serialize(DefaultSerializer.java:46) 
    at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:63) 
    ... 38 common frames omitted 

而且我在登录页面上收到500条消息,而不是消息。登录页面由Spring Security生成。我使用@EnableMongoHttpSessionJdkMongoSessionConverter被用作AbstractMongoSessionConverter的实现。

我知道问题出在序列化LdapCtx,但我该如何处理它?我的意思是简单的捕捉异常,并在登录页面显示消息如“错误的凭据”。

春季安全配置:

package xxx; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Value; 
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.context.annotation.Profile; 
import org.springframework.security.authentication.AuthenticationProvider; 
import org.springframework.security.authentication.dao.DaoAuthenticationProvider; 
import org.springframework.security.authentication.encoding.ShaPasswordEncoder; 
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 
import org.springframework.security.core.GrantedAuthority; 
import org.springframework.security.core.authority.SimpleGrantedAuthority; 
import org.springframework.security.core.userdetails.User; 
import org.springframework.security.core.userdetails.UserDetails; 
import org.springframework.security.core.userdetails.UserDetailsService; 
import org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider; 
import org.springframework.security.provisioning.InMemoryUserDetailsManager; 

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.List; 

@Configuration 
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Value("${spring.security.role.name}") 
    private String roleName; 

    @Autowired 
    private AuthenticationProvider provider; 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
       .csrf().disable() 
       .authorizeRequests() 
       .antMatchers("/app/**").fullyAuthenticated() 
       .antMatchers("/operations/**").hasAuthority(roleName) 
       .anyRequest().permitAll() 
       .and() 
       .formLogin() 
       .loginProcessingUrl("/login"); 
    } 

    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
     auth.authenticationProvider(provider); 
    } 

    @Bean 
    @Profile("dev-tests") 
    public AuthenticationProvider authenticationProvider() { 
     DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); 
     authenticationProvider.setUserDetailsService(devUserDetailsService()); 
     ShaPasswordEncoder passwordEncoder = new ShaPasswordEncoder(1); 
     authenticationProvider.setPasswordEncoder(passwordEncoder); 
     return authenticationProvider; 
    } 

    @Bean 
    @ConditionalOnMissingBean(AuthenticationProvider.class) 
    public AuthenticationProvider ldapAuthenticationProvider() { 
     ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(
       "****", 
       "ldaps://****:3269", 
       "OU=****,DC=****,DC=****,DC=****" 
     ); 
     provider.setConvertSubErrorCodesToExceptions(true); 
     provider.setSearchFilter("(&(objectClass=userProxy)(userPrincipalName={0}))"); 
     return provider; 
    } 

    private UserDetailsService devUserDetailsService() { 
     List<GrantedAuthority> authorities = new ArrayList<>(); 
     authorities.add(new SimpleGrantedAuthority(roleName)); 
     authorities.add(new SimpleGrantedAuthority("ROLE_ACTUATOR")); 

     Collection<UserDetails> users = new ArrayList<>(); 
     users.add(new User("admin", "d033e22ae348aeb5660fc2140aec35850c4da997", authorities)); //pass: admin 
     users.add(new User("read", "a7afddb68260a60f86c02a021efba7f216c2e7cf", new ArrayList<>())); //pass: read 
     return new InMemoryUserDetailsManager(users); 
    } 

} 

蒙戈配置:

package xxxxx; 

import xxxxx.SpringDataEnvServiceVersionRepository; 
import com.mongodb.Mongo; 
import com.mongodb.MongoClient; 
import com.mongodb.MongoClientURI; 
import org.springframework.beans.factory.annotation.Value; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.core.convert.converter.Converter; 
import org.springframework.data.mongodb.config.AbstractMongoConfiguration; 
import org.springframework.data.mongodb.core.convert.CustomConversions; 
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; 
import org.springframework.session.data.mongo.JdkMongoSessionConverter; 
import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession; 

import java.time.Instant; 
import java.time.LocalDate; 
import java.time.ZonedDateTime; 
import java.util.ArrayList; 
import java.util.Date; 
import java.util.List; 

import static java.time.ZoneOffset.UTC; 
import static java.time.ZonedDateTime.ofInstant; 

@Configuration 
@EnableMongoRepositories(
     basePackages = {"****"}, 
     basePackageClasses = {SpringDataEnvServiceVersionRepository.class}) 
@EnableMongoHttpSession(collectionName = "****") 
public class MongoConfiguration extends AbstractMongoConfiguration { 

    @Value("${spring.data.mongodb.uri}") 
    private String uri; 

    @Override 
    protected String getDatabaseName() { 
     return new MongoClientURI(uri).getDatabase(); 
    } 

    @Bean 
    @Override 
    public Mongo mongo() { 
     return new MongoClient(new MongoClientURI(uri)); 
    } 

    @Bean 
    public JdkMongoSessionConverter jdkMongoSessionConverter() { 
     return new JdkMongoSessionConverter(); 
    } 

    @Bean 
    @Override 
    public CustomConversions customConversions() { 
     List<Converter> list = new ArrayList<>(); 
     list.add(new DateToZonedDateTimeConverter()); 
     list.add(new ZonedDateTimeToDateConverter()); 
     list.add(new LocalDateToDateConverter()); 
     list.add(new DateToLocalDateConverter()); 
     list.add(new StringToZonedDateTimeConverter()); 
     return new CustomConversions(list); 
    } 

    private static class DateToZonedDateTimeConverter implements Converter<Date, ZonedDateTime> { 
     @Override 
     public ZonedDateTime convert(Date source) { 
      return source == null ? null : ofInstant(source.toInstant(), UTC); 
     } 
    } 

    private static class ZonedDateTimeToDateConverter implements Converter<ZonedDateTime, Date> { 
     @Override 
     public Date convert(ZonedDateTime source) { 
      return source == null ? null : Date.from(source.toInstant()); 
     } 
    } 

    private static class LocalDateToDateConverter implements Converter<LocalDate, Date> { 
     @Override 
     public Date convert(LocalDate source) { 
      return Date.from(source.atStartOfDay(UTC).toInstant()); 
     } 
    } 

    private static class DateToLocalDateConverter implements Converter<Date, LocalDate> { 
     @Override 
     public LocalDate convert(Date source) { 
      return Instant.ofEpochMilli(source.getTime()).atZone(UTC).toLocalDate(); 
     } 
    } 

    private static class StringToZonedDateTimeConverter implements Converter<String, ZonedDateTime> { 

     @Override 
     public ZonedDateTime convert(String s) { 
      return s == null ? null : ZonedDateTime.parse(s); 
     } 
    } 

} 
+0

请问您能显示相关的代码吗? –

+0

@RomanPuchkovskiy完成 –

回答

0

解决方案摆在春季安全配置,下面的代码:

@Bean 
    @ConditionalOnMissingBean(AuthenticationProvider.class) 
    public AuthenticationProvider ldapAuthenticationProvider() { 
     ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(
       "****", 
       "ldaps://****:3269", 
       "OU=****,DC=****,DC=****,DC=****" 
     ); 
     provider.setConvertSubErrorCodesToExceptions(true); 
     provider.setSearchFilter("(&(objectClass=userProxy)(userPrincipalName={0}))"); 


     return new AuthenticationProvider() { 
      @Override 
      public Authentication authenticate(Authentication authentication) throws AuthenticationException { 
       try { 
        return provider.authenticate(authentication); 
       } catch (BadCredentialsException e) { 
        throw new BadCredentialsException(e.getMessage()); 
       } 
      } 

      @Override 
      public boolean supports(Class<?> aClass) { 
       return provider.supports(aClass); 
      } 
     }; 
    } 

这从异常的原因消除了LdapCtx实例然后它不一定是seriali ZED。如有任何建议,请告诉我。