servlet Filter is not allowing to load application resources - filter

I am trying to prevent CSRF(Cross site request forgery). To prevent CSRF I have created filter which will filter every request.
After implementing the javax.servlet.Filter as expected filter does its job. But after implementing servlet filter my application resources are not loading properly.
CSS, jQuery, datatable, all the resources are not loading properly, some time they are loading, some time not.
Before implementing the filter it was working fine.
Sample error in firebug:
"NetworkError: 500 Internal Server Error - http://localhost:8080/myApp/resources/images/bg-report-content.jpg"
"NetworkError: 500 Internal Server Error - http://localhost:8080/myApp/resources/images/bg-header.jpg"
tworkError: 500 Internal Server Error - http://localhost:8080/myApp/resources/css/dataTables.bootstrap.css"
"NetworkError: 500 Internal Server Error - http://localhost:8080/myApp/resources/js/fnStandingRedraw.js"
"NetworkError: 500 Internal Server Error - http://localhost:8080/myApp/resources/js/dataTables.tableTools.js"
This How I implemented the Filter for CSRF
What I am doing is , I have created a class called LoadSalt whic creates the salt(random number). that random number I am taking in jsp. and along with the jsp I am sending it with the request.
LoadSalt calss
public class LoadSalt implements Filter{
public Cache<String, Boolean> csrfPreventionSaltCache= null;
HttpServletRequest httpReq=null;
//int count=0;
#SuppressWarnings("unchecked")
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//count++;
// Assume its HTTP
httpReq = (HttpServletRequest)request;
if(httpReq.getAttribute("csrfPreventionSaltCache")!=null)
{
csrfPreventionSaltCache= (Cache<String, Boolean>) httpReq.getAttribute("csrfPreventionSaltCache");
}
if(csrfPreventionSaltCache == null)
{
// creating a new cache
csrfPreventionSaltCache = CacheBuilder.newBuilder().maximumSize(5000)
.expireAfterAccess(5, TimeUnit.MINUTES).build();
// Setting to httpReq
httpReq.setAttribute("csrfPreventionSaltCache", csrfPreventionSaltCache);
}
// Generate the salt and store it in the users cache
String salt = RandomStringUtils.random(20, 0, 0, true, true, null, new SecureRandom());
//System.out.println("Salt: "+salt);
csrfPreventionSaltCache.put(salt, Boolean.TRUE);
// Add the salt to the current request so it can be used
// by the page rendered in this request
httpReq.setAttribute("csrfPreventionSalt", salt);
chain.doFilter(httpReq, response);
}
public void init(FilterConfig arg0) throws ServletException {
}
public void destroy() {
}
}
The another filter which validate the salt
public class ValidateSalt implements Filter {
public Cache<String, Boolean> csrfPreventionSaltCache= null;
#SuppressWarnings("unchecked")
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// Assume its HTTP
HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpResponse =(HttpServletResponse) response;
String salt =(String) httpReq.getAttribute("csrfPreventionSalt");
// Validate that the salt is in the cache
if(httpReq.getAttribute("csrfPreventionSaltCache")!=null)
{
csrfPreventionSaltCache = (Cache<String, Boolean>) httpReq.getAttribute("csrfPreventionSaltCache");
}
if(csrfPreventionSaltCache !=null && salt !=null && csrfPreventionSaltCache.getIfPresent(salt)!=null)
{
String metodName =httpReq.getMethod();
String saltFromJspPage = httpReq.getParameter("salt");
//String saltFromRequest =(String) httpReq.getAttribute("csrfPreventionSalt");
if(metodName.equalsIgnoreCase("POST"))
{
if(saltFromJspPage!=null && csrfPreventionSaltCache.getIfPresent(saltFromJspPage)!=null)
{
chain.doFilter(httpReq, response);
else
{
//throw new ServletException("Potential CSRF detected!! Please contact to system admin ASAP.");
httpResponse.sendRedirect("/myApp/pages/pageNotFound.jsp");
}
}
else
{
chain.doFilter(httpReq, response);
}
}
else
{
// Otherwise we throw an exception aborting the request flow
//throw new ServletException("Potential CSRF detected!! Inform a scary sysadmin ASAP.");
httpResponse.sendRedirect("/myApp/pages/pageNotFound.jsp");
}
}
public void init(FilterConfig arg0) throws ServletException {
}
public void destroy() {
}
}
servlet filter mapping in web.xml
<filter>
<filter-name>loadSalt</filter-name>
<filter-class>com.mpApp.security.LoadSalt</filter-class>
</filter>
<filter-mapping>
<filter-name>loadSalt</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>validateSalt</filter-name>
<filter-class>com.mpApp.security.ValidateSalt</filter-class>
</filter>
<filter-mapping>
<filter-name>validateSalt</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
What is wrong with my application?
Why servlet filter is not allowing to load resources?, though some time it does work , some time it does not,
What is the route cause of this?
Am I implementing servlet filter in wrong way.
please help.

