I can’t understand why my security doesn’t work properly. Method hasPermission() in Evaluator class not even called. I think there is something wrong with my security config.
My Security config:
<?xml version="1.0" encoding="UTF-8"?>
<bean:beans xmlns:bean="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<sec:http use-expressions="true">
<sec:intercept-url pattern="/favicon.ico" access="permitAll"/>
<sec:intercept-url pattern="/resources/**" access="permitAll"/>
<sec:intercept-url pattern="/login" access="permitAll"/>
<sec:form-login login-page="/login"
username-parameter="login"
password-parameter="password"
authentication-failure-url="/login?error"
authentication-success-handler-ref="successHandler"/>
<sec:logout logout-url="/logout" logout-success-url="/login?logout"/>
<sec:access-denied-handler error-page="/WEB-INF/views/error/403.jsp"/>
</sec:http>
<sec:authentication-manager>
<sec:authentication-provider ref="userAuthenticationProvider"/>
</sec:authentication-manager>
<sec:global-method-security pre-post-annotations="enabled" secured-annotations="enabled">
<sec:expression-handler ref="expressionHandler"/>
</sec:global-method-security>
<bean:bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<bean:property name="permissionEvaluator" ref="permissionEvaluator"/>
</bean:bean>
<bean:bean id="permissionEvaluator" class="de.mark.project.security.UserPermissionEvaluator">
<bean:constructor-arg ref="userSecurityService"/>
</bean:bean>
<bean:bean id="successHandler" class="de.mark.project.security.UrlAuthenticationSuccessHandler"/>
<bean:bean id="userSecurityService" class="de.mark.project.service.UserService"/>
<bean:bean name="userAuthenticationProvider" class="de.mark.project.security.UserAuthenticationProvider">
<bean:constructor-arg ref="userSecurityService"/>
</bean:bean>
</bean:beans>
Here is my custom evaluator:
public class UserPermissionEvaluator implements PermissionEvaluator {
private UserService service;
@Autowired
public UserPermissionEvaluator(UserService service) {
this.service = service;
}
@Override
public boolean hasPermission(Authentication authentication,
Serializable targetId, String targetType,
Object permission) {
UserDetails principal = (UserDetails) authentication.getPrincipal();
User authorizedUser = service.getUser(principal.getUsername());
Collection<Permission> userPermissions = authorizedUser.getPermissions();
for (Permission p : userPermissions) {
if (p.getName().equals(allowedPermission)) {
return true;
}
}
return false;
}
@Override
public boolean hasPermission(Authentication authentication,
Serializable targetId, String targetType,
Object permission) {
throw new RuntimeException("Error");
}
}
Method in the controller which using security:
@RequestMapping(method = RequestMethod.GET)
@PreAuthorize("hasPermission(null, 'create_user')")
public String createUserForm(@ModelAttribute("user") User user) {
return "user/internal/form/credentialForm";
}
Any ideas how to fix it?
UPD:
<web-app
version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd">
<!-- log4j configuration -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:/log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<!-- Config Setup -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/spring-config/security.xml
classpath:/spring-config/data.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<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>
<!-- Spring MVC -->
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/spring-config/mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Error handling -->
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/views/error/404.jsp</location>
</error-page>
</web-app>
UPD 2
Spring MVC config:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:ctx="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<mvc:annotation-driven/>
<ctx:component-scan base-package="de.mark.project.web"/>
<sec:global-method-security pre-post-annotations="enabled"/>
<mvc:resources mapping="/resources/**" location="classpath:/style/"/>
<mvc:interceptors>
<bean id="webContentInterceptor" class="org.springframework.web.servlet.mvc.WebContentInterceptor">
<property name="cacheSeconds" value="0"/>
<property name="useExpiresHeader" value="true"/>
<property name="useCacheControlHeader" value="true"/>
<property name="useCacheControlNoStore" value="true"/>
</bean>
</mvc:interceptors>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
This is likely due to the fact that the <global-method-security>
tag needs to be in the same context as your Spring MVC configuration otherwise your controllers will not be post processed. This is discussed in the FAQ.
So for example, if your web.xml looks like the following:
<!--
- Location of the XML file that defines the root application context
- Applied by ContextLoaderListener.
-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/*.xml
</param-value>
</context-param>
<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>
<!--
- Loads the root application context of this web app at startup.
- The application context is then available via
- WebApplicationContextUtils.getWebApplicationContext(servletContext).
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc/*.xml</param-value>
</init-param>
</servlet>
To support method security on your controllers ensure the <global-method-security>
tag is defined in a location within /WEB-INF/mvc/*.xml. Note that the remainder of the configuration should remain where it is. If you want to support method security on your services, you likely also need <global-method-security>
in the parent (i.e. where it likely is now).
If this does not help, please post your web.xml or WebApplicationInitializer's if you are not using web.xml
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With