2015-09-23 13 views
4

您好我是新來的春天和Java,我想在本教程中https://spring.io/guides/tutorials/spring-security-and-angular-js/春季啓動與會話/ Redis的序列化錯誤與錯誤的Active Directory LDAP憑證

我得到了一切工作和描述來實現網關認證服務器然後嘗試對我們公司的Ldap服務器實施身份驗證。如果我使用有效的用戶名和密碼,它將起作用。當我使用無效的憑據時,應用程序錯誤。

我不在工作,所以我沒有確切的錯誤,但它返回了一個ldap錯誤(com.sun.jndi.ldap.LdapCtx),並且Redis試圖序列化它。

在我的配置中是否存在某些我缺少的東西。從我讀過的東西,我想我應該尋找一種方法來包裝/擴展類並實現Serializable,但我不確定使用Spring Boot做到這一點的侵入性最小。

任何幫助,非常感謝。

感謝,

邁克·科瓦爾斯基

PS我一直在工作主要是在動態語言和框架到現在爲止(使用Javascript /節點,PHP/Laravel)

下面是什麼,我認爲是相關

@Configuration 
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) 
public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
    http 
     .formLogin() 
     .defaultSuccessUrl("/") 
     .loginPage("/login") 
     .permitAll() 
     .and() 
     .logout() 
     .logoutSuccessUrl("/logout") 
     .permitAll(); 


    http 
     .authorizeRequests() 
     .antMatchers("/login").permitAll() 
     .anyRequest().authenticated() 
    .and() 
     .csrf().csrfTokenRepository(csrfTokenRepository()) 
    .and() 
     .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class); 
    } 

    @Override 
    protected void configure(AuthenticationManagerBuilder authManagerBuilder)   throws Exception { 
    authManagerBuilder 
     .authenticationProvider(activeDirectoryLdapAuthenticationProvider()) 
     .userDetailsService(userDetailsService()); 
    } 

    @Bean 
    public AuthenticationManager authenticationManager() { 
     return new ProviderManager(
     Arrays.asList(activeDirectoryLdapAuthenticationProvider()) 
    ); 
    } 

    @Bean 
    public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() { 
    ActiveDirectoryLdapAuthenticationProvider provider = new  ActiveDirectoryLdapAuthenticationProvider(
    "XXX.XXX", "ldaps://XXX.XXX:636"); 
     provider.setConvertSubErrorCodesToExceptions(true); 
     provider.setUseAuthenticationRequestCredentials(true); 
     return provider; 
    } 

    private Filter csrfHeaderFilter() { 
    return new OncePerRequestFilter() { 
     @Override 
     protected void doFilterInternal(
     HttpServletRequest request, 
     HttpServletResponse response, 
     FilterChain filterChain 
    ) throws ServletException, IOException 
     { 
     CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class 
      .getName()); 
     if (csrf != null) { 
      Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN"); 
      String token = csrf.getToken(); 
      if (cookie == null || token != null 
       && !token.equals(cookie.getValue())) { 
      cookie = new Cookie("XSRF-TOKEN", token); 
      cookie.setPath("/"); 
      response.addCookie(cookie); 
      } 
     } 
     filterChain.doFilter(request, response); 
     } 
    }; 
    } 

    private CsrfTokenRepository csrfTokenRepository() { 
    HttpSessionCsrfTokenRepository repository = new  HttpSessionCsrfTokenRepository(); 
    repository.setHeaderName("X-XSRF-TOKEN"); 
    return repository; 
    } 

} 

下面是使用無效的憑證錯誤的部分:安全配置的部分