The url pattern is too wide, will try to apply the salt to every request. Keep it to the dynamic parts you can set and check the salt value, like /transferOperationServlet or /prettyImportantServlet or *.jsp

Related

Spring Security exclude URL in timeout

In Spring Security, how to exclude one particular URL from resetting the session timeout? Overall application session timeout(server.servlet.session.timeout) is 15 minutes. We have a ajax call from the web page that will get called every 1 minute. This call needs to be secured, but should not impact the session time.
We have tried adding a filter extending ConcurrentSessionFilter. Also, a filter extending SessionManagementFilter. Adding ignoring() skips authentication too. Nothing helped. Can this requirement be achieved in Spring Security? Any suggestions?
This is how i handled it. Just sharing, it may be of help to someone. Please share any better ways.
Spring Security filter is added as last in the chain.
http.addFilterAfter(new SessionInvalidationFilter(timeOutInMinutes), SwitchUserFilter.class);
It keeps track of a lastUpdatedTime, which gets updated for all calls except for those URLs that needs to be ignored. In case, the differential time is greater than the configured timeout, session gets invalidated.
public class SessionInvalidationFilter extends GenericFilterBean {
private static final String LASTUPDATEDDATETIME = "LASTUPDATEDDATETIME";
private static final List<String> ignoredURLs = Arrays.asList("/Notifications/number"); // this is the AJAX URL
private int timeOutInMinutes = 15;
public SessionInvalidationFilter(int timeOutInMinutes) {
this.timeOutInMinutes = timeOutInMinutes;
}
#Override
/**
* LASTUPDATEDDATETIME is updated for all calls except the ignoredURLs.
* Session invalidation happens only during the ignoredURLs calls.
*/
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
try {
if (session != null && request.getRequestURI() != null) {
if (ignoredURLs.contains(request.getRequestURI())) {
Object lastUpdatedDateTimeObject = session.getAttribute(LASTUPDATEDDATETIME);
if (lastUpdatedDateTimeObject != null) {
LocalDateTime lastUpdatedDateTime = (LocalDateTime) lastUpdatedDateTimeObject;
long timeInMinutes = ChronoUnit.MINUTES.between(lastUpdatedDateTime, LocalDateTime.now());
if (timeInMinutes >= timeOutInMinutes) {
log.info("Timing out sessionID:{}", session.getId());
session.invalidate();
SecurityContextHolder.clearContext();
}
}
} else {
session.setAttribute(LASTUPDATEDDATETIME, LocalDateTime.now());
}
}
} catch (Exception e) {
log.error("Exception in SessionInvalidationFilter", e);
}
chain.doFilter(request, response);
}
}

HttpServletRequest getting new session

