Expand Authors Top

If you have a few years of experience in the Java ecosystem and you’d like to share that with the community, have a look at our Contribution Guidelines.

Expanded Audience – Frontegg – Security (partner)
announcement - icon User management is very complex, when implemented properly. No surprise here.

Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.
That's basically what Frontegg is - User Management for your application. It's focused on making your app scalable, secure and enjoyable for your users.
From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.

Have a look:

>> Elegant User Management, Tailor-made for B2B SaaS

November Discount Launch 2022 – Top
We’re finally running a Black Friday launch. All Courses are 30% off until end-of-day today:

>> GET ACCESS NOW

NPI – Frontegg – Security – (partner)
announcement - icon User management is very complex, when implemented properly. No surprise here.

Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.
That's basically what Frontegg is - User Management for your application. It's focused on making your app scalable, secure and enjoyable for your users.
From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.

Have a look:

>> Elegant User Management, Tailor-made for B2B SaaS

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:

@ExtendWith(SpringExtension.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");

    @BeforeEach
    public void init() {
        User user = userRepository.findByEmail("[email protected]");
        if (user == null) {
            user = new User();
            user.setFirstName("Test");
            user.setLastName("Test");
            user.setPassword(passwordEncoder.encode("test"));
            user.setEmail("[email protected]");
            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("[email protected]", "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("[email protected]", "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.

« Previous
Registration – Password Strength and Rules
November Discount Launch 2022 – Bottom
We’re finally running a Black Friday launch. All Courses are 30% off until end-of-day today:

>> GET ACCESS NOW

Security footer banner
Comments are closed on this article!