Reputation: 649
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?
Upvotes: 0
Views: 610
Reputation: 158
Your custom implementation extends the UsernamePasswordAuthenticationFilter (which in its turn extends the AbstractAuthenticationProcessingFilter). The UsernamePasswordAuthenticationFilter, by default, is used for .formLogin authentication, handling the default AntRequestMatcher "/login". If you use a different protected endpoint, the filter's attemptAuthentication() method never gets action. So, if you want to use a different matcher (a different protected endpoint), you have to override the default AntRequestMatcher. For instance, you can do so within your custom filter constructor, by using something like that:
super.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/auth/signin", "GET"));
Upvotes: 0
Reputation: 1573
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.
Upvotes: 1