I am upgrading a legacy spring app tech stack and in the process of upgrading to spring 5.
I have made the necessary upgrades but left the controllers etc.. as they are mapped and I dont think anything is needed updated based off the documentation i have looked at (unless someone can tell me otherwise and why)
The error occurs when trying to login - user is brought to the change password screen and a 404 is thrown.
Message JSP file [/WEB-INF/jsp/public/change-password.jsp] not found
change-password.jsp
<jsp:include flush="true" page="/WEB-INF/jsp/layout.jsp">
<jsp:param name="title" value="change.password.title.text" />
<jsp:param name="main" value="/WEB-INF/jsp/public/change-password/change-password.main.jsp" />
<jsp:param name="menu" value="common/menu.jsp" />
<jsp:param name="footer" value="common/footer.jsp" />
</jsp:include>
change-password.main.jsp
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="name" uri="http://www.name.com/tags"%>
<h1>
<spring:message code="change.password.header.text" />
</h1>
<h2>
<spring:message code="change.password.help.text1" />
<br></br>
<spring:message code="change.password.help.text2" />
</h2>
<name:form modelAttribute="changePasswordFormObject" action="public/change-password/save">
<table>
<tr>
<td>
<spring:message code="change.password.currentPassword.text" />
</td>
<td>
<form:password path="currentPassword" showPassword="true" id="currentPassword"/>
</td>
<td>
<form:errors path="currentPassword" cssClass="error" />
</td>
</tr>
<tr>
<td>
<spring:message code="change.password.newPassword.text" />
</td>
<td>
<form:password path="newPassword" showPassword="true" />
</td>
<td>
<form:errors path="newPassword" cssClass="error" />
</td>
</tr>
<tr>
<td>
<spring:message code="change.password.confirmPassword.text" />
</td>
<td>
<form:password path="confirmPassword" showPassword="true" />
</td>
<td>
<form:errors path="confirmPassword" cssClass="error" />
</td>
</tr>
</table>
<p>
<amor:dojoSubmitButton name="changePasswordButton" id="changePasswordButton">
<spring:message code="change.password.button.save.text" />
</amor:dojoSubmitButton>
</p>
</name:form>
Change password controller
@PublicController
@RequestMapping("/change-password")
@SessionAttributes("changePasswordFormObject")
public class PublicChangePasswordController {
private SecurityService securityService;
@Autowired
public PublicChangePasswordController(SecurityService securityService) {
super();
this.securityService = securityService;
}
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setValidator(new ChangePasswordFormObjectValidator(securityService));
}
@RequestMapping()
public ModelAndView display(WebRequest webRequest) {
String username = (String) webRequest.getAttribute(DefaultAuthenticationFailureHandler.PASSWORD_CHANGE_USERNAME, RequestAttributes.SCOPE_SESSION);
if (!StringUtils.hasText(username)) {
// Redirect if no username is found on the session - user must have accessed it directly
return new ModelAndView("redirect:/");
}
ChangePasswordFormObject formObject = new ChangePasswordFormObject();
formObject.setUsername(username);
ModelAndView modelAndView = new ModelAndView("change-password/change-password");
modelAndView.addObject("changePasswordFormObject", formObject);
return modelAndView;
}
@RequestMapping("/save")
public String changePassword(@ModelAttribute("changePasswordFormObject") @Valid ChangePasswordFormObject formObject, BindingResult bindingResult,
WebRequest webRequest, SessionStatus sessionStatus) throws Exception {
if (bindingResult.hasErrors()) {
return "change-password/change-password";
}
ChangePasswordDetailsDto changePasswordDetailsDto = new ChangePasswordDetailsDto();
changePasswordDetailsDto.setUsername(formObject.getUsername());
changePasswordDetailsDto.setNewPassword(formObject.getNewPassword());
securityService.changePassword(changePasswordDetailsDto);
webRequest.removeAttribute(DefaultAuthenticationFailureHandler.PASSWORD_CHANGE_USERNAME, RequestAttributes.SCOPE_SESSION);
sessionStatus.setComplete();
return "redirect:/";
}
}
default public controller
@PublicController
@RequestMapping("/*")
public class DefaultPublicController {
private String servletContext = "public/";
@RequestMapping
public String handle(HttpServletRequest request) {
return request.getRequestURI().substring(request.getRequestURI().lastIndexOf(servletContext) + servletContext.length());
}
}
This is snippet from my app security config of the login failure handler to show the mapping URL
<bean id="authenticationFailureHandler" class="com.app.application.util.spring.security.DefaultAuthenticationFailureHandler">
<constructor-arg ref="daoFactory" />
<property name="defaultFailureUrl" value="/public/login?failed=true" />
<property name="changePasswordUrl" value="/public/change-password" />
<property name="suspendedUrl" value="/public/suspended" />
<property name="deletedUrl" value="/public/deleted" />
</bean>
public servlet
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="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/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"
>
<mvc:annotation-driven />
<context:component-scan base-package="com.name">
<context:include-filter type="annotation" expression="com.app.web.mvc.PublicController" />
</context:component-scan>
<context:annotation-config></context:annotation-config>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/public/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>