2012-09-02 2 views
3

long polling으로 서비스를 구현하기 위해 Spring 3.2 Milestone 1을 사용하고 있습니다. 그러나 Spring Security (3.1.2)는 첫 번째 결과가 만료되거나 (asynctimeout에 도달하고 tomcat이 http.200으로 응답 한) 즉시 SPRING_SECURITY_CONTEXT를 지우거나 일부 응답이 클라이언트로 다시 전송됩니다. Spring Security 3.1.0을 사용하면 HTTPS와 클라이언트가 하드웨어 방화벽 뒤에있는 특정 상황에서만 발생하지만 3.1.2에서는 항상 발생합니다 (첫 번째 DefferedResult가 완료된 후). 당신이 첫 번째 긴 폴링 요청에 표시되는 출력을주의 깊게 보면 여기 Spring 3.2 SPRING_SECURITY_CONTEXT를 지우는 긴 폴링

로그

DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/updates/events'; against '/login*' 
DEBUG: org.springframework.security.web.FilterChainProxy - /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481959526 at position 1 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: '[email protected]783ee2: Authentication: org.springframew[email protected]fc783ee2: Principal: [email protected]: Username: nvrs; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]0: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 46EC76439E921FE347EC48ECF71C1258; Granted Authorities: ADMIN' 
DEBUG: org.springframework.security.web.FilterChainProxy - /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481959526 at position 2 of 11 in additional filter chain; firing Filter: 'LogoutFilter' 
DEBUG: org.springframework.security.web.FilterChainProxy - /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481959526 at position 3 of 11 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter' 
DEBUG: org.springframework.security.web.FilterChainProxy - /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481959526 at position 4 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter' 
DEBUG: org.springframework.security.web.FilterChainProxy - /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481959526 at position 5 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter' 
DEBUG: org.springframework.security.web.FilterChainProxy - /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481959526 at position 6 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' 
DEBUG: org.springframework.security.web.FilterChainProxy - /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481959526 at position 7 of 11 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter' 
DEBUG: org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter - SecurityContextHolder not populated with remember-me token, as it already contained: 'org.springframew[email protected]fc783ee2: Principal: [email protected]: Username: nvrs; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]0: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 46EC76439E921FE347EC48ECF71C1258; Granted Authorities: ADMIN' 
DEBUG: org.springframework.security.web.FilterChainProxy - /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481959526 at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter' 
DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframew[email protected]fc783ee2: Principal: [email protected]: Username: nvrs; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]0: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 46EC76439E921FE347EC48ECF71C1258; Granted Authorities: ADMIN' 
DEBUG: org.springframework.security.web.FilterChainProxy - /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481959526 at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter' 
DEBUG: org.springframework.security.web.FilterChainProxy - /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481959526 at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' 
DEBUG: org.springframework.security.web.FilterChainProxy - /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481959526 at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' 
DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/updates/events'; against '/updates/**' 
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481959526; Attributes: [hasAnyRole('ADMIN','MANAGER','INTERNAL')] 
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: org.springframew[email protected]fc783ee2: Principal: org.springframework.sec[email protected]: Username: nvrs; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]0: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 46EC76439E921FE347EC48ECF71C1258; Granted Authorities: ADMIN 
DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: org.sp[email protected]52bf21bf, returned: 1 
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Authorization successful 
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - RunAsManager did not change Authentication object 
DEBUG: org.springframework.security.web.FilterChainProxy - /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481959526 reached end of additional filter chain; proceeding with original chain 
DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally 
DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed 
DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally 
DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed 
DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally 
DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed 
DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/updates/events'; against '/login*' 
DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/updates/events'; against '/resources/css/**' 
DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/updates/events'; against '/resources/images/**' 
DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/updates/events'; against '/resources/*' 
DEBUG: org.springframework.security.web.FilterChainProxy - /updates/events?clientId=nvrs1346481959144&timestamp=0&_=1346481985081 at position 1 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT 
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: [email protected] A new one will be created. 

의 관련 부분의 디버그 출력 "/ 업데이트/이벤트를?" 액세스가 허용되지만 그 이후에는 "HttpSession이 SPRING_SECURITY_CONTEXT에 대해 null 객체를 반환했습니다"라는 줄에서 볼 수 있듯이 봄 보안 컨텍스트가 지워집니다.이 객체는 처음 URL이 만료 된 후 클라이언트가 해당 URL에 대한 다른 요청에 의해 트리거됩니다. 이벤트가 비 emty 응답을 트리거합니다. 나는 모든 사용자 지정 필터가 비활성화되어 있고 긴 폴링 요청을 처리 할 때 SessionId-clientid (각 페이지 인스턴스 브라우저 탭마다 고유 한)로 액세스 할 수있는 키로 DefferedResult를 저장한다고 지적하고 싶습니다. 및 JMS 메시지가 수신되는 경우에 클라이언트에 결과를 전송하는 단계를 포함하는 방법.

이 문제점은 스프링 보안 3.1.2 또는 톰캣 7.0.28/7.0.29 (최신 및 APR 커넥터 모두)의 최신 스냅 샷과 함께 최신 3.2 스냅 샷 빌드에 존재합니다. 나는 다음과 같은 결론에 도달 한 디버거의 도움으로

+0

여기에는 이상한 것도 증거가 없습니다 (아래 답변에 해당하지 않음). 더 많은 가능성있는 설명은 어떤 이유로 (예 : HTTP/HTTPS 사이의 전환으로 인해) 세션이 손실되어 null 컨텍스트가 발생한다는 것입니다. 이것이 사실이 아니라는 것을 증명해야합니다. –

+0

나는 확실히 HTTP와 HTTPS 사이를 전환하지 않는다. 내가 말하는 것을 보여주기 위해 더 적절한 것을 만들려고합니다. – nvrs

답변

3

:

DefferedResult 후에는 프록시를 통해 org.springframework.security.web.context.HttpSessionSecurityContextRepositorysaveContext()를 호출 org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapperflush()가 호출되는 방법을 설정한다.

@Override 
protected void saveContext(SecurityContext context) { 
    final Authentication authentication = context.getAuthentication(); 
    HttpSession httpSession = request.getSession(false); 

    // See SEC-776 
    if (authentication == null || authenticationTrustResolver.isAnonymous(authentication)) { 
     if (logger.isDebugEnabled()) { 
      logger.debug("SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession."); 
     } 

     if (httpSession != null && !contextObject.equals(contextBeforeExecution)) { 
      // SEC-1587 A non-anonymous context may still be in the session 
      // SEC-1735 remove if the contextBeforeExecution was not anonymous 
      httpSession.removeAttribute(springSecurityContextKey); 
     } 
     return; 
    } 

인증 개체는 광고 httpSession.removeAttribute (springSecurityContextKey) (인해 스프링 보안 콘텍스트가 삭제되었다는 사실) 널 세션 및 사용자 만드는 다음 요청에서 SPRING_SECURITY_CONTEXT 제거 때문에 보안 컨텍스트없이 세션을 생성하므로 사용자가 로그인으로 리디렉션됩니다. 여기에 분명하지 않은 것이 없으면 비동기 요청에 대한 거래 차단기입니다. Spring Security 팀이이 문제점을인지하고 있으며, 3.2가 출시되기 전에이를 고칠 계획이 있는지 궁금합니다. 그 동안 적절한 해결 방법에 대한 제안 사항이있는 사람이 있습니까?

편집 : 임시 해결책으로 비동기 요청의 경우 세션을 편집하지 않음으로써 문제를 처리합니다.

if (httpSession != null && !contextObject.equals(contextBeforeExecution)) 

감사

+0

"인증 개체가 null입니다"라고 말하면됩니다. 이 요청 중에 문맥이 삭제 된 이유는 무엇입니까? 보안 컨텍스트는 쓰레드 로컬 객체라는 것을 기억하십시오. 이것은 아마도 대답이 아닌 질문의 일부가되어야합니다. –

+0

보안 컨텍스트는 스레드 로컬이며 비동기 요청이 저장 될 때 저장되지 않는다고 말할 수있는 범위까지 말합니다. 그러므로 asyn 컨텍스트가 재개 될 때, 인증 객체는 null이다. – nvrs

+0

당신이 명확하게 그 문제를 보여줄 수 있다면, 아마도 SO보다는 Spring Issue Tracker에서 더 잘 처리 될 수있는 것처럼 들린다. 나는 거기에 문제를 열어. –

0

서버 측에서 포크 스레드를 사용하고

if (httpSession != null && !contextObject.equals(contextBeforeExecution) && this.request.getAttribute("javax.servlet.async.request_uri") == null) 

에 : 특히 나는 경우에서 SecurityContext에 플러시하는 수표를 수정?

forked threads이 응답과 상호 작용했기 때문에 비슷한 보안 문맥 문제가 해결되었습니다. 보안 컨텍스트는 thread local이며 기본적으로 분기 된 스레드와 공유되지 않습니다 (doc 참조).

봄 보안 구성 XML :

<beans:bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> 
    <property name="targetClass" value="org.springframework.security.core.context.SecurityContextHolder" /> 
    <property name="targetMethod" value="setStrategyName" /> 
    <property name="arguments" value="MODE_INHERITABLETHREADLOCAL" /> 
</beans:bean> 

UPDATE 2016년 10월 31일 :

우리는 SecurityContextHolder MODE_INHERITABLETHREADLOCAL에의 strategy을 설정하여이 문제를 해결

가 발생할 수 있습니다 INHERITABLETHREADLOCAL 사용 스레드 풀 (예 : Tomcat)을 사용하는 환경에서 ThreadLocal이 누출됩니다. 다른 방법 (예 : DelegatingSecurityContextRunnable)을 사용하면 fork 된 스레드가 올바른 Spring 보안 컨텍스트를 갖도록 할 수 있습니다. Concurrency Support을 참조하십시오.