1

Wir haben eine Spring Boot-Anwendung mit einer Hazecast-backed Spring Session. Die Anwendung authentifiziert sich mit Active Directory mithilfe von Spring Security. Wenn ein Benutzer mit ungültigen Anmeldeinformationen anzumelden versucht, wird eine Serialisierung Fehler ausgelöst:Spring Boot-Anwendung mit Hazelcast Backed Spring Session Serialisierungsausnahme bei Active Directory-Anmeldefehler

com.hazelcast.nio.serialization.HazelcastSerializationException: java.io.NotSerializableException: com.sun.jndi.ldap.LdapCtx 
     at com.hazelcast.nio.serialization.SerializationServiceImpl.handleException(SerializationServiceImpl.java:380) 
     at com.hazelcast.nio.serialization.SerializationServiceImpl.toData(SerializationServiceImpl.java:235) 
     at com.hazelcast.nio.serialization.SerializationServiceImpl.toData(SerializationServiceImpl.java:207) 
     at com.hazelcast.map.impl.MapServiceContextImpl.toData(MapServiceContextImpl.java:338) 
     at com.hazelcast.map.impl.proxy.MapProxySupport.toData(MapProxySupport.java:1160) 
     at com.hazelcast.map.impl.proxy.MapProxyImpl.put(MapProxyImpl.java:96) 
     at org.springframework.session.hazelcast.config.annotation.web.http.HazelcastHttpSessionConfiguration$ExpiringSessionMap.put(HazelcastHttpSessionConfiguration.java:112) 
     at org.springframework.session.hazelcast.config.annotation.web.http.HazelcastHttpSessionConfiguration$ExpiringSessionMap.put(HazelcastHttpSessionConfiguration.java:102) 
     at org.springframework.session.MapSessionRepository.save(MapSessionRepository.java:72) 
     at org.springframework.session.MapSessionRepository.save(MapSessionRepository.java:36) 
     at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.commitSession(SessionRepositoryFilter.java:194) 
     at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.access$100(SessionRepositoryFilter.java:170) 
     at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:128) 
     at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:65) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) 
     at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121) 
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) 
     at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:103) 
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) 
     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) 
     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) 
     at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) 
     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) 
     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) 
     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) 
     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522) 
     at org.apache.coyote.ajp.AbstractAjpProcessor.process(AbstractAjpProcessor.java:868) 
     at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672) 
     at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1502) 
     at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1458) 
     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) 

Dies ist die identisch zu einer neuen Ausgabe (Spring Boot with Session/Redis Serialization Error with Bad Active Directory Ldap Credentials) mit Redis zu sein scheint, aber es ist keine ähnlicher Mechanismus zu sein scheint Serialisierung in der Hazelcast-Sitzungszuordnung, die für Redis in Spring Session vorhanden ist, zu steuern.

Wir haben eine Workaround (unten), aber es scheint weniger als ideal, da HazelcastHttpSessionConfiguration scheint nicht wirklich zu Erweiterung, so scheint es sollte es eine sauberere Art und Weise, die wir nicht sind Sehen.

Wir erweitern die HazelcastHttpSessionConfiguration, um an die ExpiringSessionMap zu gelangen, um die LdapCtx zu entfernen, bevor Serialisierung versucht wird. Dies scheint nicht ideal zu sein, da die HazelcastHttpSessionConfiguration sich nicht wirklich für die Erweiterung eignet, was eine Duplizierung von Code erfordert.

Gibt es eine bessere Lösung, die wir vermissen?

@Configuration 
public class CustomHazelcastHttpSessionMapConfiguration extends HazelcastHttpSessionConfiguration{ 

    private String sessionMapName = "spring:session:sessions"; 
    private int maxInactiveIntervalInSeconds = 1800; 

    @Bean 
    public SessionRepository<ExpiringSession> sessionRepository(
      HazelcastInstance hazelcastInstance, SessionEntryListener sessionListener) { 
     super.sessionRepository(hazelcastInstance, sessionListener); 

     MapSessionRepository sessionRepository = new MapSessionRepository(
       new CustomExpiringSessionMap(hazelcastInstance.getMap(this.sessionMapName))); 
     sessionRepository 
       .setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds); 

     return sessionRepository; 
    } 

    @Override 
    public void setSessionMapName(String sessionMapName) { 
     this.sessionMapName = sessionMapName; 
     super.setSessionMapName(sessionMapName); 
    } 

    @Override 
    public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) { 
     this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds; 
     super.setMaxInactiveIntervalInSeconds(maxInactiveIntervalInSeconds); 
    } 

    static class CustomExpiringSessionMap implements Map<String, ExpiringSession> { 
     private IMap<String, ExpiringSession> delegate; 

     CustomExpiringSessionMap(IMap<String, ExpiringSession> delegate) { 
      this.delegate = delegate; 
     } 

     public ExpiringSession put(String key, ExpiringSession value) { 
      if (value == null) { 
       return this.delegate.put(key, value); 
      } 
      for (String attrName : value.getAttributeNames()) { 
       Object attrVal = value.getAttribute(attrName); 
       // Don't serialize LdapCtx in a BadCredentialsException 
       if (attrVal instanceof BadCredentialsException && 
         ((BadCredentialsException) attrVal).getCause() != null && 
         ((BadCredentialsException) attrVal).getCause() instanceof ActiveDirectoryAuthenticationException && 
         ((BadCredentialsException) attrVal).getCause().getCause() != null && 
         ((BadCredentialsException) attrVal).getCause().getCause() instanceof javax.naming.AuthenticationException) { 
        ((javax.naming.AuthenticationException) ((BadCredentialsException) attrVal).getCause().getCause()).setResolvedObj(null); 
       } 
      } 
      return this.delegate.put(key, value, value.getMaxInactiveIntervalInSeconds(), 
        TimeUnit.SECONDS); 
     } 

    /*... copy and paste of the rest of ExpiringSessionMap */ 
    } 
} 

Antwort

0

Sie sollten einen custom serialization für Objekt (e) konfigurieren, mit denen Sie Probleme haben.

Auf diese Weise würden Sie Ihr Problem in der Hazelcast-Konfiguration angehen, ohne die Hazelcast-Konfiguration von Spring Session zu erweitern/duplizieren.

+0

Danke, das hat die Dinge ein bisschen sauberer gemacht. Wir haben einen benutzerdefinierten Serializer für ExpiringSession implementiert, da das Root-Objekt serialisiert wird, was die Dinge ein wenig vereinfacht. –

0

Eine sauberere Lösung wäre transient-attributes.

Wenn Sie einen Webfilter haben, können Sie ihm eine Liste von Eigenschaften übergeben, um das Verhalten zu steuern, und diese ist eine durch Kommas getrennte Liste von Attributnamen, die von der Serialisierung ausgeschlossen werden sollen.

DM ich, wenn Sie weitere Informationen benötigen.