I'm using Vaadin 7, Spring Security and the Spring-Vaadin-Integration addon and have configured the authentication bit so it's working like a charm.
When I get to the authorization part I got into some hairy trouble.
I want to set authorization per View without having to check for authorization at navigation level (like in the AppFoundation addon).
So, what I want is something like this:
@Component
@Scope("prototype")
@VaadinView(value = ASecuredView.NAME, cached = true)
@Secured("ROLE_ADMIN_PROD")
public class ASecuredView extends GridLayout implements View {
...
}
When an unauthorized user tries to enter this view, I want to handle the AccessDeniedException
and present the user with a notification message that explains something in the lines of "The view is only accessible by admins".
I do have the correct user role when I invoke the view and no exceptions are thrown when I try to navigate there with an authorized user, so the annotation itself seems to be working just as it should.
The problem is that I cannot catch the AccessDeniedException.
I have tried several different methods of solving this problem, but to no avail. Here is some of them:
- I created a
CustomAccessDeniedHandler
, no exception caught.
- I tried the simple
access-denied-handler
tag, but the exception is still not caught.
- I tried "re-throwing" the exception with a
org.springframework.web.servlet.handler.SimpleMappingExceptionResolver
, but still same behaviour.
- I tried the
@PreFilter
annotation, but it didn't work.
- I tried using a
handleSecuredAnnotations
(around) Aspect, but even that did not work!
Am I approaching this in the wrong way?
Maybe there is an easier/better way of achieving this? How?
Here's my spring-security.xml. I'll provide the whole shabang. Note that I tried the different methods separately as well:
<global-method-security secured-annotations="enabled" />
<!-- Spring-Security -->
<http auto-config="true" use-expressions="true" disable-url-rewriting="true">
<form-login authentication-success-handler-ref="authenticationSuccessHandler" />
<intercept-url pattern="/**" access="isAuthenticated()" />
<logout success-handler-ref="logoutSuccessHandler" invalidate-session="true" logout-url="/logout" />
<access-denied-handler ref="customAccessDeniedHandler" />
</http>
<authentication-manager>
<authentication-provider ref="activeDirectoryAuthenticationProvider" />
</authentication-manager>
<beans:bean id="activeDirectoryAuthenticationProvider" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<beans:constructor-arg value="someserver.com" />
<beans:constructor-arg value="ldap://ldaplb.someserver.com:389" />
<beans:property name="userDetailsContextMapper" ref="customUserDetailsContextMapper" />
<beans:property name="convertSubErrorCodesToExceptions" value="true" />
</beans:bean>
<beans:bean id="customAccessDeniedHandler" class="com.some.path.web.CustomAccessDeniedHandler" />
<beans:bean id="customUserDetailsContextMapper" class="com.some.path.web.CustomUserDetailsContextMapper" />
<beans:bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<beans:property name="defaultErrorView" value="uncaughtException" />
<beans:property name="excludedExceptions" value="org.springframework.security.access.AccessDeniedException" />
<beans:property name="exceptionMappings">
<beans:props>
<beans:prop key=".DataAccessException">dataAccessFailure</beans:prop>
<beans:prop key=".NoSuchRequestHandlingMethodException">resourceNotFound</beans:prop>
<beans:prop key=".TypeMismatchException">resourceNotFound</beans:prop>
<beans:prop key=".MissingServletRequestParameterException">resourceNotFound</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<aop:config>
<aop:aspect id="securedAspect" ref="securityFeedbackAspect">
<aop:around pointcut="@annotation(org.springframework.security.access.annotation.Secured)" method="handleSecuredAnnotations" />
</aop:aspect>
</aop:config>