title: Error while connecting with wrong user
body: <p>I have a project where I use Spring Boot, Spring Security and Spring MVC.
  I configure Spring Security to authenticate with our company ldap.</p>
  
  <p>When I try to log-in with a correct user, it works. But when I log-in with a wrong password or a wrong user, it returns an error :</p>
  
  <blockquote>
    <p>Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
    java.io.NotSerializableException: com.sun.jndi.ldap.LdapCtx
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:440) ~[na:1.7.0_67]
        at java.lang.Throwable.writeObject(Throwable.java:985) ~[na:1.7.0_67]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_67]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_67]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_67]
        at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_67]
        at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1495) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:440) ~[na:1.7.0_67]
        at java.lang.Throwable.writeObject(Throwable.java:985) ~[na:1.7.0_67]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_67]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_67]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_67]
        at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_67]
        at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1495) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177) ~[na:1.7.0_67]
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347) ~[na:1.7.0_67]
        at org.springframework.core.serializer.DefaultSerializer.serialize(DefaultSerializer.java:44) ~[spring-core-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:62) ~[spring-core-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        ... 46 common frames omitted
    Wrapped by: 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:67) ~[spring-core-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:34) ~[spring-core-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:50) ~[spring-data-redis-1.6.0.RC1.jar:1.6.0.RC1]
        ... 44 common frames omitted
    Wrapped by: org.springframework.data.redis.serializer.SerializationException: Cannot serialize; nested exception is 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.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:52) ~[spring-data-redis-1.6.0.RC1.jar:1.6.0.RC1]
        at org.springframework.data.redis.core.AbstractOperations.rawHashValue(AbstractOperations.java:166) ~[spring-data-redis-1.6.0.RC1.jar:1.6.0.RC1]
        at org.springframework.data.redis.core.DefaultHashOperations.putAll(DefaultHashOperations.java:128) ~[spring-data-redis-1.6.0.RC1.jar:1.6.0.RC1]
        at org.springframework.data.redis.core.DefaultBoundHashOperations.putAll(DefaultBoundHashOperations.java:85) ~[spring-data-redis-1.6.0.RC1.jar:1.6.0.RC1]
        at org.springframework.session.data.redis.RedisOperationsSessionRepository$RedisSession.saveDelta(RedisOperationsSessionRepository.java:409) ~[spring-session-1.0.1.RELEASE.jar:na]
        at org.springframework.session.data.redis.RedisOperationsSessionRepository$RedisSession.access$000(RedisOperationsSessionRepository.java:331) ~[spring-session-1.0.1.RELEASE.jar:na]
        at org.springframework.session.data.redis.RedisOperationsSessionRepository.save(RedisOperationsSessionRepository.java:211) ~[spring-session-1.0.1.RELEASE.jar:na]
        at org.springframework.session.data.redis.RedisOperationsSessionRepository.save(RedisOperationsSessionRepository.java:141) ~[spring-session-1.0.1.RELEASE.jar:na]
        at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.commitSession(SessionRepositoryFilter.java:187) ~[spring-session-1.0.1.RELEASE.jar:na]
        at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.access$100(SessionRepositoryFilter.java:163) ~[spring-session-1.0.1.RELEASE.jar:na]
        at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:121) ~[spring-session-1.0.1.RELEASE.jar:na]
        at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:65) ~[spring-session-1.0.1.RELEASE.jar:na]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:69) ~[spring-boot-actuator-1.3.0.M4.jar:1.3.0.M4]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_67]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_67]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at java.lang.Thread.run(Thread.java:745) [na:1.7.0_67]</p>
  </blockquote>
  
  <p>I don't understand why I have this error.I excepted to be redirected to the failure page (/login?error).</p>
  
  <p>Here is my configuration :</p>
  
  <pre><code>@Autowired
  private PortalUserDetailsService portalUserDetailsService;
  
  @Autowired
  private LoginSuccessHandler loginSuccessHandler;
  
  @Autowired
  private LogoutSuccessHandler LogoutSuccessHandler;
  
  @Override
  protected void configure(HttpSecurity http) throws Exception {
      // Manage access authority to pages
      http
          .csrf().disable()
          .authorizeRequests()
              .antMatchers("/about").permitAll()
              .anyRequest()
              .fullyAuthenticated().and()
          .httpBasic().and()
          .formLogin()
              .loginPage("/login")
              .permitAll()
              .successHandler(loginSuccessHandler)
              .failureUrl("/login?error" ).and()
          .logout()
              .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
              .permitAll()
              .logoutSuccessHandler(LogoutSuccessHandler);
  }
  
  
  @Override
  public void configure( WebSecurity web ) throws Exception
  {
      // This is here to ensure that the static content (JavaScript, CSS, etc)
      // is accessible without authentication
      web
          .ignoring()
          .antMatchers("/css/**", "/fonts/**", "/img/**", "/js/**", "/webjars/**");
  }
  
  @Override
  public void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
  }
  
  @Bean
  public AuthenticationManager authenticationManager() {
      return new ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
  }
  
  @Bean
  public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
      ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(domain, ldapUrl);
      provider.setConvertSubErrorCodesToExceptions(true);
      provider.setUseAuthenticationRequestCredentials(true);
      provider.setUserDetailsContextMapper(getUserDetailsContextMapper());
      return provider;
  }
  
  private UserDetailsContextMapper getUserDetailsContextMapper() {
      return new UserDetailsContextMapper() {
          @Override
          public UserDetails mapUserFromContext(DirContextOperations dirContextOperations, String s, Collection&lt;? extends GrantedAuthority&gt; collection) {
              PortalUserDetails portalUserDetails = portalUserDetailsService.loadZenithAttributesByUsername(s);
              try {
                  portalUserDetails = portalUserDetailsService.addLdapAttributesFromContext(dirContextOperations.getAttributes(), portalUserDetails);
              } catch (NamingException e) {
                  e.printStackTrace();
              }
              return portalUserDetails;
          }
  
          @Override
          public void mapUserToContext(UserDetails userDetails, DirContextAdapter dirContextAdapter) {
          }
  
      };
  }
  </code></pre>
  
  <p>Do you have any idea what I can do to fix this error ?</p>
  
  <p><strong>Solution :</strong>
  This problem was in my redis configuration.
  I change the config like this :</p>
  
  <pre><code>@Primary
  @Bean
  public RedisTemplate&lt;String,ExpiringSession&gt; redisTemplate2(RedisConnectionFactory connectionFactory) {
      RedisTemplate&lt;String, ExpiringSession&gt; template = new RedisTemplate&lt;String, ExpiringSession&gt;();
  
      template.setHashValueSerializer(new LdapFailAwareRedisObjectSerializer());
  
      template.setConnectionFactory(connectionFactory);
      return template;
  }
  </code></pre>
  
  <p>With this custom serializer :</p>
  
  <pre><code>public class LdapFailAwareRedisObjectSerializer implements RedisSerializer&lt;Object&gt; {
  
  private Converter&lt;Object, byte[]&gt; serializer = new SerializingConverter();
  private Converter&lt;byte[], Object&gt; deserializer = new DeserializingConverter();
  
  static final byte[] EMPTY_ARRAY = new byte[0];
  
  public Object deserialize(byte[] bytes) {
      if (isEmpty(bytes)) {
          return null;
      }
      else {
          try {
              return this.deserializer.convert(bytes);
          } catch (Exception ex) {
              throw new SerializationException("Cannot deserialize", ex);
          }
      }
  }
  
  public byte[] serialize(Object object) {
      if (object == null) {
          return EMPTY_ARRAY;
      }
  
      try {
          return serializer.convert(object);
      } catch (Exception ex) {
          return EMPTY_ARRAY;
          //TODO add logic here to only return EMPTY_ARRAY for known conditions
          // else throw the SerializationException
          // throw new SerializationException("Cannot serialize", ex);
      }
  }
  
  private boolean isEmpty(byte[] data) {
      return (data == null || data.length == 0);
  }
  }
  </code></pre>