2015-09-24 15:07:30.564 DEBUG 6552 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy  : /login at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter' 
2015-09-24 15:07:30.564 DEBUG 6552 --- [nio-8080-exec-3] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.se[email protected]44258b05 
2015-09-24 15:07:30.564 DEBUG 6552 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy  : /login at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter' 
2015-09-24 15:07:30.564 DEBUG 6552 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy  : /login at position 5 of 13 in additional filter chain; firing Filter: '' 
2015-09-24 15:07:30.564 DEBUG 6552 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy  : /login at position 6 of 13 in additional filter chain; firing Filter: 'LogoutFilter' 
2015-09-24 15:07:30.564 DEBUG 6552 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/login'; against '/logout' 
2015-09-24 15:07:30.580 DEBUG 6552 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy  : /login at position 7 of 13 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter' 
2015-09-24 15:07:30.580 DEBUG 6552 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/login'; against '/login' 
2015-09-24 15:07:30.580 DEBUG 6552 --- [nio-8080-exec-3] w.a.UsernamePasswordAuthenticationFilter : Request is to process authentication 
2015-09-24 15:07:30.580 DEBUG 6552 --- [nio-8080-exec-3] o.s.s.authentication.ProviderManager  : Authentication attempt using org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider 
2015-09-24 15:07:30.580 DEBUG 6552 --- [nio-8080-exec-3] ctiveDirectoryLdapAuthenticationProvider : Processing authentication request for user: admin 
2015-09-24 15:07:31.113 DEBUG 6552 --- [nio-8080-exec-3] ctiveDirectoryLdapAuthenticationProvider : Authentication for [email protected] failed:javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090334, comment: AcceptSecurityContext error, data 525, vece] 
2015-09-24 15:07:31.113 INFO 6552 --- [nio-8080-exec-3] ctiveDirectoryLdapAuthenticationProvider : Active Directory authentication failed: User was not found in directory 
2015-09-24 15:07:31.114 DEBUG 6552 --- [nio-8080-exec-3] w.a.UsernamePasswordAuthenticationFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials 
2015-09-24 15:07:31.114 DEBUG 6552 --- [nio-8080-exec-3] w.a.UsernamePasswordAuthenticationFilter : Updated SecurityContextHolder to contain null Authentication 
2015-09-24 15:07:31.114 DEBUG 6552 --- [nio-8080-exec-3] w.a.UsernamePasswordAuthenticationFilter : Delegating to authentication failure handler org.springframework.se[email protected]28626d9a 
2015-09-24 15:07:31.114 DEBUG 6552 --- [nio-8080-exec-3] .a.SimpleUrlAuthenticationFailureHandler : Redirecting to /login?error 
2015-09-24 15:07:31.115 DEBUG 6552 --- [nio-8080-exec-3] o.s.s.web.DefaultRedirectStrategy  : Redirecting to '/login?error' 
2015-09-24 15:07:31.115 DEBUG 6552 --- [nio-8080-exec-3] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession. 
2015-09-24 15:07:31.139 DEBUG 6552 --- [nio-8080-exec-3] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed 
2015-09-24 15:07:31.148 ERROR 6552 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception 

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) 
     at org.springframework.data.redis.core.AbstractOperations.rawHashValue(AbstractOperations.java:146) 
     at org.springframework.data.redis.core.DefaultHashOperations.putAll(DefaultHashOperations.java:128) 
     at org.springframework.data.redis.core.DefaultBoundHashOperations.putAll(DefaultBoundHashOperations.java:85) 
     at org.springframework.session.data.redis.RedisOperationsSessionRepository$RedisSession.saveDelta(RedisOperationsSessionRepository.java:409) 
     at org.springframework.session.data.redis.RedisOperationsSessionRepository$RedisSession.access$000(RedisOperationsSessionRepository.java:331) 
     at org.springframework.session.data.redis.RedisOperationsSessionRepository.save(RedisOperationsSessionRepository.java:211) 
     at org.springframework.session.data.redis.RedisOperationsSessionRepository.save(RedisOperationsSessionRepository.java:141) 
     at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.commitSession(SessionRepositoryFilter.java:193) 
     at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.access$100(SessionRepositoryFilter.java:169) 
     at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:127) 
     at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:65) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
     at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) 
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
     at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85) 
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
     at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:68) 
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) 
     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:142) 
     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:518) 
     at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) 
     at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668) 
     at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521) 
     at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478) 
     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: 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) 
     at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:34) 
     at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:50) 
     ... 40 common frames omitted 
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:497) 
     at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988) 
     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:44) 
     at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:62) 
     ... 42 common frames omitted 

回答

3

我想出瞭解決這個問題的辦法。我願意接受任何改善答案的建議。

該解決方案是不完整的,因爲我需要序列化時出現故障,所以我可以處理這個具體案件和所有其他扔SerializationException專門查找 com.sun.jndi.ldap.LdapCtx類型。但我認爲這個總體想法可能對任何被阻止的人有用。

現在,當使用無效證書(例如錯誤的用戶名或密碼不正確)的應用程序返回到登錄頁面,而不是炸燬:)

我加了一些RedisConfigurationRedisTemplate春季會議是使用來代替。

import com.gateway.utils.LdapFailAwareRedisObjectSerializer; 

@Configuration 
public class RedisConfiguration { 

    @Primary 
    @Bean 
    public RedisTemplate<String,ExpiringSession> redisTemplate(RedisConnectionFactory connectionFactory) { 
    RedisTemplate<String, ExpiringSession> template = new RedisTemplate<String, ExpiringSession>(); 

    template.setKeySerializer(new StringRedisSerializer()); 
    template.setHashKeySerializer(new StringRedisSerializer()); 
    template.setHashValueSerializer(new LdapFailAwareRedisObjectSerializer()); 

    template.setConnectionFactory(connectionFactory); 
    return template; 
    } 
} 

這是我實現RedisSerializer<Object>LdapFailAwareRedisObjectSerializer這是從here GOT)

public class LdapFailAwareRedisObjectSerializer implements RedisSerializer<Object> { 

    private Converter<Object, byte[]> serializer = new SerializingConverter(); 
    private Converter<byte[], Object> deserializer = new DeserializingConverter(); 

    static final byte[] EMPTY_ARRAY = new byte[0]; 

    public Object deserialize(byte[] bytes) { 
    if (isEmpty(bytes)) { 
     return null; 
    } 

    try { 
     return 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); 
    } 
} 
1

使用 org.springframework.core.serializer.support.DeserializingConverter的班後,此只是工作對我很好 and org.springframework.core.serializer.support.SerializingConverter

/** 
* @author Meron Abraha 12/18/17 
*/ 

public class CustomRedisSerializer implements RedisSerializer<Object> { 

private Converter<Object, byte[]> serializer = new SerializingConverter(); 
private Converter<byte[], Object> deserializer = new DeserializingConverter(); 

static final byte[] EMPTY_ARRAY = new byte[0]; 

public Object deserialize(byte[] bytes) { 
    if (isEmpty(bytes)) { 
     return null; 
    } 

    try { 
     return 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; 

    } 
} 

private boolean isEmpty(byte[] data) { 
    return (data == null || data.length == 0); 
} 
}