0

I have implemented SpringSecurity with JWT, all working nicely except one thing

@PreAuthorize("hasAuthority('admin:read')") isnt working, it gives

403 FORBIDDEN error

I will share parts of important codes. The token return all authorities properly which I added as SimpleGrantedAuthority

SecurityConfig

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...logic
}

AccountController

@RestController
@RequestMapping("/api")
public class AccountController {

    //this works
    @RequestMapping(value = "/accounts", method = RequestMethod.GET)
    @PreAuthorize("hasAnyRole('ROLE_ADMIN')")
    public ResponseEntity<?> loadAll() {
        List<AccountDTO> res = accountService.loadAll();
        return new ResponseEntity(new ResponseWrapper(res), HttpStatus.OK);
    }

    //this doesn't work
    @RequestMapping(value = "/accounts/{uid}", method = RequestMethod.GET)
    @PreAuthorize("hasAuthority('admin:read')")
    ResponseEntity<?> findByUId(@PathVariable String uid) throws Exception {
        AccountDTO dto = this.accountService.findByUid(uid);
        return new ResponseEntity<>(new ResponseWrapper(dto), HttpStatus.OK);
    }
}

Token

{
  "sub": "nenad.arbutina",
  "authorities": [
    {
      "authority": "ROLE_ADMIN"
    },
    {
      "authority": "admin:read"
    },
    {
      "authority": "admin:create"
    },
    {
      "authority": "admin:update"
    },
    {
      "authority": "admin:delete"
    }
  ],
  "iat": 1631111042,
  "exp": 1632261600
}

update on code. When debugged I am getting only ROLE_ADMIN, so I am confused

SecurityConfig

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final MyUserDetailService myUserDetailService;
    private final SecretKey secretKey;
    private final JwtConfig jwtConfig;

    @Autowired
    public SecurityConfig(
                          MyUserDetailService myUserDetailService,
                          SecretKey secretKey,
                          JwtConfig jwtConfig) {

        this.myUserDetailService = myUserDetailService;
        this.secretKey = secretKey;
        this.jwtConfig = jwtConfig;
    }
    @Bean
    PasswordEncoder getEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig, secretKey))
                .addFilterAfter(new JwtTokenVerifier(secretKey, jwtConfig), JwtUsernameAndPasswordAuthenticationFilter.class)
                .authorizeRequests()
                .antMatchers("/", "index","/css/*", "/js/*").permitAll()
                .anyRequest()
                .authenticated();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(daoAuthenticationProvider());
    }

    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider() {
        DaoAuthenticationProvider provider = new 
        DaoAuthenticationProvider();
        provider.setPasswordEncoder(getEncoder());
        provider.setUserDetailsService(myUserDetailService);
        return provider;
    }
}

JwtTokenVerifier

public class JwtTokenVerifier extends OncePerRequestFilter {

    private final SecretKey secretKey;
    private final JwtConfig jwtConfig;

    public JwtTokenVerifier(SecretKey secretKey,
                            JwtConfig jwtConfig) {
        this.secretKey = secretKey;
        this.jwtConfig = jwtConfig;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        String authorizationHeader = request.getHeader(jwtConfig.getAuthorizationHeader());

        if (Strings.isNullOrEmpty(authorizationHeader) || !authorizationHeader.startsWith(jwtConfig.getTokenPrefix())) {
            filterChain.doFilter(request, response);
            return;
        }
        String token = authorizationHeader.replace(jwtConfig.getTokenPrefix(), "");
        try {


            Jws<Claims> claimsJws = Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(token);
            Claims body = claimsJws.getBody();
            String username = body.getSubject();

            List<Map<String, String>> authorities = (List<Map<String, String>>) body.get("authorities");

            Set<SimpleGrantedAuthority> simpleGrantedAuthorities = authorities.stream()
                    .map(m -> new SimpleGrantedAuthority(m.get("authority")))
                    .collect(Collectors.toSet());

            Authentication authentication = new UsernamePasswordAuthenticationToken(
                    username,
                    null,
                    simpleGrantedAuthorities
            );

            SecurityContextHolder.getContext().setAuthentication(authentication);

            filterChain.doFilter(request, response);

        } catch (JwtException e ){
            throw new IllegalStateException(String.format("Token %s is not to be trusted", token));
        }
    }
}
Apostolos
  • 10,033
  • 5
  • 24
  • 39

0 Answers0