Announcement Announcement Module
Collapse
No announcement yet.
access-denied-handler problem Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • access-denied-handler problem

    Hello! I've added Spring Security to my application, but I have a little problem.
    I set a custom "access denied page" which is accessDenied.jsp,
    The redirection works BUT the URL in the browser's address bar doesn't change into the "access denied" page; because of this, the links in the accessDenied.jsp page don't work.
    Can someone help me sort this out?

    Here is the interested piece of applicationContext.xml.

    Code:
    <sec:http auto-config="true">
        <sec:intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
        <sec:intercept-url pattern="/member/**" access="ROLE_MEMBER,ROLE_ADMIN" />
        <sec:form-login login-page="/login.jsp" default-target-url="/index.jsp" 
                             authentication-failure-url="/loginfail.jsp"/>
        <sec:access-denied-handler error-page="/accessDenied.jsp"/>
    </sec:http>

  • #2
    If you want the URL to change, use an AccessDeniedHandler which performs a redirect, rather than a forward (as the default one does). Use the "ref" attribute to point to a bean which implements the AccessDeniedHandler interface.

    Comment


    • #3
      Originally posted by Luke Taylor View Post
      If you want the URL to change, use an AccessDeniedHandler which performs a redirect, rather than a forward (as the default one does). Use the "ref" attribute to point to a bean which implements the AccessDeniedHandler interface.
      Thanks! I followed your advice and it worked!

      Here are the modifications I made, hoping they will be useful to whoever has my same problem.

      Excerpt from applicationcontext.xml:

      Code:
      <!-- ========================= SECURITY ======================== -->
      
      <sec:http auto-config="true">
      <!--		<sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />-->
      	<sec:intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
      	<sec:intercept-url pattern="/member/**" access="ROLE_MEMBER,ROLE_ADMIN" />
      	<sec:form-login login-page="/login.jsp" default-target-url="/index.jsp" authentication-failure-url="/loginfail.jsp"/>
      	<sec:access-denied-handler ref ="myAccessDeniedHandlerImpl"/>
      	<!-- <sec:logout logout-success-url="/index.jsp" /> -->
      </sec:http>
      	
      <!-- 
      	This is a modified AccessDeniedHandler that performs a redirect instead of a forward.
      	This way, the address bar updates to the access denied page's URL.
       -->
      <bean id="myAccessDeniedHandlerImpl" class="sst.MyAccessDeniedHandlerImpl">
      	<property name="errorPage" value="/accessDenied.jsp"/>
      </bean>
      Here is my implementation of codeAccessDeniedHandler:

      Code:
      package org.springframework.security.web.access.;
      
      import java.io.IOException;
      
      import javax.servlet.RequestDispatcher;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      
      import org.apache.commons.logging.Log;
      import org.apache.commons.logging.LogFactory;
      import org.springframework.security.access.AccessDeniedException;
      import org.springframework.security.web.WebAttributes;
      import org.springframework.security.web.access.AccessDeniedHandler;
      
      
      /**
       * Implementation of {@link AccessDeniedHandler}.
       * <p>
       * This implementation sends a 403 (SC_FORBIDDEN) HTTP error code. In addition, if an {@link #errorPage} is defined,
       * the implementation will perform a request dispatcher "redirect" (instead of "forward") to the specified error page view.
       * Being a "redirect", the <code>SecurityContextHolder</code> won't remain
       * populated. This is of detriment if the view (or a tag library or macro) wishes to access the
       * <code>SecurityContextHolder</code>. The request scope will also be populated with the exception itself, available
       * from the key {@link WebAttributes.ACCESS_DENIED_403}.
       *
       * @author Luca
       */
      @SuppressWarnings("unused")
      public class MyAccessDeniedHandlerImpl implements AccessDeniedHandler {
          //~ Static fields/initializers =====================================================================================
          /**
           * @deprecated Use the value in {@link WebAttributes} directly.
           */
          @Deprecated
          public static final String SPRING_SECURITY_ACCESS_DENIED_EXCEPTION_KEY = WebAttributes.ACCESS_DENIED_403;
          protected static final Log logger = LogFactory.getLog(MyAccessDeniedHandlerImpl.class);
      
          //~ Instance fields ================================================================================================
      
          private String errorPage;
      
          //~ Methods ========================================================================================================
      
          public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException)
                  throws IOException, ServletException {
              if (!response.isCommitted()) {
                  if (errorPage != null) {
                      // Put exception into request scope (perhaps of use to a view)
                      request.setAttribute(WebAttributes.ACCESS_DENIED_403, accessDeniedException);
      
                      // Set the 403 status code.
                      response.setStatus(HttpServletResponse.SC_FORBIDDEN);
      
                      // redirect to error page.
                      
                      /*
                       * This is the original code from the default 
                       * org.springframework.security.web.access.AccessDeniedHandlerImpl, 
                       * which performs a forward:
                       */
                      //RequestDispatcher dispatcher = request.getRequestDispatcher(errorPage);
                      //dispatcher.forward(request, response);
                      
                      /*
                       * This is my code that performs a redirect:
                       */
                      response.sendRedirect(request.getContextPath()+errorPage);
                  } else {
                      response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());
                  }
              }
          }
      
          /**
           * The error page to use. Must begin with a "/" and is interpreted relative to the current context root.
           *
           * @param errorPage the dispatcher path to display
           *
           * @throws IllegalArgumentException if the argument doesn't comply with the above limitations
           */
          public void setErrorPage(String errorPage) {
              if ((errorPage != null) && !errorPage.startsWith("/")) {
                  throw new IllegalArgumentException("errorPage must begin with '/'");
              }
      
              this.errorPage = errorPage;
          }
      }

      Comment


      • #4
        Wouldn't it be better if we have a declarative attribute to specify if we want to forward or redirect instead of implementing a new interface just to redirect?

        Comment


        • #5
          Originally posted by skram View Post
          Wouldn't it be better if we have a declarative attribute to specify if we want to forward or redirect instead of implementing a new interface just to redirect?
          I totally agree!

          Comment


          • #6
            Most of the code copied from AccessDeniedHandlerImpl is redundant here - there is no point in storing the exception as a request attribute or setting the response code if you are doing a redirect.

            Alternatively could also just make sure you render the links in your error page using non-relative paths.

            Comment

            Working...
            X