Home > Mobile >  [[Edited]] JWT spring security: How to have roles be read by .hasRole() or .hasAuthority(), where th
[[Edited]] JWT spring security: How to have roles be read by .hasRole() or .hasAuthority(), where th

Time:12-07

I am trying to add an authorization to the spring actuator service using roles in the HTTP config but it doesn't work and the response is "forbidden 403" which means the user is unauthorized.
So My question is where exactly the .hasRole() finds the signed in user roles when using JWT token

Here is the config method in the class which extends WebSecurityConfigurerAdapter class

    protected void configure(HttpSecurity http) throws Exception {
    http.cors()
        .and()
        .csrf().disable()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .addFilterBefore(new JwtTokenVerifier(jwtConfig), UsernamePasswordAuthenticationFilter.class)
        .authorizeRequests()
        .antMatchers("/auth/**").permitAll()
        .antMatchers("/actuator/**").hasRole("ACTUATOR")
        .anyRequest()
        .authenticated()
        .and()
        .formLogin().disable();
    }   

Here I put the roles in the JWT Token

public String generateJwtToken(UserDetailsImpl userDetails) {
        Map<String, Object> claims = new HashMap<>();
        Set<String> Userroles = new HashSet<>();

        Role r1 = new Role();
        r1.setDescription("ROLE_ACTUATOR");
        r1.setId(1L);
        
        Set<Role> roles = new HashSet<>();
        roles.add(r1);
        
        for(Role role:roles){
            Userroles.add(role.getDescription());
        }
        claims.put("Roles",Userroles.toArray());
        claims.put("userId", userDetails.getId());
        
    return Jwts.builder()
            .setClaims(claims)
        .setSubject(userDetails.getUsername())
        
        .setIssuedAt(new Date())
        .setExpiration(java.sql.Date.valueOf(LocalDate.now().plusDays(getTokenExpirationAfterDays())))
        .signWith(Keys.hmacShaKeyFor(getSecretKey().getBytes())).compact();
    }  

So what is wrong or missing? Thanks in advance
Here is an update of the JWT custom filter:

public class JwtTokenVerifier extends OncePerRequestFilter {

    private JwtConfig jwtConfig;

    public JwtTokenVerifier(JwtConfig jwtConfig) {
    super();
    this.jwtConfig = jwtConfig;
    }

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

    String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
    if (authorizationHeader == null || authorizationHeader.isEmpty() || !authorizationHeader.startsWith(jwtConfig.getTokenPrefix())) {
        String requestParam = request.getParameter("token");
        if (requestParam != null && !requestParam.isEmpty() && requestParam.startsWith(jwtConfig.getTokenPrefix())) {
        authorizationHeader = requestParam;
        } else {
        filterChain.doFilter(request, response);
        return;
        }
    }
    try {
        if (jwtConfig.validateJwtToken(authorizationHeader)) {
        String username = jwtConfig.getUserNameFromJwtToken(authorizationHeader);

        Authentication auth = new UsernamePasswordAuthenticationToken(username, new WebAuthenticationDetailsSource().buildDetails(request), null);
        SecurityContextHolder.getContext().setAuthentication(auth);
        }

    } catch (Exception e) {
        e.printStackTrace();
        response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
    }
    filterChain.doFilter(request, response);
    }

}

CodePudding user response:

In the WebSecurityConfigurerAdapter extention, I see ACTUATOR, but in the user details definition I see ROLE_ACTUATOR. Is this a mismatch?

CodePudding user response:

Thanks to @SteveRiesenberg, as said in the chat "if roles are not handled by your custom JWT filter, then that is the issue. Roles (authorities) must be populated when the authentication is performed."
so since the roles are not handled in the filter, they are not passed through the security chain.
The code of the filter is edited as follows:

UserDetailsImpl userDetails  = (UserDetailsImpl) userDetailsService.loadUserByUsername(username);
Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
                
Authentication auth = new UsernamePasswordAuthenticationToken(username, new WebAuthenticationDetailsSource().buildDetails(request), authorities); 

Where the authorities are passed to the UsernamePasswordAuthenticationToken and UserDetailsImpl is the implementation of UserDetails class provided by spring

  • Related