Is there any reason why a filter slow down the server response?
I've a web app with the following filter:
package com.bingo.filters;
import java.io.IOException;
import java.util.Arrays;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class CacheFilter implements Filter {
static class CacheControlHeaderResponse extends HttpServletResponseWrapper {
public static final String[] CACHEABLE_CONTENT_TYPES = new String[] {
"text/css", "text/javascript", "image/png", "image/jpeg",
"image/gif", "image/jpg" };
static {
Arrays.sort(CACHEABLE_CONTENT_TYPES);
}
public CacheControlHeaderResponse(HttpServletResponse response) {
super(response);
}
#Override
public void setContentType(String contentType) {
super.setHeader("Expires", "-1");
super.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
super.setHeader("Pragma", "no-cache");
super.setContentType(contentType);
}
}
public CacheFilter() {
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
chain.doFilter(request, new CacheControlHeaderResponse(res));
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
This is the configuration I added to my web.xml
<filter>
<filter-name>cFilter</filter-name>
<filter-class>com.bingo.filters.CacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cFilter</filter-name>
<url-pattern>/bingo/*</url-pattern>
</filter-mapping>
When I deploy the war with this new code, the application server answer very slowly. It takes 6 or 7 seconds for a page to be retrieved.
But if I deploy the old war file without the above code, then the response is very fast.
Is there anything wrong into the above code, that can explain the performance issue?
Related
I'm trying to implement CSRF Protection in Java. For cache I'm using google/guava and saving the cache in the Http Session. With Custom HttpServlet I'm creating csrf-token and saving to Http Session and return in some custom key-value object.
For validation csrf token I'm using Custom Filter, which need to check session and load cache (there is problem) and compare with custom header parameter.
But I'm getting java.lang.ClassCastException.
java.lang.ClassCastException: com.google.common.cache.LocalCache$LocalManualCache cannot be cast to com.google.common.cache.LoadingCache
Here is my Filter
package com.csrf;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.common.cache.Cache;
public class ValidateCsrfFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String salt = httpRequest.getHeader("TOKEN-CSRF");
Cache<String, Boolean> csrfSaltCache = (Cache<String, Boolean>) httpRequest.getSession().getAttribute("CACHE-CSRF");
if (csrfSaltCache != null && salt != null && csrfSaltCache.getIfPresent(salt) != null) {
chain.doFilter(request, response);
} else {
((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED, "CSRF Token isn't valid!");
}
}
#Override
public void destroy() {
}
}
This is my Servlet where I'm creating Token
package com.csrf;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.SecureRandom;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.apache.commons.lang.RandomStringUtils;
public class CreateCsrfTokenServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Cache<String, Boolean> cache = (Cache<String, Boolean>) request.getSession().getAttribute("CACHE-CSRF");
if (cache == null) {
cache = CacheBuilder.newBuilder().maximumSize(5000).expireAfterWrite(20, TimeUnit.MINUTES).build();
request.getSession().setAttribute("CACHE-CSRF", cache);
}
String salt = RandomStringUtils.random(20, 0, 0, true, true, null, new SecureRandom());
cache.put(salt, Boolean.TRUE);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
String outputString = "{\"key\": \"" + "TOKEN-CSR" + "\", \"value\": \"" + salt + "\"}";
out.print(outputString);
out.flush();
}
}
And my web.xml
<!-- ... -->
<servlet>
<servlet-name>CreateCsrfTokenServlet</servlet-name>
<servlet-class>com.csrf.CreateCsrfTokenServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CreateCsrfTokenServlet</servlet-name>
<url-pattern>/csrf/createtoken</url-pattern>
</servlet-mapping>
<filter>
<filter-name>ValidateCsrfFilter</filter-name>
<filter-class>com.csrf.ValidateCsrfFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ValidateCsrfFilter</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
Does anyone have idea how I can solve this ClassCastException between LocalCache$LocalManualCache and Cache?
I'm am trying to set up an application that has an Angular front-end and a Maven/Spring Boot backend and have set up my first REST controller. My issue is that when I send a GET HTTP request to the backend from my Angular IDE it returns an error stating:
"Access to XMLHttpRequest at 'http://localhost:8080/api/getData' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."
I'm confused as I have set up the "doFilter" to accept all requests from any origin so it shouldn't be throwing this error. My code follows:
My APIController:
package com.SSCCoursework.controller;
import com.SSCCoursework.Model.SharePrice;
import com.SSCCoursework.Model.Shares;
import com.SSCCoursework.Model.SharesList;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#CrossOrigin (origins = "http://localhost:4200", maxAge = 3600)
#RestController
public class ApiController
{
File Shares_File = new File("Shares_Data.xml");
ArrayList<Shares> shareList = new ArrayList<Shares>();
#RequestMapping(value="/api/getData", produces="application/JSON")
public Object getData()
{
Shares share1 = new Shares();
SharePrice share1_2 = new SharePrice();
share1.setCompanyName("test");
share1.setCompanySymbol("test");
share1.setNumOfShares(123);
Date date = new Date();
share1.setLastShareUpdate(date);
share1_2.setCurrency("dollar");
share1_2.setValue(12345f);
share1.setSharePrice(share1_2);
shareList.add(share1);
SharesList sharelist = new SharesList();
sharelist.setBookList(shareList);
return share1;
}
}
My SimpleCORSFilter:
package com.SSCCoursework.Security;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
#Component
public class SimpleCORSFilter implements Filter
{
#Override
public void init(FilterConfig filterConfig) throws ServletException
{
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException
{
HttpServletResponse res = (HttpServletResponse) response;
HttpServletRequest req = (HttpServletRequest) request;
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, Referer, Connection, User-Agent, authorization, sw-useragent, sw-version");
if (req.getMethod().equals("OPTIONS"))
{
res.setStatus(HttpServletResponse.SC_OK);
return;
}
filterChain.doFilter(request, response);
}
#Override
public void destroy()
{
}
}
My Angular code is just trying to use a GET method (this.httpClient.get('http://localhost:8080/api/getData') to print the data to the browser console but the error is preventing it from working. Am I missing a step in my backend?
you can easily define a global cors config just by adding in your main application class where you start your spring boot app
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:8080")
.allowedMethods("PUT", "DELETE", "GET", "POST");
}
};
}
for more details take a look here
I have a mvc web application which need to be secured using the java filter concept.
If I am not logged in the application should take me to the login page and if I am logged in the application must not allow me to access the login page.
Below is the filter code which I have implementd in filter
Login url is /login (login.jsp)
home page url is /home (home.jsp)
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
#WebFilter("/LoginFilter")
public class LoginFilter implements Filter {
private RequestDispatcher dispatcher;
public LoginFilter() {
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req=(HttpServletRequest) request;
HttpServletResponse res=(HttpServletResponse) response;
HttpSession session=req.getSession(false);
String reqUri=req.getRequestURI();
System.out.println("RequestURI:"+reqUri);
if(session!=null && session.getAttribute("user")!=null){
if(reqUri.equals("login")){
System.out.println("you are already logged in");
dispatcher=request.getRequestDispatcher("/home");
dispatcher.forward(req, res);
return;
}
else{
chain.doFilter(request, response);
}
}
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
You can use the below updated code to check if it is completing your requirement or not.
where login url is predefined and checking every time for logged-in user to take him/her to secured page.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
#WebFilter("/LoginFilter")
public class LoginFilter implements Filter {
private String loginUri="/LoginLogout/login";
private RequestDispatcher dispatcher;
public LoginFilter() {
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req=(HttpServletRequest) request;
HttpServletResponse res=(HttpServletResponse) response;
HttpSession session=req.getSession(false);
String reqUri=req.getRequestURI();
System.out.println("RequestURI:"+reqUri);
//already looged in
if(session!=null && session.getAttribute("user")!=null){
//trying to access login url after logged in
if(reqUri.equals(loginUri)){
System.out.println("you are already logged in");
dispatcher=request.getRequestDispatcher("/home");
dispatcher.forward(req, res);
return;
}
else{
chain.doFilter(request, response);
}
}
//if not logged-in
else{
System.out.println("First have to logged in");
dispatcher=request.getRequestDispatcher("/login");
dispatcher.forward(req, res);
return;
}
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
Suppose I'm running embedded jetty with the following code. I want to pass in some parameters to my filter. When I look at the Jetty API for adding a filter - there are no options to set init-params. My question is Does embedded Jetty have the ability to set the init-params of a filter?
import java.io.IOException;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
public class JettyFilter {
public static void main(final String[] args) throws Exception {
Server server = new Server(8080);
ServletHandler handler = new ServletHandler();
server.setHandler(handler);
handler.addServletWithMapping(HelloServlet.class, "/*");
handler.addFilterWithMapping(HelloPrintingFilter.class, "/*",
EnumSet.of(DispatcherType.REQUEST));
server.start();
server.join();
}
public static class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("<h1>Hello SimpleServlet</h1>");
}
}
public static class HelloPrintingFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.print("hello from filter");
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
#Override
public void destroy() {}
}
}
Assuming you're using this version (or higher) of Jetty's ServletHandler, the addFilterWithMapping(..) method returns a FilterHolder which provides a setInitParameter(..) method to set your init parameter.
Just to summarise - it looks like this:
import java.io.IOException;
import java.util.EnumSet;
import java.util.Enumeration;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
public class TestEmbeddedFilter {
public static void main(String[] args) {
Server server = new Server(8082);
ServletContextHandler context = new ServletContextHandler(
ServletContextHandler.SESSIONS);
context.setContextPath("/");
ServletHandler handler = new ServletHandler();
ServletHolder sh = new ServletHolder(new MyServlet());
context.addServlet(sh, "/*");
FilterHolder fh = handler.addFilterWithMapping(MyFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
fh.setInitParameter("initParamKey", "InitParamValue");
context.addFilter(fh, "/*", EnumSet.of(DispatcherType.REQUEST));
context.setHandler(handler);
server.setHandler(context);
try {
server.start();
// server.join();
} catch (Exception e) {
e.printStackTrace();
}
}
#SuppressWarnings("serial")
public static class MyServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
response.setContentType("text/html");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("<h1>Hello MyServlet</h1>");
}
}
public static class MyFilter implements Filter {
public void destroy() {
System.out.println("Stopping filter");
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("doFilter called with: " + request);
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
Enumeration<String> enums = filterConfig.getInitParameterNames();
while (enums.hasMoreElements()) {
String param = (String) enums.nextElement();
System.out.println(param + ":" + filterConfig.getInitParameter(param));
}
}
}
}
I am working with embedded Jetty and I want to add a servlet filter to check for authentication before each request. I tried following this example but it looks like the signature has changed.
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.0.4.v20130625</version>
</dependency>
My Jetty starter looks like this:
public class JettyStarter {
public static void main( final String[] args ) throws Exception {
Server server = new Server(8080);
final ServletHolder servletHolder = new ServletHolder(new CXFServlet());
final ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
// context.addFilter(AuthenticationFilter.class, "/*", FilterMapping.REQUEST);
context.addServlet(servletHolder, "/platform/*");
context.addEventListener(new ContextLoaderListener());
context.setInitParameter("contextClass", AnnotationConfigWebApplicationContext.class.getName());
context.setInitParameter("contextConfigLocation", Config.class.getName());
server.setHandler(context);
server.start();
server.join();
}
}
When I uncomment the line
// context.addFilter(AuthenticationFilter.class, "/*", FilterMapping.REQUEST);
I find that the signature has changed. So I want to take a small step back and ask, with embedded Jetty, how do I add a filter that runs at the beginning of the request and allows the request to continue only if some condition is met?
The beginning of the AuthenticationFilter class looks like this:
import javax.servlet.*;
import java.io.IOException;
public class AuthenticationFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {}
#Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {}
#Override
public void destroy() {}
}
You are probably looking for EnumSet.of(DispatcherType.REQUEST), included a full example below:
import java.io.IOException;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
public class JettyFilter {
public static void main(final String[] args) throws Exception {
Server server = new Server(8080);
ServletHandler handler = new ServletHandler();
server.setHandler(handler);
handler.addServletWithMapping(HelloServlet.class, "/*");
handler.addFilterWithMapping(HelloPrintingFilter.class, "/*",
EnumSet.of(DispatcherType.REQUEST));
server.start();
server.join();
}
public static class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("<h1>Hello SimpleServlet</h1>");
}
}
public static class HelloPrintingFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.print("hello from filter");
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
#Override
public void destroy() {}
}
}