How to set order for SessionRepositoryFilter? - spring

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, "/*");
}
}

Related

How to set a <context-param> in Spring Boot without web.xml?

I have a Spring Boot application. I basically need to set the following context parameter:
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
But my Spring Boot application doesn't have a web.xml. How can I set it programmatically?
Following other posts, I added a ServletContextInitializer implementation.
#Configuration
public class ConfigureJSFContextParameters implements ServletContextInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setInitParameter("javax.faces.STATE_SAVING_METHOD", "client");
}
}

Spring security login not showing

I'm adding Spring Security on a Spring MVC app; however, when I run the application, the Spring Security default login does not show up (not even when I browse to a link which is supposed to be "secured").
Configuration class (forgive the indentation):
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConf extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
.antMatchers("**/secured/**").authenticated()
.anyRequest().permitAll()
.and()
.formLogin().permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(getPasswordEncoder());
}
private PasswordEncoder getPasswordEncoder() {
return new PasswordEncoder() {
#Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return encode(rawPassword).equals(encodedPassword);
}
#Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
};
} }
I also tried adding a custom login, but it does not seem to find the page (which is otherwise reachable):
http.authorizeRequests()
.antMatchers("**/secured/**").authenticated()
.anyRequest().permitAll()
.and()
.formLogin().loginPage('/login').permitAll();
Summing up, I need the default Spring Security login page to be displayed first, so I can test the authentication, then I need to be able to add a new login form to be displayed instead. What should I do?
EDIT: I figured out the configuration problem which prevented the Spring login to be displayed. The following tags had to be added in the web.xml file in order to integrate Spring Security with Spring MVC. Now the login is succesfully displayed.
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I figured out the configuration problem which prevented the Spring login to be displayed. The following tags had to be added in the web.xml file in order to integrate Spring Security with Spring MVC. Now the login is succesfully displayed.
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Enabling CORS Spring issue with Spring Security

I need to enable CORS for Spring application that uses Spring Security and it is not working. I am making GET request from http://localhost:3000 (which is node.js server) to http://localhost:8080 (which is Tomcat server).
I tried the following approaches but can not make any of them work:
https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
Spring Data Rest and Cors
https://gist.github.com/zeroows/80bbe076d15cb8a4f0ad
Enabling CORS using Spring Boot 1.3.3-RELEASE
Spring CORS controller annotation not working
Currently I have a #Controller:
#Controller
#RequestMapping("/views")
public class LoginController{
#Autowired
private EventService eventService;
#RequestMapping(value = "/companies", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public String listCompanies(Model model) {
String companiesList = eventService.getCompanies();
return companiesList;
}
}
And AppConfig file where I have been unsuccessfully trying to allow CORS:
#EnableWebMvc
#Configuration
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
I want to somehow get the json from the listCompanies method in my Angular2 app. I am getting No 'Access-Control-Allow-Origin' header is present error, so I suppose it is CORS issue.
I had similar problem and fixed it with custom filter as described in documentation: 27.5 Filter based CORS support
Basically, you need to create filter:
public class MyCorsFilter extends CorsFilter {
public MyCorsFilter() {
super(configurationSource());
}
private static UrlBasedCorsConfigurationSource configurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedMethod("*");
config.addAllowedHeader("*");
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
and then add it in web.xml (or corresponding java based config) before springSecurityFilterChain like this:
<filter>
<filter-name>corsFilter</filter-name>
<filter-class>com.example.configuration.cors.MyCorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>corsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I also have dispatchOptionsRequest (which is not necessary according to the new documentation):
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
...
<!-- "OPTIONS" method support -->
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
...
</servlet>
Did you defined somewhere the allowed origines in spring configuration? http://localhost:8080
#EnableWebMvc
#Configuration
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true);
}
}
Look at chapter 27.3 of official docs to enable global CORS configuration :
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cors.html
If you don't need to include cookies on cross-origin request, replace .allowCredentials(true) by .allowCredentials(false)
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Enabling CORS support - Access-Control-Allow-Origin
*
*
* <code>
<!-- Add this to your web.xml to enable "CORS" -->
<filter>
<filter-name>cors</filter-name>
<filter-class>com.elm.mb.rest.filters.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
* </code>
*/
public class CORSFilter extends OncePerRequestFilter {
private static final Log LOG = LogFactory.getLog(CORSFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
LOG.trace("Sending Header....");
// CORS "pre-flight" request
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
// response.addHeader("Access-Control-Allow-Headers", "Authorization");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
response.addHeader("Access-Control-Max-Age", "1");
}
filterChain.doFilter(request, response);
}
}

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
}
}

understanding spring filters in Spring 3.2.8

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.

Resources