Results 1 to 6 of 6

Thread: access-denied-handler problem

  1. #1
    Join Date
    Jan 2011
    Posts
    4

    Default 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. #2
    Luke Taylor is offline Senior Member Acegi Security System TeamSpring Team
    Join Date
    Aug 2004
    Location
    Glasgow, Scotland
    Posts
    3,449

    Default

    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.
    Spring - by Pivotal
    twitter @tekul

  3. #3
    Join Date
    Jan 2011
    Posts
    4

    Default

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

  4. #4
    Join Date
    Dec 2010
    Posts
    315

    Default

    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?

  5. #5
    Join Date
    Jan 2011
    Posts
    4

    Default

    Quote 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!

  6. #6
    Luke Taylor is offline Senior Member Acegi Security System TeamSpring Team
    Join Date
    Aug 2004
    Location
    Glasgow, Scotland
    Posts
    3,449

    Default

    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.
    Spring - by Pivotal
    twitter @tekul

Tags for this Thread

Posting Permissions

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