My question is quite simple "Can have any problems when using Spring security and GWT RPC ?" .
I would like to use spring's method level security on GWT's RPC methods.For instance : at my ServiceImpl class , I used Expression-Based Access Control as below.
#PreAuthorize("hasRole('ROLE_ADMIN')")
public final String getById(Long id) {
.........
}
If un-authorize role access users trying to access page dealing with this rpc method , exception was thrown and don't redirect to my access-denied page. I have no idea why doesn't go to my access-denied page ? I got an exception at my console as
threw an unexpected exception: org.springframework.security.access.AccessDeniedException: Access is denied
I configured as this answer exactly but still getting above error.Please correct me if I am wrong "I think this problem may due to gwt's RPC" because non-rpc methods were fine and redirect to my unSecure.html . I spend about 3 days for this error . At onFailure(Throwable caught) of my asynchronous method show
500 The call failed on the server; see server log for details
I want to show my configurations .
spring-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:sec="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.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<sec:global-method-security
secured-annotations="enabled" pre-post-annotations="enabled" />
<sec:http auto-config="false" entry-point-ref="authenticateFilterEntryPoint">
<sec:access-denied-handler ref="accessDeniedHandler" />
<sec:intercept-url pattern="/login.html" />
<sec:logout logout-url="/logout.html" logout-success-url="/login.html"
invalidate-session="true" />
<sec:form-login login-page="/login.html"
login-processing-url="/login_check" authentication-failure-url="/login.html?error=1" />
<sec:session-management invalid-session-url="/login.html">
<sec:concurrency-control max-sessions="50"
error-if-maximum-exceeded="true" />
</sec:session-management>
<sec:remember-me key="mykey"
token-validity-seconds="604800" />
</sec:http>
<beans:bean id="authenticateFilterEntryPoint"
class="mypackage.common.security.SessionTimeoutEntryPoint">
<beans:property name="loginFormUrl" value="/login.html" />
</beans:bean>
<beans:bean id="accessDeniedHandler"
class="mypackage.common.security.AccessDeniedEntryPoint">
<beans:property name="errorPage" value="/unSecure.html" />
</beans:bean>
<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>
<beans:bean id="authenticationUserService"
class="mypackage.common.security.AuthenticationUserService" />
<sec:authentication-manager>
<sec:authentication-provider
user-service-ref="authenticationUserService">
<sec:password-encoder hash="md5" />
</sec:authentication-provider>
</sec:authentication-manager>
<beans:bean id="authLoggerListener"
class="org.springframework.security.authentication.event.LoggerListener" />
<beans:bean id="eventLoggerListener"
class="org.springframework.security.access.event.LoggerListener" />
AccessDeniedEntryPoint.java
public class AccessDeniedEntryPoint extends org.springframework.security.web.access.AccessDeniedHandlerImpl {
private static final Logger logger = LoggerFactory.getLogger(AccessDeniedEntryPoint.class);
#Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
super.handle(request, response, accessDeniedException);
}
}
SessionTimeoutEntryPoint.java
public class SessionTimeoutEntryPoint extends LoginUrlAuthenticationEntryPoint {
#Override
public final void commence(final HttpServletRequest request, final HttpServletResponse response,
final AuthenticationException authException) throws IOException, ServletException {
super.commence(request, response, authException);
}
}
So , I would like to get unSecure.html when un-authorize role users access this method. I would really appreciated any of your suggestions. Sorry for my long question. I don't want to hit my head anymore ! Thanks.
As in my last response, I used this long time ago. In my case instead of dealing always with urls I delegated into handlers.
I mean, if you want to integrate GWT-RPC with Spring-Security, the first thing that I did, was from my GWT app try to login against Spring.
So the first thing that you need to do is create a RPC-CALL (here official documentation) for login.
I found useful the annotation #RemoteServiceRelativePath("examplelogin.rpc"), so if you use it you can take advantage about the path, and then, in the spring-security.xml you can filter the request by those path (see the updated example below).
Not sure why you want to integrate GWT-RPC with Spring-Security and then you specify /login.html (should it be a rpc call, described befored instead of html? But maybe you are using your own MVP with GWT, so I am not saying that is wrong, only it surprises me :) ).
Reading your code I do not see something wrong, but in my case I have some differences:
....
<http use-expressions="true" entry-point-ref="http401UnauthorizedEntryPoint">
<intercept-url pattern="/yourProject/public.rpc" access="permitAll" />
<intercept-url pattern="/yourProject/examplelogin.rpc" access="hasRole('ROLE_ADMIN')" />
<form-login authentication-success-handler-ref="authenticationSuccessHandler"
authentication-failure-handler-ref="authenticationFailureHandler"/>
..... //logout, session-management, custom-filters....
<beans:bean id="http401UnauthorizedEntryPoint"
class="your.project.Http401UnauthorizedEntryPoint" />
<beans:bean id="authenticationSuccessHandler"
class="your.project.GWTAuthenticationSuccessHandler"/>
<beans:bean id="authenticationFailureHandler"
class="your.project.GWTAuthenticationFailureHandler"/>
</http>
....
You asked specifically about the possibility of using Spring-Security with GWT-RPC (that is the reason because in the <intercept-url> tags I place there the .rpc urls)
Note that the
The answer is yes, I have done it (three years ago, but I did :) )
I think here the keys for your problem are:
Specify the interceptor url for the RPC calls or your /login.html
Delegate on handlers like I did (be careful maybe you are doing well
and the error is in other part, but at least I did like in the example and it
worked).
Sorry for not showing you directly the error, I hope this answers will help.
Thanks.
Related
The problem is that my custom Spring Security filter is never invoked when a request comes in. During debugging, I found that in doFilter() in FilterChainProxy, my filter (JwtAuthenticationFilter) can be fetched:
But it's skipped. Then I found it's due to:
So the superclass of my filer, which is AbstractAuthenticationProcessingFilter thinks the request doesn't need authentication and it just calls doFilter() to pass it down. I think my configs specified that auth is needed. This specific request is /ui/home/index.jsp, where \ui is the context.
My security configs:
<http use-expressions="true" pattern="/**" entry-point-ref="JwtAuthenticationEntryPoint" create-session="stateless">
<custom-filter before="CONCURRENT_SESSION_FILTER" ref="jwtAuthenticationFilter" />
<intercept-url pattern="/home/**" access="isAuthenticated()"/>
// some other intercept-url definitions
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="authenticationProvider"/>
</authentication-manager>
And bean configs:
<bean id="jwtAuthenticationFilter" class="com.pk.jjwt.JwtAuthenticationTokenFilter" >
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="jwtAuthenticationSuccessHandler" />
</bean>
<bean id="JwtAuthenticationEntryPoint" class="com.pk.jjwt.JwtAuthenticationEntryPoint" />
<bean id="authenticationProvider" class="com.pk.jjwt.JwtAuthenticationProvider" />
<bean id="jwtAuthenticationSuccessHandler" class="com.pk.jjwt.JwtAuthenticationSuccessHandler" />
I wonder what might cause the filters getting skipped? I think I specified that every url pattern needs to be authenticated. I'm not sure why it thinks that request doesn't need authentication from my custom filter.
Edit:
So I debugged the requiresAuthentication() method, and found:
Basically it's evaluating uri.endsWith("/ui/**") and uri is /ui/home/index.jsp. It returned false, so the filter is skipped.
First of all this is not a duplicate question i checked answers here! and
here! but couldnt get it to work.
Also i want to perform it just before logout so can not use logoutSuccessHandler.
So i need to create a custom LOGOUT_FILTER , with which i am really having hard time getting it to work.
here is my spring-security xml in which i tried two methods
first was :-
<custom-filter ref="logoutFilter" position="LOGOUT_FILTER" />
<beans:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<beans:constructor-arg index="0" value="/logoutSuccess" />
<beans:constructor-arg index="1">
<beans:list>
<beans:bean id="securityContextLogoutHandler"
class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
<beans:bean id="myLogoutHandler" class="com.fe.cms.listener.SimpleLogoutHandler" />
</beans:list>
</beans:constructor-arg>
<beans:property name="filterProcessesUrl" value="/logout" />
</beans:bean>
but this gives me error
Configuration problem: Security namespace does not support decoration of element [custom-filter]
then i tried..
<beans:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<beans:constructor-arg index="0" value="/logout" />
<beans:constructor-arg index="1">
<beans:ref bean="securityContextLogoutHandler" />
<beans:ref bean="myLogoutHandler" />
</beans:constructor-arg>
<beans:property name="filterProcessesUrl" value="/logout" />
</beans:bean>
<beans:bean id="securityContextLogoutHandler"
class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
<beans:bean id="myLogoutHandler" class="com.fe.cms.listener.SimpleLogoutHandler" />
<http auto-config="false" entry-point-ref="authenticationManger">
<custom-filter ref="logoutFilter" position="LOGOUT_FILTER" />
</http>
but this gives me error :-
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.filterChains': Cannot resolve reference to bean 'org.springframework.security.web.DefaultSecurityFilterChain#48' while setting bean property 'sourceList' with key [48]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.web.DefaultSecurityFilterChain#48': Cannot create inner bean '(inner bean)' of type [org.springframework.security.web.access.ExceptionTranslationFilter] while setting constructor argument with key [6]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#181': Could not resolve matching constructor (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)
Please can anyone tell where am i doing wrong ..
i will post full xml files if needed
According to your clarification what you want is to get access the to session and perform some logic. Instead of hacking around with a custom LogoutFilter simply write an ApplicationListener that listens to HttpSessionDestroyedEvents.
#Component
public class SessionListener implements ApplicationListener<HttpSessionDestroyedEvent> {
public void onApplicationEvent(HttpSessionDestroyedEvent evt) {
HttpSession session = evt.getSession();
// Your logic here
}
}
To be able re receive events make sure that you register the HttpSessionEventPublisher in your web.xml.
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
Main advantage of this solution is that you will also be able to process sessions that timeout and not only regular logouts.
If you need to execute some operation just before logout I suppose Spring interceptors can help you.
You could implement a class like this:
public class JustBeforeLogoutInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
boolean res = super.preHandle(request, response, handler);
//
// your code...
//
return res;
}
}
Then you need to configure the interceptor:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/logout" />
<bean class="your.app.JustBeforeLogoutInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
This should work. Take a try.
You can try to extend current LogoutFilter and execute your custom logic before calling super class' doFilter method.
Like this
public class CustomLogoutFilter extends LogoutFilter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (requiresLogout(request, response)) {
// IMPLEMENT YOUR CUSTOM LOGIC HERE
super.doFilter(req, res, chain);
return;
}
chain.doFilter(request, response);
}
}
Then you have to replace default LogoutFilter with your CustomLogoutFilter
<http>
<custom-filter position="LOGOUT_FILTER" ref="customLogoutFilter" />
</http>
<bean id="customLogutFilter" class="example.CustomLogoutFilter">
<property name="filterProcessesUrl" value="/logout" />
<!-- Put other needed properties here-->
</bean>
I'm trying to create a custom filter to take care of authentication, since I'm forced to use a combination of an AD and local database (arg!) to determine access rights. I'm using the official docs, for this particular issue mostly this part.
However, when I run my server it is complaining about the AuthenticationManager being null, while I believe I am setting it in XML as covered in this SO question. What am I missing here?
The exception:
SEVERE: Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myUsernamePasswordAuthenticationFilter' defined in file [*snip*]:
Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: authenticationManager must be specified
...
Caused by: java.lang.IllegalArgumentException: authenticationManager must be specified
at org.springframework.util.Assert.notNull(Assert.java:112)
The XML: (with some simplified class names)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:sec="http://www.springframework.org/schema/security"
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.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<context:property-placeholder location="classpath*:META-INF/spring/*.properties" />
<context:spring-configured />
<context:component-scan base-package="myapp" />
<!-- Spring Security Configuration. -->
<sec:http auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint"
access-denied-page="/denied.jsp">
<sec:custom-filter position="FORM_LOGIN_FILTER" ref="myAuthenticationFilter" />
<sec:intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<sec:intercept-url pattern="/404.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<sec:intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<sec:intercept-url pattern="/**" access="ROLE_USER" />
<sec:logout logout-url="/logout" logout-success-url="/login" />
</sec:http>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="myAuthenticationProvider" />
</sec:authentication-manager>
<bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login" />
</bean>
<bean id="myAuthenticationFilter" class="myapp.MyUsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="myAuthenticationProvider" class="myapp.MyAuthenticationProvider" />
The Filter:
#Component
public class MyUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public AdminUsernamePasswordAuthenticationFilter() {
super("/login");
}
#Override
public Authentication attemptAuthentication(final HttpServletRequest request,
final HttpServletResponse response) throws AuthenticationException {
// stuff and:
return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(
login, request.getParameter("password")));
}
}
The AuthenticationProvider:
#Component
public class MyAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
// all the funky AD+DB code
return null;
}
#Override
public boolean supports(final Class<?> clazz) {
return true;
}
}
I am running Java 6, the latest Spring Security (3.1.4.RELEASE) and Spring (3.2.3.RELEASE) versions, running on a Tomcat v6 server. Different Spring versions do not appear to be a problem (related SO question). And if it would be a problem, having to run Spring 3.1.4 if you want to use Spring Security is just meh...
Some additional things I tried to no avail:
I tried ditching the <sec:authentication-manager /> in favour of a normal bean, as mentioned here (bottom answer).
I tried adding bean id's, names, authentication-manager-refs in all sorts of combinations.
Ah... I spot the basic error made by many in Spring. You have your bean MyUsernamePasswordAuthenticationFilter defined in XML, which is correct. However you have it also annotated by #Component annotation, which means it is being picked and registered as another bean definition by component scan. And bean instance comming from this definition won't indeed have its authenticationManager dependency initalized.
Just remove the #Component annotation in MyUsernamePasswordAuthenticationFilter and you should be OK.
I have implemented spring-security in my application, my spring-security.xml has following form-login tag.
<form-login login-page="/login.htm" default-target-url="/dashboard.htm"
authentication-failure-url="/login.htm?error=true"
authentication-success-handler-ref="authenticationSuccessHandler" />
I want to login from /login.htm and after successful authetication I want user to hit dashboard.htm. Everythig is working fine except for the fact that after successfull authetication it doesn't hit /dashboard.htm but hits the context..but if I manually type dashboard.htm in url then everything works fine...Yes..I have the implementation of authticationSuccessHandler.
Try removing the default-target-url attribute and add the following:
<b:bean id="authenticationSuccessHandler" class="com.example.CustomSimpleURLAuthenticationSuccessHandler">
<b:property name="defaultTargetUrl" value="/dashboard.htm"/>
</b:bean>
<beans:bean id="loginSuccessHandler" class="com.example.LoginSuccessHandler">
<beans:property name="defaultTargetUrl" value="/security/success"/>
<beans:property name="alwaysUseDefaultTargetUrl" value="true"/>
</beans:bean>
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
request.getSession().setMaxInactiveInterval(60 * 60); //one hour
System.out.println("Session set up for 60min");
super.onAuthenticationSuccess(request, response, authentication);
}
}
I use this suggestion from the question spring is not redirecting to default target url?. I tried this and it is working.
<form-login login-page="/login.htm"
default-target-url="/dashboard.htm"
always-use-default-target="true"/>
As you can see in the image, there is some kind of bad design (IMO It always redirect to the default-target-url).
When you go to the login form from a forbidden resource, it will redirect you to that URL and not going thru the default-target-url
http://i.stack.imgur.com/fj9ou.png
I have a spring 3 application with the configurations given below. When any user tries to access a page and he/she isn't logged in, I get an Access is Denied exception with an ugly stack trace. How do I handle this exception and not let it dump out a stack trace. I implemented my own access-denied-handler but that doesn't get invoked.
Based on the type of the requested resource, I would like to show custom error messages or pages. Here is my spring configuration.
How do I get Spring to invoke my access-denied-handler . Here is my spring configuration
<security:http auto-config='true'>
<security:intercept-url pattern="/static/**" filters="none"/>
<security:intercept-url pattern="/login" filters="none"/>
<security:intercept-url pattern="/**" access="ROLE_USER" />
<security:form-login login-page="/index"
default-target-url="/home" always-use-default-target="true"
authentication-success-handler-ref="AuthenticationSuccessHandler"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/index?error=true"/>
<security:remember-me key="myLongSecretCookieKey" token-validity-seconds="1296000"
data-source-ref="jdbcDataSource" user-service-ref="AppUserDetailsService" />
<security:access-denied-handler ref="myAccessDeniedHandler" />
</security:http>
<bean id="myAccessDeniedHandler"
class="web.exceptions.handlers.AccessDeniedExceptionHandler">
<property name="errorPage" value="/public/403.htm" />
</bean>
The custom class for handling this exception is given below
public class AccessDeniedExceptionHandler implements AccessDeniedHandler
{
private String errorPage;
#Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException arg2) throws IOException, ServletException {
response.sendRedirect(errorPage);
}
public void setErrorPage(String errorPage) {
if ((errorPage != null) && !errorPage.startsWith("/")) {
throw new IllegalArgumentException("errorPage must begin with '/'");
}
this.errorPage = errorPage;
}
}
When I run this application, this is the error that I get. I am only pasting a part of the stacktrace and the Spring Debug logs.
20:39:46,173 DEBUG AffirmativeBased:53 - Voter: org.springframework.security.access.vote.RoleVoter#5b7da0d1, returned: -1
20:39:46,173 DEBUG AffirmativeBased:53 - Voter: org.springframework.security.access.vote.AuthenticatedVoter#14c92844, returned: 0
20:39:46,178 DEBUG ExceptionTranslationFilter:154 - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:71)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:204)
How do I fix this problem? Firstly, I want to stop spring from Throwing that exception. If it still throws it, I want to handle it and not raise any flags.
Update: I have attached a part of my web.xml as well.
<!-- Hibernate filter configuration -->
<filter>
<filter-name>HibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<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>
<!--Dispatcher Servlet -->
<servlet>
<servlet-name>rowz</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
In your configuration You require the user to be always authenticated when entering any URL on Your site:
<security:intercept-url pattern="/**" access="ROLE_USER" />
I think You should allow the user to be unauthenticated when entering the login page:
<security:intercept-url pattern="/your-login-page-url" access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/your-login-process-url" access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/your-login-failure-url" access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/**" access="ROLE_USER" />
If You use URL's like: /login/start, /login/error and /login/failure You can have:
<security:intercept-url pattern="/login/**" access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/**" access="ROLE_USER" />
Update:
Having this configuration should make the framework to redirect all unauthenticated (anonymous) users to login page, and all authenticated to AccessDeniedHandler. The AccessDeniedException is one of the core parts of the framework and ignoring it is not a good idea. It's hard to help more if You only provide parts of Your Spring Security configuration.
Be sure to read the JavaDoc for ExceptionTranslationFilter for detailed explanation of what exceptions are thrown by the framework, why and how are the handled by default.
If possible, try removing as many custom parts You added, like AuthenticationSuccessHandler, RememberMeAuthenticationFilter and AccessDeniedHandler and see if the problem pesist? Try to get the minimal congiuration and add new features step by step to see where the error comes from.
One important thing that You don't mention in Your question is what is the result of this error message? Do You get HTTP 500? Or HTTP 403? Or do You get redirected to login page?
If, as You mentioned in the question, the user is unauthenticated and he/she gets redirected to login page, than that's how it's intended to work. It looks like You get the error message logged by ExceptionTranslationFilter:172 only because You have DEBUG level set to Spring Security classes. If so, than that's also how it's intended to work, and if You don't want the error logged, than simply rise the logging level for Spring Secyruty classes.
Update 2:
The patterns with filters="none" must match the login-page, login-processing-url and authentication-failure-ur attributes set in <security:form-login /> to skip all SpringSecurity checks on pages that display the login page and process the logging in.
<security:http auto-config='true'>
<security:intercept-url pattern="/static/**" filters="none"/>
<security:intercept-url pattern="/index" filters="none"/>
<security:intercept-url pattern="/j_spring_security_check" filters="none"/>
<security:intercept-url pattern="/**" access="ROLE_USER" />
<security:form-login login-page="/index"
default-target-url="/home" always-use-default-target="true"
authentication-success-handler-ref="AuthenticationSuccessHandler"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/index?error=true"/>
<security:remember-me key="myLongSecretCookieKey" token-validity-seconds="1296000"
data-source-ref="jdbcDataSource" user-service-ref="AppUserDetailsService" />
<security:access-denied-handler ref="myAccessDeniedHandler" />
</security:http>
AccessDeniedHandler is invoked when user is logged in and there is no permissions to resource (source here). If you want to handle request for login page when user is not logged in, just configure in security-context:
<http ... entry-point-ref="customAuthenticationEntryPoint">
And define customAuthenticationEntryPoint:
<beans:bean id="customAuthenticationEntryPoint" class="pl.wsiadamy.webapp.controller.util.CustomAuthenticationEntryPoint">
</beans:bean>
TIP, don't try to fight with ExceptionTranslationFilter.
I have tried to override org.springframework.security.web.access.ExceptionTranslationFilter, without effects:
<beans:bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
<beans:property name="authenticationEntryPoint" ref="customAuthenticationEntryPoint"/>
<beans:property name="accessDeniedHandler" ref="accessDeniedHandler"/>
</beans:bean>
<beans:bean id="accessDeniedHandler"
class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<beans:property name="errorPage" value="/accessDenied.htm"/>
</beans:bean>
The ref="customAuthenticationEntryPoint" just didn't invoked.
I have added Spring Access denied page in follwing way:
Spring Frame Work: 3.1
Spring Security: 3.1, Java 1.5+
Entry in *-security.xml:
<security:access-denied-handler error-page="/<My Any error page controller name>" />
Example:
<security:access-denied-handler error-page="/accessDeniedPage.htm" />
Error page will always start with "/"
Entry for controller:
#Controller
public class RedirectAccessDenied {
#RequestMapping(value = "/accessDeniedPage.htm", method = RequestMethod.GET)
public String redirectAccessDenied(Model model) throws IOException, ServletException {
System.out.println("############### Redirect Access Denied Handler!");
return "403";
}
}
Here 403 is my JSP name.
Spring Security uses an AuthenticationEntryPoint object to decide what to do when a user requires authentication. You can create your own AuthenticationEntryPoint bean ( see javadoc ), and then set the entryPoint attribute in the http element:
<http entry-point-ref="entryPointBean" .... />
However, by default, the form-login element creates a LoginUrlAuthenticationEntryPoint which redirects all of your unauthenticated users to the login page, so you shouldn't have to do this yourself. In fact, the log you posted claims it is forwarding the user to the authentication entry point: "Access is denied (user is anonymous); redirecting to authentication entry point".
I wonder if the problem is that you turned off the filter chain for the login url. Instead of setting filters to none, which means spring security is bypassed entirely, try keeping the filters on but allowing unrestricted access like this:
<security:intercept-url pattern="/login" access="permitAll" />
If that still doesn't help, please post the rest of the log so we can see what happens after the request is transferred to the entry point.
Programmatically solution:
#Order(1)
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//
// ...
//
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandlerImpl() {
#Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
super.handle(request, response, accessDeniedException);
accessDeniedException.printStackTrace();
}
});
//
// ...
//
}
}
Can you check your web.xml is supporting forward request?
errorPage is a FORWARD request and mostly in web.xml we support REDIRECTS only. Just a thought else your code looks ok to me.
Edited
A different point of view and This is been taken from working code only.
Have a look at Authenticated Voter class
Disable the annotations
<global-method-security pre-post-annotations="disabled"
secured-annotations="disabled" access-decision-manager-ref="accessDecisionManager">
</global-method-security>
bypassing filters
<http auto-config="true" use-expressions="true"
access-decision-manager-ref="accessDecisionManager"
access-denied-page="/accessDenied">
<intercept-url pattern="/appsecurity/login.jsp" filters="none" />
<intercept-url pattern="/changePassword" filters="none" />
<intercept-url pattern="/pageNotFound" filters="none" />
<intercept-url pattern="/accessDenied" filters="none" />
<intercept-url pattern="/forgotPassword" filters="none" />
<intercept-url pattern="/**" filters="none" />
<form-login login-processing-url="/j_spring_security_check"
default-target-url="/home" login-page="/loginDetails"
authentication-failure-handler-ref="authenticationExceptionHandler"
authentication-failure-url="/?login_error=t" />
<logout logout-url="/j_spring_security_logout"
invalidate-session="true" logout-success-url="/" />
<remember-me />
<!-- Uncomment to limit the number of sessions a user can have -->
<session-management invalid-session-url="/">
<concurrency-control max-sessions="1"
error-if-maximum-exceeded="true" />
</session-management>
</http>
custom Decision Voter
<bean id="customVoter" class="xyz.appsecurity.helper.CustomDecisionVoter" />
Access Decision Manager
<!-- Define AccessDesisionManager as UnanimousBased -->
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
<property name="decisionVoters">
<list>
<ref bean="customVoter" />
<!-- <bean class="org.springframework.security.access.vote.RoleVoter"
/> -->
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</property>
</bean>
Authentiation Exception Handler
<bean id="authenticationExceptionHandler"
class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
<property name="exceptionMappings">
<props>
<!-- /error.jsp -->
<prop
key="org.springframework.security.authentication.BadCredentialsException">/?login_error=t</prop>
<!-- /getnewpassword.jsp -->
<prop
key="org.springframework.security.authentication.CredentialsExpiredException">/changePassword</prop>
<!-- /lockedoutpage.jsp -->
<prop key="org.springframework.security.authentication.LockedException">/?login_error=t</prop>
<!-- /unauthorizeduser.jsp -->
<prop
key="org.springframework.security.authentication.DisabledException">/?login_error=t</prop>
</props>
</property>
</bean>
It looks like spring tries to redirect users who have not logged in to the login page, which is "/index", but that itself is a protected url.
The other possibility is, it tries to display /public/403.html, but that is again protected by security configuration.
Can you add the following entries and try?
<security:intercept-url pattern="/login" filters="none" />
<security:intercept-url pattern="/public/**" filters="none" />