Search code examples
javaspringspring-bootspring-security

Spring security custom UsernamePasswordAuthenticationFilter not replacing default UsernamePasswordAuthenticationFilter


I'm trying to implement my own UsernamePasswordAuthenthicationFilter that authenticates every request from my frontend using firebase auth.

public class FireBaseAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 
        
        .
        .
        //Assigning roles happens here
        List<GrantedAuthority> authorities = new ArrayList<>();
        if (user.getCustomClaims() != null) {
            if (user.getCustomClaims().get("boss").equals("true")) {
                authorities.add(new SimpleGrantedAuthority("boss"));
            }
            if (user.getCustomClaims().get("admin").equals("true")) {
                authorities.add(new SimpleGrantedAuthority("admin"));
            }
            if (user.getCustomClaims().get("office").equals("true")) {
                authorities.add(new SimpleGrantedAuthority("office"));
            }
            if (user.getCustomClaims().get("warehouse").equals("true")) {
                authorities.add(new SimpleGrantedAuthority("warehouse"));
            }
            if (user.getCustomClaims().get("store").equals("true")) {
                authorities.add(new SimpleGrantedAuthority("store"));
            }

            SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(user.getEmail(), user.getUid(), authorities));

   
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
            user.getEmail(),
                user.getUid(),
                authorities
        );
    
            }

        filterChain.doFilter(request, response);
    }

}

Then i try and replace the default auth in my security config:

public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().disable().csrf().disable().httpBasic().disable().formLogin().disable()
                .addFilter(new FireBaseAuthenticationFilter())
                .sessionManagement().sessionCreationPolicy(STATELESS).and()
                .authorizeRequests()
                .anyRequest().authenticated();
    }
}

But for some reason my custom filter is never called during runtime? What am I missing here?


Solution

  • Example :

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable().cors().and().authorizeRequests()
                    .antMatchers(HttpMethod.POST, ChallengeConstant.AUTHORIZE_ENDPOINT).permitAll()
                    .antMatchers(HttpMethod.POST, ChallengeConstant.TOKEN_ENDPOINT).permitAll()
                    .antMatchers(HttpMethod.GET, "/*").permitAll()
                    .antMatchers(HttpMethod.GET, "/assets/**").permitAll()
                    .anyRequest().authenticated()
                    .and()
                    .addFilterBefore(new JWTFilter(userService, objectMapper), UsernamePasswordAuthenticationFilter.class)
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        }
    

    If you want to validate token :

    @AllArgsConstructor
    public class JWTFilter extends OncePerRequestFilter {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(JWTFilter.class);
        private final UserService userService;
        private final ObjectMapper objectMapper;
    
        @Override
        protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
            String token = httpServletRequest.getHeader(ChallengeConstant.AUTH_HEADER);
            if (token != null) {
                LOGGER.info("The request is authenticated. Performing Token validity");
                String userName;
                try {
                    userName = JWT.require(Algorithm.HMAC512(ChallengeConstant.DUMMY_SIGN.getBytes()))
                            .build()
                            .verify(token.replace(ChallengeConstant.TOKEN_PREFIX, ""))
                            .getSubject();
                } catch (JWTVerificationException ex) {
                    LOGGER.warn(String.format("Token is not valid. Token: %s", token), ex);
                    generateErrorResponse(httpServletResponse, ExceptionResponse.UNAUTHORIZED);
                    return;
                }
                LOGGER.info("Token is valid for username: {}", userName);
                try {
                    UserEntity userEntity = userService.findUserByName(userName);
                    List<GrantedAuthority> authList = userEntity.getAuthorizations()
                            .stream()
                            .map(authorizationEntity -> new SimpleGrantedAuthority(authorizationEntity.getAuth()))
                            .collect(Collectors.toList());
                    SecurityContextHolder.getContext().setAuthentication(
                            new UsernamePasswordAuthenticationToken(userEntity.getUserName(), userEntity.getPassword(), authList));
                    LOGGER.debug("User has been found by given username: {} with authorities: {}", userName, authList.toString());
                } catch (NotFoundException ex) {
                    LOGGER.warn("User couldn't be found with given username: {}", userName);
                    generateErrorResponse(httpServletResponse, ExceptionResponse.NOT_FOUND);
                    return;
                }
            }
            LOGGER.info("The request is NOT authenticated. It will continue to request chain.");
            filterChain.doFilter(httpServletRequest, httpServletResponse);
        }
    
        private void generateErrorResponse(HttpServletResponse httpServletResponse, ExceptionResponse exceptionResponse) throws IOException {
            LOGGER.trace("Generating http error response");
            httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
            httpServletResponse.setStatus(exceptionResponse.getStatus().value());
            ErrorResource errorResource = new ErrorResource(exceptionResponse.getCode(),
                    exceptionResponse.getMessage());
            httpServletResponse.getWriter().write(objectMapper.writeValueAsString(errorResource));
            LOGGER.trace("Error response is {}", errorResource.toString());
            httpServletResponse.getWriter().flush();
        }
    

    I think you can validate in Filter and return error response if it is not valid.