FC
FACADE
CODE
Lesson 13 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

Remove Role-Based Access

We have intentionally left the role-based access restrictions to few APIs in order to show you how to combine roles and permissions together. But going forward we will replace it completely with permission-based access control.

Let's modify HttpSecurity configuration by replacing hasRole() with hasAuthority() for each API using the appropriate permissions we have created in PermissionEnum.


@Bean
public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .authorizeRequests(auth -> auth
                .antMatchers(GET, PUBLIC_API_LIST).permitAll()
                .antMatchers(API_LIST_STUDENTS).hasAuthority(LIST_STUDENTS.name())
                .antMatchers(API_LIST_INSTRUCTORS).hasAuthority(LIST_INSTRUCTORS.name())
                .antMatchers(API_VIEW_PROFILE).hasAuthority(VIEW_PROFILE.name())
                .antMatchers(POST, API_CREATE_COURSES).hasAuthority(CREATE_COURSE.name())
                .antMatchers(PUT, API_UPDATE_COURSES).hasAuthority(UPDATE_COURSE.name())
                .antMatchers(API_PLAY_COURSE).hasAuthority(PLAY_COURSE.name())
                .anyRequest().authenticated()
        )
        .httpBasic();
    return http.build();
}

Remove roles from Authorities

With only hasAuthority() used to secure each REST API we no longer need to provide the roles assigned to each user. So we can directly map getPermissions() in authorities() and remove getRoles() and getRolesAndPermissions() altogether in DbUserDetailService.


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

private String[] getPermissions(Set<AppRole> roles) {
    return roles.stream()
        .flatMap(role -> role.getPermissions().stream())
        .map(permission -> permission.getName().name())
        .collect(Collectors.toSet())
        .toArray(new String[0]);
} 

This got even more simplified where we no longer required to combine roles (by prefixing it with ROLE_) and permissions. And we no longer need to care about the authorities override issues we highlighted in Chapter 7.

Finally we will have each APIs secured against its own permission, and users with only the permissions corresponding to the APIs they can access as their authorities as mentioned in the below table.

UserAuthorities
Bob, Kevin, StuartPLAY_COURSE, VIEW_PROFILE
Gru, LucyCREATE_COURSE, UPDATE_COURSE, PLAY_COURSE, VIEW_PROFILE
AdminLIST_STUDENTS, LIST_INSTRUCTORS, VIEW_PROFILE

Note

  1. There will be no change in the API access behaviour after replacing the Role-based API access with Permission-based API access.
  2. In addition to Play Course, we have secured Update Course as well as View Profile APIs with its own permissions, but still these three APIs have not met the Security Objectives defined in Chapter 1