Java – spring security – access-denied-handler

javaspringspring-mvcspring-security

I have some problems with Spring Security and getting an access-denied-handler to work.

Spring security is working but when I visit /admin without the required privileges (ROLE_ADMIN), Spring Security is just redirecting to the root page which is my login form page.

I want to be able to redirect the user to /accessdenied or /?accessdenied=true which should load the login page and display the following message: "Permission denied – please login"

spring-security.xml:

<beans:beans 
    xmlns:security="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                    http://www.springframework.org/schema/security 
                    http://www.springframework.org/schema/security/spring-security-3.1.xsd">


    <security:http>
        <security:intercept-url pattern='/home' access='ROLE_USER,ROLE_ADMIN' />
        <security:intercept-url pattern='/admin*' access='ROLE_ADMIN' />
        <security:form-login login-page='/' default-target-url='/home' authentication-failure-url='/?error=true' />
        <security:logout logout-success-url='/' />
        <security:access-denied-handler error-page="/accessdenied"/>
    </security:http>
    <security:authentication-manager>
        <security:authentication-provider>
            <security:user-service>
                <security:user name='a' password='a' authorities='ROLE_ADMIN,ROLE_USER' />
                <security:user name='u' password='u' authorities='ROLE_USER' />
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>
</beans:beans>

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
        /WEB-INF/spring/root-context.xml 
        /WEB-INF/spring/spring-security.xml
        </param-value>
    </context-param>

    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Processes application requests -->
    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

  <!-- Spring Security -->  
  <filter>  
    <filter-name>springSecurityFilterChain</filter-name>  
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  </filter>  
  <filter-mapping>  
    <filter-name>springSecurityFilterChain</filter-name>  
    <url-pattern>/*</url-pattern>  
  </filter-mapping>  
  <welcome-file-list>  
    <welcome-file>login.jsp</welcome-file>  
  </welcome-file-list>  

</web-app>

LoginController.java
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class LoginController {

    private static final Logger logger = LoggerFactory.getLogger(LoginController.class);

    /**
     * Simply selects the home view to render by returning its name.
     */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Locale locale, Model model) 
    {
        logger.info("Welcome home! The client locale is {}.", locale);

        return "login";
    }

    @RequestMapping(value = "/accessdenied", method = RequestMethod.GET)
    public String accessDenied(Locale locale, Model model) 
    {
        logger.info("Welcome home! The client locale is {}.", locale);

        model.addAttribute("message", "Permission denied - please login");

        return "login";
    }
}

I have tried several guides including the following, and none of it worked:

http://www.mkyong.com/spring-security/customize-http-403-access-denied-page-in-spring-security/
access denied page using spring security not working
How to redirect to access-denied-page with spring security

Any help would be greatly appreciated.

Best Answer

Can you please check the logs and confirm in your case AuthenticationException is getting thrown or AccessDeniedException when you visit /admin page.

Also you visit admin page with a correct login not having admin privileges or you visit it without login at all ?

Editted:

  1. Can you check by adding some log statement or debug that when you access /admin with a correct login (not having admin priv), is the method accessDenied() getting called ?
  2. Also can you share your login jsp, you might not have displayed message param correctly
  3. When user doesn't have required priv but is a valid user then accessDeniedHandler is called, you can see something like this in debug logs

access is denied (user is not anonymous); delegating to AccessDeniedHandler

AccessDeniedHndler will forward the request to errorPage (Its not a redirect)