RoleUpdateInterceptor.java

1
package edu.ucsb.cs156.frontiers.interceptors;
2
3
import edu.ucsb.cs156.frontiers.repositories.AdminRepository;
4
import edu.ucsb.cs156.frontiers.repositories.InstructorRepository;
5
import jakarta.servlet.http.HttpServletRequest;
6
import jakarta.servlet.http.HttpServletResponse;
7
import java.util.Collection;
8
import java.util.HashSet;
9
import java.util.Set;
10
import org.springframework.security.core.Authentication;
11
import org.springframework.security.core.GrantedAuthority;
12
import org.springframework.security.core.authority.SimpleGrantedAuthority;
13
import org.springframework.security.core.context.SecurityContext;
14
import org.springframework.security.core.context.SecurityContextHolder;
15
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
16
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
17
import org.springframework.stereotype.Component;
18
import org.springframework.web.servlet.HandlerInterceptor;
19
20
/**
21
 * RoleUpdateInterceptor reloads a user's security context on each request to the backend. This is
22
 * necessary to ensure that the user has the correct roles and does not have to log in or out to
23
 * have access to restricted endpoints.
24
 *
25
 * <p>To prevent interference with @WebMvcTest test slices, ControllerTestCase contains a
26
 * passthrough RoleUpdateInterceptor MockitoBean so that every ControllerTestCase is not required to
27
 * add an AdminRepository and InstructorRepository MockitoBean.
28
 */
29
@Component
30
public class RoleUpdateInterceptor implements HandlerInterceptor {
31
32
  private final AdminRepository adminRepository;
33
34
  private final InstructorRepository instructorRepository;
35
36
  public RoleUpdateInterceptor(
37
      AdminRepository adminRepository, InstructorRepository instructorRepository) {
38
    this.adminRepository = adminRepository;
39
    this.instructorRepository = instructorRepository;
40
  }
41
42
  @Override
43
  public boolean preHandle(
44
      HttpServletRequest request, HttpServletResponse response, Object handler) {
45
    // Update user's security context on server each time the user makes HTTP request to the backend
46
    // If user has admin or instructor status in database, we will update their roles in security
47
    // context
48
    SecurityContext securityContext = SecurityContextHolder.getContext();
49
    Authentication authentication = securityContext.getAuthentication();
50
51 1 1. preHandle : negated conditional → KILLED
    if (authentication instanceof OAuth2AuthenticationToken) {
52
      OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
53 1 1. preHandle : negated conditional → KILLED
      if (oauthToken.getPrincipal() instanceof OidcUser) {
54
        OidcUser oidcUser = (OidcUser) oauthToken.getPrincipal();
55
        String email = oidcUser.getEmail();
56
        Set<GrantedAuthority> newAuthorities = new HashSet<>();
57
        Collection<? extends GrantedAuthority> currentAuthorities = authentication.getAuthorities();
58
59
        // Copy all existing authorities except ROLE_ADMIN and ROLE_INSTRUCTOR
60
        currentAuthorities.stream()
61
            .filter(
62
                authority ->
63 2 1. lambda$preHandle$0 : replaced boolean return with true for edu/ucsb/cs156/frontiers/interceptors/RoleUpdateInterceptor::lambda$preHandle$0 → KILLED
2. lambda$preHandle$0 : negated conditional → KILLED
                    !authority.getAuthority().equals("ROLE_ADMIN")
64 1 1. lambda$preHandle$0 : negated conditional → KILLED
                        && !authority.getAuthority().equals("ROLE_INSTRUCTOR"))
65 1 1. preHandle : removed call to java/util/stream/Stream::forEach → KILLED
            .forEach(newAuthorities::add);
66
67
        // Check if user is admin or instructor and add appropriate role
68 1 1. preHandle : negated conditional → KILLED
        if (adminRepository.existsByEmail(email)) {
69
          newAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
70 1 1. preHandle : negated conditional → KILLED
        } else if (instructorRepository.existsByEmail(email)) {
71
          newAuthorities.add(new SimpleGrantedAuthority("ROLE_INSTRUCTOR"));
72
        }
73
74
        // Create new authentication with updated authorities
75
        Authentication newAuth =
76
            new OAuth2AuthenticationToken(
77
                oidcUser, newAuthorities, oauthToken.getAuthorizedClientRegistrationId());
78
79
        SecurityContextHolder.getContext().setAuthentication(newAuth);
80
      }
81
    }
82
83 1 1. preHandle : replaced boolean return with false for edu/ucsb/cs156/frontiers/interceptors/RoleUpdateInterceptor::preHandle → KILLED
    return true;
84
  }
85
}

Mutations

51

1.1
Location : preHandle
Killed by : edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests]/[method:non_oauth_authentication_handled()]
negated conditional → KILLED

53

1.1
Location : preHandle
Killed by : edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests]/[method:skip_oauth2()]
negated conditional → KILLED

63

1.1
Location : lambda$preHandle$0
Killed by : edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests]/[method:admin_role_removed_when_user_loses_admin_status()]
replaced boolean return with true for edu/ucsb/cs156/frontiers/interceptors/RoleUpdateInterceptor::lambda$preHandle$0 → KILLED

2.2
Location : lambda$preHandle$0
Killed by : edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests]/[method:admin_role_removed_when_user_loses_admin_status()]
negated conditional → KILLED

64

1.1
Location : lambda$preHandle$0
Killed by : edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests]/[method:admin_role_removed_when_user_loses_admin_status()]
negated conditional → KILLED

65

1.1
Location : preHandle
Killed by : edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests]/[method:admin_role_removed_when_user_loses_admin_status()]
removed call to java/util/stream/Stream::forEach → KILLED

68

1.1
Location : preHandle
Killed by : edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests]/[method:admin_role_removed_when_user_loses_admin_status()]
negated conditional → KILLED

70

1.1
Location : preHandle
Killed by : edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests]/[method:admin_role_removed_when_user_loses_admin_status()]
negated conditional → KILLED

83

1.1
Location : preHandle
Killed by : edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.interceptors.RoleUpdateInterceptorTests]/[method:other_authorities_preserved_while_updating_roles()]
replaced boolean return with false for edu/ucsb/cs156/frontiers/interceptors/RoleUpdateInterceptor::preHandle → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0