understanding spring filters in Spring 3.2.8 - spring

I am implementing a filter for security reasons.... The point that the page gets frozen and I don't know exactly why because the filter in fact is not still doing anything !
<!-- spring security csrf -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>fr.telecom.support.context.DevicesSecurityFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Here my filter:
public class DevicesSecurityFilter extends DelegatingFilterProxy {
public DevicesSecurityFilter() {
// TODO Auto-generated constructor stub
}
public DevicesSecurityFilter(Filter delegate) {
super(delegate);
}
public DevicesSecurityFilter(String targetBeanName) {
super(targetBeanName);
}
public DevicesSecurityFilter(String targetBeanName,
WebApplicationContext wac) {
super(targetBeanName, wac);
}
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
System.out.println ("do Filter...");
//super.doFilter(request, response, filterChain);
}
}

The filter is doing something: it prevents the request from going to the next filter/servlet in the chain, and doesn't send anything to the response. So it basically intercepts all requests and responds with a blank response to all of them.
For the filter to be "transparent", its doFilter() method must contain
filterChain.doFilter(request, response);
or, since it's a DelegatingFilterProxy, it shouldn't have any doFilter() method at all, and instead let the parent's doFilter method implementation do its job: delegating to the Spring bean it's configured to use. In fact, you shouldn't even create subclasses of DelegatingFilterProxy: as its name indicates, it works, on its own, by delegating to a Spring bean. The Spring bean should be the one doing the filtering job.
By overriding the doFilter() method, you're preventing that delegation to happen.

Related

Logging all request and response in Spring Boot REST service

I use Spring boot and have some REST controllers. I want to logging all request and response. I using external tomacat, not embeded! I write Interceptor:
#Component
#Log4j2
public class LoggingWebMvcInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
final ContentCachingRequestWrapper wrapper = new ContentCachingRequestWrapper(request);
log.debug("REQ!!!! {}", wrapper.getReader().lines().collect(Collectors.joining(System.lineSeparator())));
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//log.debug("Response: {}", response);
}
And adding his:
#Configuration
public class WebMvcConfig implements WebMvcConfigurer {
private final LoggingWebMvcInterceptor loggingWebMvcInterceptor;
#Autowired
public WebMvcConfig(LoggingWebMvcInterceptor loggingWebMvcInterceptor) {
this.loggingWebMvcInterceptor = loggingWebMvcInterceptor;
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loggingWebMvcInterceptor);
}
}
But It don't work!
When I try POST request, his logging, but I have error: "Required request body is missing.
What am I doing wrong? I created a wrapper for the request!
I need to completely log all requests (POST, GET, DELETE, PUT) with headers and body and all responses. How can i do this? Any help, please.
Although your problem is not every well understood (not documented well -- for example where this is coming from is not shown Required request body is missing.) but anyways.
For logging purposes, I would not go with an Interceptor as I feel that this is too much work. Instead you could very well create an Aspect with a pointcut defined to around methods annotated with the various Spring controller annotation. The ProceedingJoinPoint#proceed method effectively allows you to grab the response object and the request itself contains all the information needed regarding parameters, IP, methods and so on.
With that in hand, you could then inject a HttpServletRequest in there, thus ending up having all the right tools to perform any logging activities.
Adding the caching wrapper is something very correct indeed if you would like to cache and re-read the HttpServletRequest's body multiple time but I would avoid adding it in the Interceptor/Aspect itself.
According to Baeldung documentation, ContentCachingRequestWrapper class has these limitations:
ContentCachingRequestWrapper class only supports the following:
Content-Type:application/x-www-form-urlencoded
Method-Type:POST
and
We must invoke the following method to ensure that request data is cached in ContentCachingRequestWrapper before using it: requestCacheWrapperObject.getParameterMap();
https://www.baeldung.com/spring-http-logging
You can use a web Filter (javax.servlet.Filter) as :
public class CustomFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain){
//Log actions heres
chain.doFilter(req, resp);}}
Then declare your filter in web.xml as :
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>package.CustomFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Extending SpringBootWebSecurityConfiguration with custom HttpSecurity configuration