I have an application that does authentication via oauth.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpResp = (HttpServletResponse) response;
// Check if already logged in
if (getUser(httpReq) != null) {
chain.doFilter(request, response);
return;
}
// Try to parse auth response
if (procAuthResponse(httpReq)) {
chain.doFilter(request, response);
return;
}
// Go to auth server
sendAuthRequest(httpReq, httpResp);
}
This works fine.
In the method procAuthResponse I am paring the response from the server and to this.
HttpSession session = request.getSession();
session.setAttribute(USER_PRINCIPLE_ATR, userInfo);
It works also well, but there is a session scoped class with the method getCurrent user, that is used by servlets.
public UserInfo getCurrentUser() {
HttpSession session = getHttpSession();
if (session == null) {
LOG.warn("Method getCurrentUser: unable to find a session");
return null;
}
Object user = session.getAttribute(OAuthLoginFilter.USER_PRINCIPLE_ATR);
if (!(user instanceof UserInfo)) {
LOG.warn(String.format("Method getCurrentUser, wrong type for attribute %s", OAuthLoginFilter.USER_PRINCIPLE_ATR));
return null;
}
currentUser = (UserInfo) user;
return currentUser;
}
This method gets called multiple times and it turnes out that on the first call everything works as expected and after that the getHttpSession() returns a different session that does not contain any information that is set in the filter class. It is not a new session every time, the session without the needed information is always the same.
Code of getHttpSession()
private HttpSession getHttpSession() {
Object request = FacesContext.getCurrentInstance().getExternalContext().getRequest();
if (!(request instanceof HttpServletRequest)) {
LOG.warn("not a valid http request");
return null;
}
HttpServletRequest hreq = (HttpServletRequest) request;
return hreq.getSession(false);
}
Do you have any idea why this happens?
Thx for your help
There was still an old filter class, not configured in the web.xml, but annotated with #WebFilter("/*").
I deleted this file and now everything works as expected.

Spring interceptor intercepting late

Spring boot 2.1.7 running a test server -- need to check my cache for a hit using the url as key, and then act based on a cache hit or not.
I send a request from my browser for https://localhost:8443/test/param=value --- my filter picks it up, and using code from another answer on SO, the filter constructs the url -- the filter code sees the url is https://localhost:8443/test?param=value
Great!
Then my interceptor gets hit (thanks to Theo on SO), but it thinks the url is https://localhost:8443/favicon.ico -- what's up with that? Not much of an interceptor if I didn't get to intercept the original /test url.
To get around that, in the filter, I stored the "real" url in the ServletContext, and that variable is read out correctly in the interceptor. Seems like an awful hack, and silly that I have to do it. For now I've hard-coded the decision to redirect to url /test2, but back in Chrome, I see the output from test1, not test2.
The network tab in Chrome seems to suggest:
that I was redirected to test2, but only after a request for favicon got inserted (for whatever mysterious reason) and yet as the image shows, the output is clearly test1, not test2.
Something I don't understand is that devtools also shows a response from test2:
#WebFilter( urlPatterns = "/test", description = "a filter for test servlet", initParams = {
#WebInitParam( name = "msg", value = "==> " ) }, filterName = "test filter" )
public class TestFilter implements Filter
{
private FilterConfig filterConfig;
#Override
public void doFilter( ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain )
throws IOException, ServletException
{
String url = getCurrentUrlFromRequest( servletRequest );
// in the debugger, url is correctly shown as
// https://localhost:8443/test/param=value
if ( null != url )
{
ServletContext s = servletRequest.getServletContext();
s.setAttribute( "realUrl", url );
}
servletResponse.getOutputStream().print( filterConfig.getInitParameter( "msg" ) );
filterChain.doFilter( servletRequest, servletResponse );
public String getCurrentUrlFromRequest( ServletRequest request )
{
if ( !( request instanceof HttpServletRequest ) ) return null;
return getCurrentUrlFromRequest( (HttpServletRequest) request );
}
public String getCurrentUrlFromRequest( HttpServletRequest request )
{
StringBuffer requestURL = request.getRequestURL();
String queryString = request.getQueryString();
if ( queryString == null ) return requestURL.toString();
return requestURL.append( '?' ).append( queryString ).toString();
}
#Override
public void destroy()
{
}
#Override
public void init( FilterConfig filterConfig ) throws ServletException
{
this.filterConfig = filterConfig;
}
}
//then the interceptor:
#Component
public class CheckForCacheInterceptor implements HandlerInterceptor
{
#Bean
public MappedInterceptor myInterceptor()
{
CheckForCacheInterceptor ci = new CheckForCacheInterceptor();
ci.setRedirectMapping( "/test2" );
return new MappedInterceptor( null, ci );
}
private String redirectMapping;
#Override
public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler )
{
String url = (String) request.getServletContext().getAttribute( "realUrl" );
// "realUrl" has https://localhost:8443/test/param=value, but I'd like
// to get rid of hack. Problem is that right here, running the same
// exact code (copy/paste of filter's
// getCurrentUrlFromRequest( HttpServletRequest request ) method )
//which gets the correct url in the filter yields
// https://localhost:8443/favicon.ico -- where did that come from?
// TODO check cache using requestUrl as key
boolean foundInCache = false;
if ( foundInCache )
{
// TODO: somehow write cache value to response
// then send response
return false;
} else
{
try
{
// TODO: make direct request,
// get response body, then
response.sendRedirect( redirectMapping );
return false;
} catch ( IOException e )
{
e.printStackTrace();
}
}
return false;
}
So before my questions pile up to the ceiling, I'll ask for help -- how is this favicon request sneaking in before my interceptor even has a crack at the original url, why can't I get the original url in my interceptor, and given that the Chrome devtools shows I am getting through to test2, how is the output coming from the test1 servlet instead of the test2 servlet?
FWIW, I'm getting the exact same behavior in Postman. Thanks so much for any help!
I read another answer on SO (sorry I don't have the link) which has fixed the issue of not intercepting the initial get request to /test -- it said that interceptors only intercept requests going to Controllers, so I needed to have a Controller which was mapped to /test. After writing a quickie Controller, the interceptor is now intercepting as one might expect.

How to know the handler spring controller class and the handler method for the specified HttpServletRequest object

I need to somehow access the handler method with the reflection in the web filter and get the requestPattern value without passing the control to the dispatcher servlet. How can I do this?
I only have for that HttpServletRequest object and somehow I can also #Autowire there ApplicationContext object.
Thanks.
I have started to look how the DispatcherServlet itself decides which handler method it will give the control and implemented with such a way.
Here is the code:
//Initialization in filter constructor
....
final HandlerMapping handlerMappings = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, HandlerMapping.class, true, false).get("requestMappingHandlerMapping");
....
#Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
.....
Method mappingMethod = null;
try {
mappingMethod = ((HandlerMethod)handlerMappings.getHandler(request).getHandler()).getMethod();
RequestMapping requestMapping = mappingMethod.getAnnotation(RequestMapping.class);
final String requestPattern = requestMapping.value();
}
catch(Exception ex){
logger.error("Error getting the mapping bean for the request URL " + request.getRequestURI(), ex);
return;
}
....
}
On top of the proposal of #Arsen I would suggest to do like this:
try {
handlerMappings.getHandler(request);
String requestPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
} catch (Exception ex) {
logger.error("Error getting the mapping bean for the request URL " + request.getRequestURI(), ex);
return;
}
The getHandler() instruction is enoght to trig the spring lookup of the correct controller that will also set the HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE attribute, this is usually available in controllers but not in filters.
Be aware that these solutions will waste some resources, cause spring will do the lookup again after that.

