3

Spring 3.2 Milestone 1 を使用して、long pollingを使用するサービスを実装しています。ただし、何らかの理由で、Spring Security (3.1.2) は、最初の延期された結果が期限切れになる (asynctimeout に達し、Tomcat が http.200 で応答する) か、何らかの応答がクライアントに返された直後に SPRING_SECURITY_CONTEXT をクリアします。Spring Security 3.1.0 を使用すると、これは特定の状況 (HTTPS およびクライアントが何らかのハードウェア ファイアウォールの背後にある) でのみ発生しますが、3.1.2 では常に発生します (最初の DefferedResult が満たされた後)!

ログの関連部分のデバッグ出力は次のとおりです。

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: 'org.springframework.security.core.context.SecurityContextImpl@fc783ee2: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@fc783ee2: Principal: org.springframework.security.core.userdetails.User@33ca09: Username: nvrs; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@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.springframework.security.authentication.UsernamePasswordAuthenticationToken@fc783ee2: Principal: org.springframework.security.core.userdetails.User@33ca09: Username: nvrs; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@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.springframework.security.authentication.UsernamePasswordAuthenticationToken@fc783ee2: Principal: org.springframework.security.core.userdetails.User@33ca09: Username: nvrs; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@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.springframework.security.authentication.UsernamePasswordAuthenticationToken@fc783ee2: Principal: org.springframework.security.core.userdetails.User@33ca09: Username: nvrs; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@0: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 46EC76439E921FE347EC48ECF71C1258; Granted Authorities: ADMIN
DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@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: org.apache.catalina.session.StandardSessionFacade@61ed10f7. A new one will be created.

出力を注意深く見ると、最初の長いポーリング リクエスト「/updates/events?」が表示されます。正しく処理されます-アクセスが許可されますが、その後、「HttpSessionがSPRING_SECURITY_CONTEXTのnullオブジェクトを返しました」という行からわかるように、最初のURLが期限切れになった後、またはイベントは非空応答をトリガーします。ここで指摘したいのは、すべてのカスタム フィルターが無効になっており、ロング ポーリング リクエストを処理するときに、アクセスするためのキーとして sessionId-clientid (ページ インスタンスのブラウザー タブごとに一意) を使用して、DeferedResult を Map に保存し、 JMS メッセージを受信した場合にクライアントに結果を送信します。

この問題は、Spring フレームワーク 3.2 M1 および最新の 3.2 スナップショット ビルドと、Spring Security 3.1.2 または Tomcat 7.0.28 / 7.0.29 (デフォルト コネクタと APR コネクタの両方) でのそれぞれの最新スナップショットとの組み合わせに存在します。

4

2 に答える 2

3

デバッガーの助けを借りて、次の結論に達しました。

DefferedResult が設定された後、 get のメソッドが呼び出され、プロキシ経由でflush()が呼び出されます。org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrappersaveContext()org.springframework.security.web.context.HttpSessionSecurityContextRepository

@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;
    }

認証オブジェクトが null であるため (Spring セキュリティ コンテキストがクリアされているため)、行 httpSession.removeAttribute(springSecurityContextKey) はセッションから SPRING_SECURITY_CONTEXT を削除し、ユーザーが行う次のリクエストはセキュリティ コンテキストのないセッションになります。したがって、ユーザーはログインにリダイレクトされます。ここで明らかな何かが欠けていない限り、これは非同期リクエストの取引ブレーカーです。Spring Security チームがこの問題を認識しているかどうか、また 3.2 がリリースされる前に修正する予定があるかどうかは疑問です。それまでの間、適切な回避策について何か提案はありますか?

編集:現時点では、一時的な解決策として、非同期リクエストの場合はセッションを編集しないことで問題に対処しています。具体的には、securityContext をいつフラッシュするかのチェックを変更しました。

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

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

ありがとう

于 2012-09-03T09:29:53.227 に答える
0

サーバー側でフォークされたスレッドを使用していますか?

forked threadsレスポンスとやり取りしたために、セキュリティ コンテキストがクリアされるという同様の問題がありました。セキュリティ コンテキストはthread local変数であり、デフォルトでは fork されたスレッドと共有されません ( docを参照)。

strategyを に設定することで、この問題を修正しSecurityContextHolderましたMODE_INHERITABLETHREADLOCAL

春のセキュリティ設定 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>

2016 年 10 月 31 日更新:

を使用INHERITABLETHREADLOCALすると、スレッド プールを使用する環境 (Tomcat など) で ThreadLocal リークが発生する可能性があります。DelegatingSecurityContextRunnableフォークされたスレッドが正しい Spring セキュリティ コンテキストを確実に取得するようにする他の方法 ( を使用するなど) もあります。同時実行サポートを参照してください。

于 2015-12-22T07:31:50.180 に答える