Results 1 to 9 of 9

Thread: SecurityContextHolderAwareRequestFilter/Wrapper improvements

  1. #1
    Join Date
    Dec 2005
    Location
    Oslo, Norway
    Posts
    15

    Default SecurityContextHolderAwareRequestFilter/Wrapper improvements

    I had to rewrite these classes in order to meet two requirements, and I want to know if these are of general interest:

    • Add a property 'rolePrefix' to SecurityContextHolderAwareRequestFilter. This is passed on to the SecurityContextHolderAwareRequestWrapper. The prefix, if set, is prepended to the role name before comparison in the isUserInRole method. For example, if set to 'ROLE_', It allows you to write
      Code:
      request.isUserInRole("Admin")
      insted of
      Code:
      request.isUserInRole("ROLE_Admin")
    • We use the <error-page> mechanism to display errors in the web application. At least in Tomcat, and when Acegi is configured to use a <url-pattern> for the filter mapping, the Acegi filters bypassed when the error page is rendered. If you use the HttpSessionContextIntegrationFilter in your filter chain, the SecurityContext is gone when you render the error page.

      I solved this problem by putting the SecurityContext as an attribute of the HttpServletRequest. This is done in the SecurityContextHolderAwareRequestFilter when it wraps the request (although this could perhaps be refactored out into a separate filter). When the wrapper tries to find the Authetication object, and none is found in the SecurityContextHolder, it tries the request attribute to see if it is there before giving up and returning null.


    Comments?

  2. #2
    Join Date
    Dec 2005
    Location
    Oslo, Norway
    Posts
    15

    Default

    Quote Originally Posted by Rolf Arne Corneliussen
    I had to rewrite these classes in order to meet two requirements, and I want to know if these are of general interest:

    • We use the <error-page> mechanism to display errors in the web application. At least in Tomcat, and when Acegi is configured to use a <url-pattern> for the filter mapping, the Acegi filters bypassed when the error page is rendered. If you use the HttpSessionContextIntegrationFilter in your filter chain, the SecurityContext is gone when you render the error page.

      I solved this problem by putting the SecurityContext as an attribute of the HttpServletRequest. This is done in the SecurityContextHolderAwareRequestFilter when it wraps the request (although this could perhaps be refactored out into a separate filter). When the wrapper tries to find the Authetication object, and none is found in the SecurityContextHolder, it tries the request attribute to see if it is there before giving up and returning null.
    When using servlet specification 2.4, this can probably be solved by specifying a filter chain with a HttpSessionContextIntegrationFilter and a SecurityContextHolderAwareRequestFilter to handle the error page resources. To ensure this happens, use a <dispatcher>ERROR</dispatcher> element inside the <filter-mapping> element.

    Anyway, is there something unsecure or 'wrong' with storing the security context as an attribute in the HttpServletrequest?

  3. #3
    Join Date
    Aug 2004
    Location
    Sydney, Australia
    Posts
    2,768

    Default

    I can't see any problem with storing it in the HttpServletRequest for use by error pages and alike.
    Ben Alex
    Project Founder, Spring UAA, Spring Roo and Spring Security

  4. #4
    Join Date
    May 2006
    Posts
    1

    Default

    Rolf, I am interested in knowing more about the classes involved in this...would it be convenient for you to email me the classes, web.xml, and applicationContext-whatever.xml?

    Would greatly appreciate it.

    -Ro

  5. #5
    Join Date
    Dec 2005
    Location
    Oslo, Norway
    Posts
    15

    Default

    Quote Originally Posted by rpaul
    Rolf, I am interested in knowing more about the classes involved in this...would it be convenient for you to email me the classes, web.xml, and applicationContext-whatever.xml?

    Would greatly appreciate it.

    -Ro
    I'm sorry I cannot do that for different reasons. However, I can create JIRA issues for the two points mentioned here:

    * Add a 'rolePrefix' property to the SecurityContextHolderAwareRequestFilter

    * Ensure the existence of a SecurityContext when rendering error pages.

  6. #6
    Join Date
    Dec 2005
    Posts
    19

    Default Dispatcher

    Hi

    I tried the dispatcher suggestion from above and it work great on my error page.
    Unfortunetly now it dosen't work on my other normal pages.
    Code:
    <filter-mapping>
    		<filter-name>Acegi Filter Chain Proxy</filter-name>
    		<url-pattern>/*</url-pattern>
    	
    <!--		<dispatcher>FORWARD</dispatcher>-->
    <!--		<dispatcher>INCLUDE</dispatcher>-->
    <!--		<dispatcher>ERROR</dispatcher>-->
    		<dispatcher>REQUEST</dispatcher>
    	</filter-mapping>
    With request on, it works on normal pages.
    with error on and the other two without request it works on error pages.
    with all on it works on normal pages but not error pages.

    Any ideas?

  7. #7
    Join Date
    Dec 2005
    Location
    Oslo, Norway
    Posts
    15

    Default

    Quote Originally Posted by warer
    Hi

    I tried the dispatcher suggestion from above and it work great on my error page.
    Unfortunetly now it dosen't work on my other normal pages.
    Code:
    <filter-mapping>
    		<filter-name>Acegi Filter Chain Proxy</filter-name>
    		<url-pattern>/*</url-pattern>
    	
    <!--		<dispatcher>FORWARD</dispatcher>-->
    <!--		<dispatcher>INCLUDE</dispatcher>-->
    <!--		<dispatcher>ERROR</dispatcher>-->
    		<dispatcher>REQUEST</dispatcher>
    	</filter-mapping>
    With request on, it works on normal pages.
    with error on and the other two without request it works on error pages.
    with all on it works on normal pages but not error pages.

    Any ideas?
    According to the servlet specification, a single dispatcher element with value REQUEST is equivalent to having none, so the correct configuration is

    Code:
    <dispatcher>ERROR</dispatcher>
    <dispatcher>REQUEST</dispatcher>
    I believe the reason it does not work is that the HttpSessionContextIntegrationFilter is not designed to work with error pages, because it is designed to be applied only one per request. I have not got around to file a Jira issue for this yet, but I will.

    Lets take the simple example that you have set up an error page config for handling authrorization failures, like

    Code:
    <error-page>
       <error-code>403</error-code>
       <location>/unauthorized.jsp</location>
    </error-page>
    If a user lacks a required role, ExceptionTranslationFilter by default issues a sendError on the response. When the request processing returns up the filter chain, it eventually reaches the HttpSessionContextIntegrationFilter and it executes

    Code:
    // Remove SecurityContextHolder contents
    SecurityContextHolder.clearContext();
    When the container finds out that it should generate an error page, it is filtered though acegi (because of the <dispatcher>ERROR</dispatcher> element). When the HttpSessionContextIntegrationFilter is invoked for the second time on the same request, it just passes control down the filter chain without setting the proper security context. The code snippet below from HttpSessionContextIntegrationFilter explains the behaviour
    Code:
    if ((request != null) && (request.getAttribute(FILTER_APPLIED) != null)) {
       // ensure that filter is only applied once per request
       chain.doFilter(request, response);
    } else {
       if (request != null) {
          request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
       }
       <normal processing of session context integration>
    I would suggest that the attribute is set to null when the context is cleared, like

    Code:
    // Remove SecurityContextHolder contents
    SecurityContextHolder.clearContext();
    request.setAttribute(FILTER_APPLIED, null);
    But I really do not know the ramifications of this, and the Acegi team may know a better solution.


    A safe workaournd would be to write a simple filter

    Code:
    public class RemoveFilterAppliedFilter implements Filter {
    
       public void init( FilterConfig filterConfig ) throws ServletException {}
    
       public void doFilter( ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain ) throws IOException, ServletException {
          servletRequest.setAttribute( "__acegi_session_integration_filter_applied", null );
          filterChain.doFilter( servletRequest, servletResponse );
       }
    
       public void destroy() {}
    
    }
    Then in web.xml, set up the filter
    Code:
    <filter>
       <filter-name>ErrorPageFilter</filter-name>
       <filter-class>RemoveFilterAppliedFilter</filter-class>
    </filter>
    and place if BEFORE acegi filter (also in web.xml)

    Code:
    <filter-mapping>
       <filter-name>ErrorPageFilter</filter-name>
       <url-pattern>/*</url-pattern>
       <dispatcher>ERROR</dispatcher>
    </filter-mapping>
    
    <filter-mapping>
       <filter-name>AcegiFilterChainProxy</filter-name>
       <url-pattern>/*</url-pattern>
       <dispatcher>REQUEST</dispatcher>
       <dispatcher>ERROR</dispatcher>
    </filter-mapping>

    Cheers,

    Rolf Arne

  8. #8
    Join Date
    Dec 2005
    Location
    Oslo, Norway
    Posts
    15

    Default

    I've finally filed the Jira issues. SEC-302 and SEC-305.

  9. #9
    Join Date
    Dec 2005
    Posts
    19

    Default

    Thanks for the workaround, it works.
    Hope they fix this in 1.1 release.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •