0

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>
dynamo
  • 184
  • 13

0 Answers0