FC
FACADE
CODE
Lesson 5 of 28
FC
FACADE
CODE

Learn Spring Security

Contents

01. Bootstrap The Application
1. Introduction
2. Install Spring Security
3. Enable Basic Auth
4. Authentication with AppUser
5. Password Encoder
02. Web Layer Security - RBAC
6. Permit Public APIs
7. Role Based Authorization
8. Disable CSRF
9. Current Authenticated User
03. Web Layer Security - PBAC
10. Permission Based Authorization
11. Define Permissions
12. Assign Permissions
13. Remove Role Based Access
04. Service Layer Security
14. PreAuthorize
15. PostAuthorize
16. Authorize Using Spring Beans
05. Domain Object Instance Security
17. Domain Object Instance Security
18. PermissionEvaluator Interface
19. PermissionEvaluator Strategy
20. DB Backed UserDetailsService
06. Token Based Authentication
21. Basic Authentication Revisited
22. Generate Token
23. Persist Token
24. Verify Token
25. Invalidate Token
07. Token Based Authentication and Authorization
26. JSON Web Token
27. Generate JWT
28. Verify JWT

Password Encoder

In the last chapter, we mentioned that we have not encrypted the password for any users in the database. You might also have noticed from the ListStudents API response that the passwords are all just plain text.

Storing passwords in plain text is a terrible idea that any level of database compromise will expose your application users. It could be logging the passwords by mistake or inadequately securing the database dumps etc., We must encrypt the password using irreversible cryptographic functions that even the system / database administrators could not retrieve them.

In this chapter, we will introduce the most commonly used BCryptPasswordEncoder offered by Spring Security.

BCryptPasswordEncoder

BCryptPasswordEncoder is one of the implementations of the PasswordEncoder interface. It helps us to encode the password as well as match the raw password with the encoded password on authentication.

Let's create and register BCryptPasswordEncoder bean in the SecurityBean class.


@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

Encrypt the passwords

Autowire the PasswordEncoder in AppDataInitialiser, and then use it to encrypt the password for all the users before saving it in the database like below:


AppUser gruUser = AppUser.builder()
        .username("Gru")
        .password(passwordEncoder.encode("password"))
        .email("gru@email.com")
        .roles(Collections.singleton(instructorRole))
        .build();

Restarting the application triggers AppDataInitialiser to clear the database and recreate all the user records with encrypted passwords.

Update UserDetails

In order to let Spring Security know that we have used BCryptPasswordEncoder to encrypt the passwords, we might think to replace the prefix for each password from {noop} to {bcrypt}. But it is no longer required as Spring Security is already aware of the PasswordEncoder bean available in the ApplicationContext. Let's remove the prefix and map the password directly while creating the UserDetails list in DbUserDetailsService.


public List<UserDetails> getAllUserDetails() {
    return appUserRepository.findAll()
            .stream()
            .map(appUser -> User.builder()
                    .username(appUser.getUsername())
                    .password(appUser.getPassword())
                    .authorities(Collections.EMPTY_SET)
                    .build()
            )
            .collect(Collectors.toList());
}

In addition to encrypting the passwords, BCryptPasswordEncoder bean will be automatically used by Spring Security for password verification also using matches() method.

Restart the application and send a GET request to the ListStudents API from Postman as Bob user. You can see from the response that all the passwords are encrypted now.

Passwords are encrypted for all the users
Passwords are encrypted for all the users

Though the passwords are encrypted, it is still not a good practice to expose them in any manner. Let's add @JsonIgnore annotation to the password field in AppUser entity to ignore serializing it.

Passwords are removed from the response
Passwords are removed from the response