I am trying to gain a better understanding of the auto-configuration of spring boot. In particular I need to add some custom spring security configuration to disable authentication for HTTP OPTIONS verbs in order to get my CORS requests working.
Without any custom configuration by default the SpringBootWebSecurityConfiguration is loaded by Spring Boot's auto-configuration.
What I would like to do is to keep using this auto-configuration but add some additional http configuration. I tried this:
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
Logger logger = LogManager.getLogger (SecurityConfiguration.class);
#Override
protected void configure (HttpSecurity http) throws Exception {
logger.info ("--- ALLOW all HTTP OPTIONS Requests");
http.authorizeRequests ().antMatchers (HttpMethod.OPTIONS, "*//**").permitAll ();
}
}
But this does not work as excepted. When I debug through SpringBootWebSecurityConfiguration and also the above code, I can see that both my configure-method and springs auto-configuration are executed but it looks like my http-configuration takes precedence.
So does that mean the auto-configuration is available only in an all-or-nothing kind of way? Or can I use the the auto-configuration but still extend it with some custom antMatcher?
What is the best-practice for this scenario?
You could create a new servlet filter and place it before the Spring security filter. For example:
#Component("CORSFilter")
public class CORSFilter implements Filter {
public void doFilter(
ServletRequest req,
ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Origin", "THE_HOST_YOU_WANT_TO_ALLOW_HERE");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, PUT, PATCH, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
"origin, content-type, accept, x-requested-with, authorization");
if (request.getMethod().equals("OPTIONS")) {
try {
response.getWriter().print("OK");
response.getWriter().flush();
} catch (IOException e) {
//...
}
} else {
chain.doFilter(req, res);
}
}
public void init(FilterConfig filterConfig) {
//...
}
public void destroy() {
//...
}
}
and then add this to your web.xml (or configure in your WebInitializer if you are using Java config only):
<filter>
<filter-name>CORSFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>contextAttribute</param-name>
<param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.[YOUR_SERVLET_NAME]</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CORSFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The reason you cannot do it is you are missing the annotation #EnableWebSecurity, have a look at the javadoc:
* Add this annotation to an {#code #Configuration} class to have the Spring Security
* configuration defined in any {#link WebSecurityConfigurer} or more likely by extending
* the {#link WebSecurityConfigurerAdapter} base class and overriding individual methods:

SpringMVC Session Timeout - Redirect to a Special JSP

I've looked everywhere but haven't found a simple solution.
We have a special JSP, timeout.jsp, that needs to be shown whenever a SpringMVC module intercepts an invalid session action. The timeout is already configured in web.xml and works correctly.
Previously in Struts, it was a matter of defining a forward and intercepting dispatchMethod,
<forward name="sessionTimeout" path="/WEB-INF/timeout.jsp" redirect="false" />
#Override
protected ActionForward dispatchMethod(final ActionMapping mapping, final ActionForm form,
final HttpServletRequest request, final HttpServletResponse response, final String name)
throws Exception {
//...
if (!isSessionValid())
return mapping.findForward("sessionTimeout");
}
But how would you implement a catch-all solution in SpringMVC modules?
All my SpringMVC URLs come to this servlet mapping, *.mvc:
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>*.mvc</url-pattern>
</servlet-mapping>
Anything that sends a URL with this pattern should be cross-checked for session validity and if invalid, redirected to timeout.jsp.
NOTE
The solution given here (https://stackoverflow.com/a/5642344/1005607) did not work:
<web-app>
<error-page>
<exception-type>org.springframework.web.HttpSessionRequiredException</exception-type>
<location>/index.jsp</location>
</error-page>
</web-app>
There's a NullPointerException in my SpringMVC Form Code even before any kind of SessionRequiredException, as soon as I try to access the session. I need to globally protect against these NullPointerExceptions.
My final solution: an old-fashioned Filter. It works for me, no other simple solution available.
web.xml
<filter>
<filter-name>spring_mvc_controller_filter</filter-name>
<filter-class>myapp.mypackage.SpringMVCControllerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>spring_mvc_controller_filter</filter-name>
<url-pattern>*.mvc</url-pattern>
</filter-mapping>
SpringMVCControllerFilter
public class SpringMVCControllerFilter implements Filter
{
#Override
public void destroy() {
// TODO Auto-generated method stub
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpSession session = request.getSession(false);
if (session.isValid() && !session.isNew())
{
chain.doFilter(request, response);
}
else
{
request.getRequestDispatcher("/WEB-INF/jsp/sessionTimeout.jsp").forward(request, response);
}
}
#Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}

How to set order for SessionRepositoryFilter?

I am evaluating spring-session with my web application. During the very first request to the web app, multiple httpsession is being created for a single client. After debugging I found that the problem is, the response is committed earlier in the filter chain by ShallowEtagHeaderFilter before reaching SessionRepositoryFilter, so the cookie added to the response is not sent to the client. so, every further ajax request creates a new session, but the session id is not set in the cookie.
I'm trying to move SessionRepositoryFilter after ShallowEtagHeaderFilter. is there a way to do it?
filter config:
#Bean
public SessionRepositoryFilter sessionFilter(RedisOperationsSessionRepository sessionRepository) {
HttpSessionStrategy cookieStrategy = new CookieHttpSessionStrategy();
((CookieHttpSessionStrategy) cookieStrategy).setCookieName("JSESSIONID");
SessionRepositoryFilter sessionRepositoryFilter = new SessionRepositoryFilter(sessionRepository);
sessionRepositoryFilter.setHttpSessionStrategy(cookieStrategy);
return sessionRepositoryFilter;
}
filter is registered by:
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addFilter("sessionFilter", DelegatingFilterProxy.class)
.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");
}
As you mentioned in the comment, you can register a filter for any url-pattern using web.xml:
<filter>
<filter-name>sessionFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>sessionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Or in a spring way you can do it in the application configuration class, like this:
#Configuration
public class WebAppConfig implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) {
servletContext
.addFilter("sessionFilter", DelegatingFilterProxy.class)
.addMappingForUrlPatterns(null, false, "/*");
}
}

init-param in web.xml for Spring OncePerRequestFilter not getting set

I have a Spring MVC app with Spring 3.2.5 that has a filter on it that makes a change to a request. This filter has a parameter that I am trying to set via the init-param in web.xml. I cannot seem to get the web.xml to set the value on my bean, and cannot figure out where it is getting stored (if it is at all) in the spring bean. I have not added my filter bean to my context, but only to my web.xml.
My web.xml:
<filter>
<filter-name>myFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<description>
...
</description>
<param-name>allowMethods</param-name>
<param-value>GET, POST</param-value>
</init-param>
</filter>
My filter code:
public class MyFilter extends OncePerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(MyFilter.class);
protected String allowMethods;
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Do filter stuff, and try printing allowMethods via the logger
}
/**
* #return the allowMethods
*/
public String getAllowMethods()
{
return allowMethods;
}
/**
* #param allowMethods the allowMethods to set as a comma separated list
* for request types. For example, "GET" or "GET, PUT", or "GET, PUT, POST, DELETE"
*/
public void setAllowMethods(String allowMethods)
{
logger.info("Setting CORS filter to allow cross-site scripting with methods: {}", allowMethods);
this.allowMethods = allowMethods;
}
}
I do not see the setter message, the value is not stored in the filter configuration that Spring saves, and I cannot override any methods that look like they'll give me the information I want (they are declared final).
How do I get the init-param mapped to my filter. Do I have to use the applicationContext to do it? If so, what is the convention to do this with Spring?
Thanks

Resources