1

Currently performing the upgrade from Spring Boot v2.3.5 to v2.4.0. However, I'm running into a problem in regards to setting the SecurityContextHolder when a user is authenticated and actually going through the FilterChain.

The problematic code is part of a class that extends the BasicAuthenticationFilter and looks like this:

    /**
     * Perform the filter for authentication
     *
     * @param request  The HttpServletRequest
     * @param response The HttpServletResponse
     * @param chain    The FilterChain
     * @throws IOException      When the filter could not be performed
     * @throws ServletException When the filter could not be performed
     */
    @Override
    protected void doFilterInternal(final HttpServletRequest request,
                                    final HttpServletResponse response,
                                    final FilterChain chain) throws IOException, ServletException {
        final String header = request.getHeader(jwtConfiguration.getHeader());

        if (header == null || !header.startsWith(jwtConfiguration.getTokenPrefix())) {
            chain.doFilter(request, response);
            return;
        }

        final UsernamePasswordAuthenticationToken authentication = getAuthentication(request);

        if (authentication == null) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
        } else {
            final SecurityContext context = SecurityContextHolder.createEmptyContext();

            context.setAuthentication(authentication);
            SecurityContextHolder.setContext(context);

            chain.doFilter(request, response); // The exception is thrown here, but only when setting the SecurityContextHolder
        }
    }


...

    /**
     * Get the UsernamePasswordAuthenticationToken from the HttpServletRequest
     *
     * @param request The HttpServletRequest
     * @return The UsernamePasswordAuthenticationToken that was filtered from the HttpServletRequest
     */
    private UsernamePasswordAuthenticationToken getAuthentication(final HttpServletRequest request) {
        final String token = request.getHeader(jwtConfiguration.getHeader());
        if (token != null && !token.isEmpty()) {
            final UserDto user = authorizationService.getCurrentUser(token);

            if (user != null) {
                final Set<GrantedAuthority> grantedAuthorities = new HashSet<>();

                if (user.getRoles() != null) {
                    for (final RoleDto role : user.getRoles()) {
                        if (role.getPermissions() != null) {
                            for (final PermissionDto permission : role.getPermissions()) {
                                grantedAuthorities.add(new SimpleGrantedAuthority(permission.getName()));
                            }
                        }
                    }
                }

                return new UsernamePasswordAuthenticationToken(user, null, grantedAuthorities);
            }
            return null;
        }
        return null;
    }

Without setting the SecurityContextHolder the code works just fine, but unfortunately, the Authentication will not be set, which isn't the result I'm after since I'd like to secure certain endpoints.

The class that extends WebSecurityConfigurerAdapter is set up like so:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final JwtConfiguration jwtConfiguration;
    private final IAuthorizationService userService;

    /**
     * Initialize a new WebSecurityConfiguration
     *
     * @param jwtConfiguration The JwtConfiguration object
     * @param userService      The IAuthorizationService implementation
     */
    public WebSecurityConfiguration(@Autowired final JwtConfiguration jwtConfiguration,
                                    @Autowired final IAuthorizationService userService) {
        if (jwtConfiguration == null)
            throw new NullPointerException("JwtConfig cannot be null!");
        if (userService == null)
            throw new NullPointerException("IAuthorizationService cannot be null!");

        this.jwtConfiguration = jwtConfiguration;
        this.userService = userService;
    }

    /**
     * Configure the HttpSecurity
     *
     * @param http The HttpSecurity object
     * @throws Exception When the configuration failed
     */
    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        final AuthenticationManager authenticationManager = authenticationManager();

        http
                .csrf().disable().cors().and()
                .authorizeRequests()
                .antMatchers("/authentication/**",
                        "/v2/api-docs",
                        "/configuration/ui",
                        "/swagger-resources/**",
                        "/configuration/security",
                        "/swagger-ui.html",
                        "/webjars/**")
                .permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilterBefore(new JwtAuthorizationFilter(authenticationManager, jwtConfiguration, userService), JwtAuthorizationFilter.class)
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

The exception itself, that occurs when setting the SecurityContextHolder, when passing through the chain is as follows:

java.lang.IllegalStateException: No primary or single public constructor found for interface org.springframework.security.core.Authentication - and no default constructor found either

Exception Stacktrace

João Dias
  • 16,277
  • 6
  • 33
  • 45

0 Answers0