JSF ajax request calls filter (should be ignored!)

I have some filters, which grab e.g. a parameter like "id" to check some right (used to load some contents). These filters should ignore all ajax-requests, because e.g. the rights does not have to be checked after every little request (only on page load)
The Problem is, that when I perform an ajax-request, it throws me a null-pointer, because I don't append the ID with ajax requests. I found out, that it still works, when I use and it fails, when I use (both perform ajax requests).
This is my filter:
public class ExtendedAccessFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
//ignore filter if it is an ajax-request (DOES NOT WORK if not p:commandButton!)
if(isAJAXRequest(req)){
chain.doFilter(request, response);
System.out.println("ABORT FILTER, AJAX");
return;
}
//Nullpointer thrown here (because no Id is submitted)
int requestedId = Integer.parseInt(request.getParameter("id"));
}
private boolean isAJAXRequest(HttpServletRequest request) {
boolean check = false;
String facesRequest = request.getHeader("Faces-Request");
if (facesRequest != null && facesRequest.equals("partial/ajax")) {
check = true;
}
return check;
}
}
Am I doing something wrong?
You are doing it right way. You can also do it using JSF API by checking if PartialViewContext exists and it is an Ajax Request
if(FacesContext.getCurrentInstance().getPartialViewContext() !=null &&
FacesContext.getCurrentInstance().getPartialViewContext().isAjaxRequest()) {
}

Resources