JWTFilter.java
package jasper.security.jwt;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jasper.component.ConfigCache;
import jasper.config.Props;
import jasper.domain.proj.HasOrigin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;
import java.io.IOException;
import static jasper.domain.proj.HasOrigin.isSubOrigin;
import static jasper.security.Auth.LOCAL_ORIGIN_HEADER;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/**
* Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is
* found.
*/
public class JWTFilter extends GenericFilterBean {
private static final Logger logger = LoggerFactory.getLogger(JWTFilter.class);
public static final String AUTHORIZATION_HEADER = "Authorization";
private final Props props;
private final TokenProvider tokenProvider;
private final TokenProviderImplDefault defaultTokenProvider;
private final ConfigCache configs;
public JWTFilter(Props props, TokenProvider tokenProvider, TokenProviderImplDefault defaultTokenProvider, ConfigCache configs) {
this.props = props;
this.tokenProvider = tokenProvider;
this.defaultTokenProvider = defaultTokenProvider;
this.configs = configs;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
var httpServletRequest = (HttpServletRequest) servletRequest;
if (!"OPTIONS".equalsIgnoreCase(httpServletRequest.getMethod())) {
var route = httpServletRequest.getRequestURI();
if (route.startsWith("/api/") || route.startsWith("/pub/api/")) {
var origin = resolveOrigin(httpServletRequest);
var jwt = resolveToken(httpServletRequest);
if (configs.root().web(origin)) {
if (tokenProvider.validateToken(jwt, origin)) {
SecurityContextHolder.getContext().setAuthentication(tokenProvider.getAuthentication(jwt, origin));
} else {
SecurityContextHolder.getContext().setAuthentication(defaultTokenProvider.getAuthentication(null, origin));
}
} else {
logger.error("{} No web access for origin ({}): {} ", props.getOrigin(), origin, route);
}
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
private String resolveToken(HttpServletRequest request) {
var bearerToken = request.getHeader(AUTHORIZATION_HEADER);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
private String resolveOrigin(HttpServletRequest request) {
var origin = props.getOrigin();
var originHeader = request.getHeader(LOCAL_ORIGIN_HEADER);
if (isNotBlank(originHeader)) {
originHeader = originHeader.toLowerCase();
logger.trace("Origin set by header ({})", originHeader);
if ("default".equals(originHeader)) return origin;
if (originHeader.matches(HasOrigin.REGEX_NOT_BLANK) && isSubOrigin(props.getLocalOrigin(), originHeader)) return originHeader;
} else {
logger.trace("Origin header not allowed to be blank");
}
logger.trace("Default origin used ({})", origin);
return origin;
}
}