Table of Contents
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.