I am experimenting with spring security and I encountered a problem that i can't solve for almost a day now.. My login form for default /login URL is working fine, csrf is enabled. onAuthenticationSuccess method in MyAuthenticationSuccessHandler is invoked and it is redirecting to desired page after successful login. My problem concerns /logout URL. I searched many pages for solution but couldn't find answer that fits. When i'm trying to logout via /logout URL in header.jsp HTTP Status 405 ? Method Not Allowed page is shown and the message is Request method 'POST' not supported. I'm sending logout form by POST
<form id="logoutForm" action="${pageContext.request.contextPath}/logout" method="POST" >
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
onLogoutSuccess method in MyLogoutSuccessHandler is invoked and user is logged out but redirection stops on /logout URL with that 405 error page. It can't reach my /loginController/showLogout
redirection specified in MyLogoutSuccessHandler. I can't figure out what is messed up
This is my code:
security-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<jee:jndi-lookup jndi-name="jdbc/spring" id="dataSource"
expected-type="javax.sql.DataSource">
</jee:jndi-lookup>
<bean id="activeUserStore" class="com.springtutorial.authentication.ActiveUserStore" />
<bean id="myAuthenticationSuccessHandler"
class="com.springtutorial.authentication.MyAuthenticationSuccessHandler">
<property name="activeUserStore" ref="activeUserStore"></property>
</bean>
<bean id="myLogoutSuccessHandler"
class="com.springtutorial.authentication.MyLogoutSuccessHandler" />
<security:authentication-manager>
<security:authentication-provider >
<security:jdbc-user-service
data-source-ref="dataSource"
users-by-username-query="select username, password, enabled from simple_users where binary username = ?"
authorities-by-username-query="select username, role from authorities where binary username = ?" />
<security:password-encoder ref="passwordEncoder"></security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
<security:http use-expressions="true">
<security:intercept-url pattern="/loggedUsers"
access="hasRole('ROLE_ADMIN')" />
<security:intercept-url pattern="/adminPage"
access="hasRole('ROLE_ADMIN')" />
<security:intercept-url pattern="/offerController/processCreateOfferForm"
access="isAuthenticated()" />
<security:intercept-url pattern="/offerController/showCreateOfferForm"
access="isAuthenticated()" />
<security:intercept-url pattern="/offerController/offerCreated"
access="isAuthenticated()" />
<security:intercept-url pattern="/" access="permitAll" />
<security:intercept-url pattern="/showAccessDenied"
access="permitAll" />
<security:intercept-url pattern="/loginController/showRegisterUserForm"
access="permitAll" />
<security:intercept-url pattern="/loginController/processRegisterUserForm"
access="permitAll" />
<security:intercept-url pattern="/loginController/userRegistered"
access="permitAll" />
<security:intercept-url pattern="/loginController/showLoginForm"
access="permitAll" />
<security:intercept-url pattern="/loginController/showLogout"
access="permitAll" />
<security:intercept-url pattern="/resources/**"
access="permitAll" />
<security:intercept-url pattern="/offerController/showOffers"
access="permitAll" />
<security:intercept-url pattern="/**" access="denyAll" />
<security:form-login login-page="/loginController/showLoginForm"
authentication-failure-url="/loginController/showLoginForm?error=true"
authentication-success-handler-ref="myAuthenticationSuccessHandler" />
<security:logout invalidate-session="true"
success-handler-ref="myLogoutSuccessHandler" />
<security:access-denied-handler error-page="/showAccessDenied" />
<security:remember-me key="offersAppKey" />
<security:csrf />
</security:http>
<bean id="passwordEncoder"
class="org.springframework.security.crypto.password.StandardPasswordEncoder">
</bean>
I am using apache tiles 3 for my view and I'm redirecting to default /login URL in loginForm.jsp tile: loginForm.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<script type="text/javascript">
$(document).ready(function() {
document.username.focus()
});
</script>
<h3>My Login</h3>
<c:if test="${param.error}">
<p class="errors">Login failed. Username or password are wrong.</p>
</c:if>
<form action='${pageContext.request.contextPath}/login' method='POST'>
<table>
<tr>
<td>User:</td>
<td><input type='text' id='username' name='username' ></td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='password' /></td>
</tr>
<tr>
<td>Remember me:</td>
<td><input type='checkbox' name='remember-me' checked="checked" /></td>
</tr>
<tr>
<td colspan='2'><input name="submit" type="submit"
value="Login" /></td>
</tr>
<tr>
<td><input name="_csrf" type="hidden"
value="${_csrf.token}" /></td>
</tr>
</table>
</form>
<p><a href="<c:url value="showRegisterUserForm"/>">Create new User</a></p>
and redirecting to default /logout URL in header.jsp tile:
header.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sec"
uri="http://www.springframework.org/security/tags"%>
<a class="title"
href="${pageContext.request.contextPath}/">Offers</a>
<sec:authorize access="!isAuthenticated()">
<a class="login"
href="${pageContext.request.contextPath}/loginController/showLoginForm">Login</a>
</sec:authorize>
<sec:authorize access="isAuthenticated()">
<!-- <a class="login" href="${pageContext.request.contextPath}/logout">Logout</a> -->
<a class="login" id="logoutLink" href="#">Logout</a>
<form id="logoutForm" action="${pageContext.request.contextPath}/logout" method="POST" >
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
</sec:authorize>
<script type="text/javascript">
$(document).ready(function() {
$('#logoutLink').click(function() {
$('#logoutForm').submit();
});
});
</script>
And those are my implementations of AuthenticationSuccessHandler and LogoutSuccessHandler:
MyAuthenticationSuccessHandler
public class MyAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Autowired
private ActiveUserStore activeUserStore;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
HttpSession session = request.getSession(false);
if (session != null) {
LoggedUser user = new LoggedUser(authentication.getName(), activeUserStore);
session.setAttribute("user", user);
}
if (savedRequest == null) {
getRedirectStrategy().sendRedirect(request, response, "/");
} else {
String targetUrl = savedRequest.getRedirectUrl();
getRedirectStrategy().sendRedirect(request, response, targetUrl);
}
}
public ActiveUserStore getActiveUserStore() {
return activeUserStore;
}
public void setActiveUserStore(ActiveUserStore activeUserStore) {
this.activeUserStore = activeUserStore;
}
}
MyLogoutSuccessHandler
public class MyLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
System.out.println("co jest");
HttpSession session = request.getSession();
if (session != null) {
session.removeAttribute("user");
}
String URL = request.getContextPath() + "/loginController/showLogout";
getRedirectStrategy().sendRedirect(request, response, URL);
}
}
I implemented those because i want to track logged in users :)