Java Spring how to force https ssl in webapplicationinitializer?

To force https into web.xml, I used this piece of code:

<security-constraint> <web-resource-collection> <url-pattern>/*</url-pattern> </web-resource-collection> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> 

Is there an equivalent for this in Spring Java Config? I already realized that I need a ServletSecurityElement . But how to connect it to the others?

 public class WebAppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext container) throws ServletException { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); container.addListener(new ContextLoaderListener(context)); context.register(PersistenceJPAConfig.class); FilterRegistration filter = container.addFilter("wicket.myproject", WicketFilter.class); filter.setInitParameter("applicationClassName", WicketApplication.class.getName()); filter.setInitParameter(WicketFilter.FILTER_MAPPING_PARAM, "/*"); filter.addMappingForUrlPatterns(null, false, "/*"); HttpConstraintElement forceHttpsConstraint = new HttpConstraintElement(ServletSecurity.TransportGuarantee.CONFIDENTIAL, ""); ServletSecurityElement securityElement = new ServletSecurityElement(forceHttpsConstraint); } } 
+8
java spring spring-java-config
source share
7 answers

As John Thompson noted, you were there. You just needed to add the security element that you defined in the servlet. In another note, I noticed that you have a "" as the roleNames parameter for the HttpConstraintElement . This will actually cause everyone who did not have a role "" . If you want this to work as normal (force https), do not perform any roles. It ended up working for me:

 public class ApplicationInitializer implements WebApplicationInitializer { private static final String DISPATCHER_SERVLET_NAME = "dispatcher"; private static final String DISPATCHER_SERVLET_MAPPING = "/"; @Override public void onStartup(ServletContext container) throws ServletException { // Create the dispatcher servlet Spring application context AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext(); dispatcherContext.register(ApplicationConfiguration.class); // Register and map the dispatcher servlet ServletRegistration.Dynamic dispatcher = container.addServlet(DISPATCHER_SERVLET_NAME, new DispatcherServlet(dispatcherContext)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping(DISPATCHER_SERVLET_MAPPING); // Force HTTPS, and don't specify any roles for this constraint HttpConstraintElement forceHttpsConstraint = new HttpConstraintElement(ServletSecurity.TransportGuarantee.CONFIDENTIAL); ServletSecurityElement securityElement = new ServletSecurityElement(forceHttpsConstraint); // Add the security element to the servlet dispatcher.setServletSecurity(securityElement); } } 
+3
source

I think you need to get the servlet registration descriptor and then register the security element. Try something like this:

 ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet()); registration.setLoadOnStartup(1); registration.setServletSecurity(securityElement); //your prev defined securityElement 
+1
source

In case you are using Spring Security 3.2, you can do it as follows.

 <security:intercept-url pattern="/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="https"/> 

with mapping of http and https ports.

 <security:port-mappings> <security:port-mapping http="${port.mapping.http.port}" https="${port.mapping.https.port}" /> 
+1
source

What do you mean, connect it to the rest? Sounds like you should be installed. Spring will automatically detect the configuration of the configured Java WebApplicationInitializer.

Remember that implementations of WebApplicationInitializer are detected automatically - so you can pack them in your own as you think.

Cm:

http://docs.spring.io/spring-framework/docs/3.1.x/javadoc-api/org/springframework/web/WebApplicationInitializer.html#onStartup(javax.servlet.ServletContext)

0
source

One way to do this is to create an HTTP filter inside your application:

 @Component @ConfigurationProperties("security.http") public class ForceHTTPSFilter implements Filter { public static final String X_FORWARDED_PROTO_HEADER = "x-forwarded-proto"; private boolean forceHttps = false; @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if(forceHttps && !request.getProtocol().toUpperCase().contains("HTTPS") && request instanceof HttpServletRequest) { Optional<String> protocol = Optional.ofNullable(((HttpServletRequest)request).getHeader(X_FORWARDED_PROTO_HEADER)); if(!protocol.orElse("http").equals("https")){ ((HttpServletResponse)response).sendError(HttpStatus.FORBIDDEN.value(), "Please use HTTPS when submitting data to this server."); return; } } chain.doFilter(request, response); } @Override public void destroy() { } public boolean isForceHttps() { return forceHttps; } public void setForceHttps(boolean forceHttps) { this.forceHttps = forceHttps; } } 

You can enable / disable the filter using the @ConfigurationProperties property.

In addition, you should check the x-forwarded-proto header, because some proxies (like Heroku) remove the protocol from the URL and store it in that header.

And of course, here is the unit test of this filter:

 public class ForceHTTPSFilterTest { @Rule public MockitoRule rule = MockitoJUnit.rule(); @InjectMocks private ForceHTTPSFilter filter; @Test public void testAcceptHTTPRequestWhenFlagIsDisabled() throws Exception{ HttpServletRequest request = mock(HttpServletRequest.class); when(request.getProtocol()).thenReturn("HTTP/1.1"); HttpServletResponse response = mock(HttpServletResponse.class); FilterChain chain = mock(FilterChain.class); filter.doFilter(request, response, chain); verify(chain, times(1)).doFilter(any(), any()); verify(response, never()).sendError(eq(403), anyString()); } @Test public void testAcceptHTTPRequestWhenFlagIsEnableAndItHasForwardedProtoHeader() throws Exception{ HttpServletRequest request = mock(HttpServletRequest.class); when(request.getProtocol()).thenReturn("HTTP/1.1"); when(request.getHeader(ForceHTTPSFilter.X_FORWARDED_PROTO_HEADER)).thenReturn("https"); HttpServletResponse response = mock(HttpServletResponse.class); filter.setForceHttps(true); FilterChain chain = mock(FilterChain.class); filter.doFilter(request, response, chain); verify(chain, times(1)).doFilter(any(), any()); verify(response, never()).sendError(eq(403), anyString()); } @Test public void testAcceptHTTPSRequest() throws Exception{ HttpServletRequest request = mock(HttpServletRequest.class); when(request.getProtocol()).thenReturn("HTTPS/1.1"); HttpServletResponse response = mock(HttpServletResponse.class); filter.setForceHttps(true); FilterChain chain = mock(FilterChain.class); filter.doFilter(request, response, chain); verify(chain, times(1)).doFilter(any(), any()); verify(response, never()).sendError(eq(403), anyString()); } @Test public void testRejectHTTPRequestWhenFlagIsEnableAndItDoesntHaveForwardedProtoHeader() throws Exception{ HttpServletRequest request = mock(HttpServletRequest.class); when(request.getProtocol()).thenReturn("HTTP/1.1"); HttpServletResponse response = mock(HttpServletResponse.class); filter.setForceHttps(true); FilterChain chain = mock(FilterChain.class); filter.doFilter(request, response, chain); verify(chain, never()).doFilter(any(), any()); verify(response, times(1)).sendError(eq(403), anyString()); } } 
0
source
 private static final String DISPATCHER_SERVLET_NAME = "dispatcher"; private static final String DISPATCHER_SERVLET_MAPPING = "/"; @Override public void onStartup(ServletContext servletContext) throws ServletException { AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); rootContext.register(ApplicationContext.class); ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, new DispatcherServlet(rootContext)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping(DISPATCHER_SERVLET_MAPPING); HttpConstraintElement forceHttpsConstraint = new HttpConstraintElement(TransportGuarantee.CONFIDENTIAL); ServletSecurityElement securityElement = new ServletSecurityElement(forceHttpsConstraint); dispatcher.setServletSecurity(securityElement); } 
0
source

None of the above answers are good enough when using Spring Boot and external Tomcat. Here is the correct configuration:

super () must be called, and the existing dispatcher servlet must be taken from the existing container.

 private static final String DISPATCHER_SERVLET_NAME = "dispatcherServlet"; @Override public void onStartup(ServletContext container) throws ServletException { super.onStartup(container); // Get the existing dispatcher servlet ServletRegistration.Dynamic dispatcher = (ServletRegistration.Dynamic) container.getServletRegistration(DISPATCHER_SERVLET_NAME); // Force HTTPS, and don't specify any roles for this constraint HttpConstraintElement forceHttpsConstraint = new HttpConstraintElement(ServletSecurity.TransportGuarantee.CONFIDENTIAL); ServletSecurityElement securityElement = new ServletSecurityElement(forceHttpsConstraint); // Add the security element to the servlet dispatcher.setServletSecurity(securityElement); } 
0
source

All Articles