Updating your Password

1. Overview

In this quick article we’ll implement a simple “Change my own password” functionality available to the user after they register and log in.

2. Client Side – Change My Password Page

Let’s take a look at the very simple client side page:

<html>
<body>
<div id="errormsg" style="display:none"></div>
<div>
    <input id="oldpass" name="oldpassword" type="password" />
    <input id="pass" name="password" type="password" />
    <input id="passConfirm" type="password" />              
    <span id="error" style="display:none">Password mismatch</span>
                    
   <button type="submit" onclick="savePass()">Change Password</button>
</div>
 
<script src="jquery.min.js"></script>
<script type="text/javascript">

var serverContext = [[@{/}]];
function savePass(){
    var pass = $("#pass").val();
    var valid = pass == $("#passConfirm").val();
    if(!valid) {
      $("#error").show();
      return;
    }
    $.post(serverContext + "user/updatePassword",
      {password: pass, oldpassword: $("#oldpass").val()} ,function(data){
        window.location.href = serverContext +"/home.html?message="+data.message;
    })
    .fail(function(data) {
        $("#errormsg").show().html(data.responseJSON.message);
    });
}
</script> 
</body>
</html>

3. Update User Password

Let’s now implement the server side operation as well:

@PostMapping("/user/updatePassword")
@PreAuthorize("hasRole('READ_PRIVILEGE')")
public GenericResponse changeUserPassword(Locale locale, 
  @RequestParam("password") String password, 
  @RequestParam("oldpassword") String oldPassword) {
    User user = userService.findUserByEmail(
      SecurityContextHolder.getContext().getAuthentication().getName());
    
    if (!userService.checkIfValidOldPassword(user, oldPassword)) {
        throw new InvalidOldPasswordException();
    }
    userService.changeUserPassword(user, password);
    return new GenericResponse(messages.getMessage("message.updatePasswordSuc", null, locale));
}

Notice how the method is secured via the @PreAuthorize annotation, since it should only accessible to logged in users.

4. API Tests

Finally, let’s consume the API with some API tests to make sure everything is working fine; we’ll start with the simple configuration of the test and the data initialization:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  classes = { ConfigTest.class, PersistenceJPAConfig.class }, 
  loader = AnnotationConfigContextLoader.class)
public class ChangePasswordApiTest {
    private final String URL_PREFIX = "http://localhost:8080/"; 
    private final String URL = URL_PREFIX + "/user/updatePassword";
    
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    FormAuthConfig formConfig = new FormAuthConfig(
      URL_PREFIX + "/login", "username", "password");

    @Before
    public void init() {
        User user = userRepository.findByEmail("test@test.com");
        if (user == null) {
            user = new User();
            user.setFirstName("Test");
            user.setLastName("Test");
            user.setPassword(passwordEncoder.encode("test"));
            user.setEmail("test@test.com");
            user.setEnabled(true);
            userRepository.save(user);
        } else {
            user.setPassword(passwordEncoder.encode("test"));
            userRepository.save(user);
        }
    }
}

Now – let’s try to change password for a logged in user:

@Test
public void givenLoggedInUser_whenChangingPassword_thenCorrect() {
    RequestSpecification request = RestAssured.given().auth()
      .form("test@test.com", "test", formConfig);

    Map<String, String> params = new HashMap<String, String>();
    params.put("oldpassword", "test");
    params.put("password", "newtest");

    Response response = request.with().params(params).post(URL);

    assertEquals(200, response.statusCode());
    assertTrue(response.body().asString().contains("Password updated successfully"));
}

Next – let’s try to change password given a wrong old password:

@Test
public void givenWrongOldPassword_whenChangingPassword_thenBadRequest() {
    RequestSpecification request = RestAssured.given().auth()
      .form("test@test.com", "test", formConfig);

    Map<String, String> params = new HashMap<String, String>();
    params.put("oldpassword", "abc");
    params.put("password", "newtest");

    Response response = request.with().params(params).post(URL);

    assertEquals(400, response.statusCode());
    assertTrue(response.body().asString().contains("Invalid Old Password"));
}

Finally – let’s try to change password without authentication:

@Test
public void givenNotAuthenticatedUser_whenChangingPassword_thenRedirect() {
    Map<String, String> params = new HashMap<String, String>();
    params.put("oldpassword", "abc");
    params.put("password", "xyz");

    Response response = RestAssured.with().params(params).post(URL);

    assertEquals(302, response.statusCode());
    assertFalse(response.body().asString().contains("Password updated successfully"));
}

Note how – for each test – we’re providing a FormAuthConfig to handle the authentication.

We’re also resetting the password via init() to make sure we use the correct password before test.

5. Conclusion

And that’s a wrap – a straightforward way to allow the user to change their own password after registering and logging into the application.

The full implementation of this tutorial can be found in the github project – this is an Eclipse based project, so it should be easy to import and run as it is.

Related posts:

Spring – Injecting Collections
Java Program to Check if a Point d lies Inside or Outside a Circle Defined by Points a, b, c in a Pl...
Spring @RequestMapping New Shortcut Annotations
Java 8 Streams peek() API
Java Program to Implement Quick Sort with Given Complexity Constraint
Java Program to Generate Random Numbers Using Multiply with Carry Method
Java Program to implement Sparse Vector
Java Program to Remove the Edges in a Given Cyclic Graph such that its Linear Extension can be Found
How to Break from Java Stream forEach
Returning Custom Status Codes from Spring Controllers
Java Program to Implement Meldable Heap
An Intro to Spring Cloud Security
Java – Reader to Byte Array
Mệnh đề if-else trong java
Java Program to Implement Find all Forward Edges in a Graph
Create Java Applet to Simulate Any Sorting Technique
Spring Boot - Tracing Micro Service Logs
LIKE Queries in Spring JPA Repositories
How to Get a Name of a Method Being Executed?
Toán tử instanceof trong java
Examine the internal DNS cache
Tính trừu tượng (Abstraction) trong Java
Spring’s RequestBody and ResponseBody Annotations
Giới thiệu java.io.tmpdir
Java Program to Implement PriorityQueue API
A Guide to Queries in Spring Data MongoDB
ClassNotFoundException vs NoClassDefFoundError
Migrating from JUnit 4 to JUnit 5
Java 9 Stream API Improvements
Java Program to Perform Postorder Recursive Traversal of a Given Binary Tree
Guide to the Fork/Join Framework in Java
Java Program to Implement the String Search Algorithm for Short Text Sizes