java-17spring-boot-3spring-security-6

Spring Security 6 Request Matchers


So I recently started working with Spring security and I kind of get what it does, however the one thing that is seriously aluding me is how the requestMatchers().hasRole() and requestMatchers.hasAuthority() works...

I understand how they get called and I have this piece of code here that I am trying to get working, but I am clearly doing something wrong as the SUPER_USER roll just does not get access to the /userManagement/** endpoints...

http
      //CSRF Protection
      .csrf(csrf -> csrf.disable())
      .authorizeHttpRequests(
        auth -> {
          auth
            //Whitelist URLS
            .requestMatchers("/auth/**").permitAll()

            //Authorize Requests
            .requestMatchers("/userManagement/**").hasRole(Role.SUPER_USER.name())
            .anyRequest().denyAll();
        }
      )

I have a Role enum like so...

@RequiredArgsConstructor
public enum Role {
  SUPER_USER(
    Set.of(
      SUPER_USER_READ,
      SUPER_USER_UPDATE,
      SUPER_USER_CREATE,
      SUPER_USER_DELETE
    )
  );

@Getter
  private final Set<Permission> permissions;

  public List<SimpleGrantedAuthority> getAuthorities() {
    List<SimpleGrantedAuthority> permissions = getPermissions().stream()
      .map(permission -> new SimpleGrantedAuthority(permission.getPermission()))
      .collect(Collectors.toList());
    permissions.add(new SimpleGrantedAuthority("ROLE_" + this.name()));
    return permissions;
  }

  public static Role fromString(String value) {
    for (Role role : Role.values()) {
      if (role.name().equalsIgnoreCase(value)) {
        return role;
      }
    }
    throw new LoginException("Invalid Role: " + value);
  }
}

With the permissions declaired in it's own Enum

@RequiredArgsConstructor
public enum Permission {
  SUPER_USER_READ("superuser:read"),
  SUPER_USER_UPDATE("superuser:update"),
  SUPER_USER_CREATE("superuser:create"),
  SUPER_USER_DELETE("superuser:delete");

  @Getter
  private final String permission;
}

My end goal is to be able to call this endpoint with a User that has a SuperUser role.

@RestController
@RequestMapping("/userManagement")
@RequiredArgsConstructor
public class UserManagementController {

  private final UserService userService;

  @GetMapping("/getUsers")
  public String getUsers() {
    return "getUsers";
  }

}

I am hoping someone would be able to give me some sort of lead as to what the issue can be?

I have spent hours scouring YouTube videos and looking through sample code that is simmilarly structured. No matter what changes I tried to apply eg. trying diffenent roles or using only the SuperUserRole or with the hasPermission method I am unable to get through this.

If I do this

//.requestMatchers("/userManagement/**").hasRole(Role.SUPER_USER.name())
//            .requestMatchers(HttpMethod.GET, "/userManagement/**").hasAuthority(Permission.SUPER_USER_READ.getPermission())
//            .anyRequest().denyAll();
.anyRequest.authenticated();

I get to my endpoint and get the expected result. This tells me that the problem lies in how I am handling this config.

And the console is not much help after enabling debug logging for Spring Boot as the only thing that comes up is this o.s.s.w.a.Http403ForbiddenEntryPoint - Pre-authenticated entry point called. Rejecting access and there is not much info that I can find as to how to resolve this


Solution

  • Okay so I figured it out...

    In the Enum I have the getAuthorities() method.

    What I neglected to do is in my User entity which is implementing org.springframework.security.core.userdetails.UserDetails

    In the overridden getAuthorities() I just needed to return this.role.getAuthorities()