1

Good day, I have the application with microservices and gateway (zuul) built on SpringBoot 2. It is all uses SSL. I need the automatic redirect from: http:\\localhost (currently shows nothing) to https:\\localhost (shows some text), so the user doesn't need to bother.

Once again: http:\\localhost has to show the same text as https:\\localhost (I need a redirect)

I've tried, does nothing.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.requiresChannel().anyRequest().requiresSecure();
    }
}

Tried another approach, but SpringBoot failed to recognize TomcatEmbeddedServletContainerFactory

@Bean
public EmbeddedServletContainerFactory servletContainer() {
    TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {

        @Override
        protected void postProcessContext(Context context) {
            SecurityConstraint securityConstraint = new SecurityConstraint();
            securityConstraint.setUserConstraint("CONFIDENTIAL");
            SecurityCollection collection = new SecurityCollection();
            collection.addPattern("/*");
            securityConstraint.addCollection(collection);
            context.addConstraint(securityConstraint);
        }
    };
    tomcat.addAdditionalTomcatConnectors(createHttpConnector());
    return tomcat;
}

private Connector createHttpConnector() {
    Connector connector
            = new Connector("org.apache.coyote.http11.Http11NioProtocol");
    connector.setScheme("http");
    connector.setSecure(false);
    connector.setPort(8080);
    connector.setRedirectPort(8443);
    return connector;
}

this one doesn't work either (doesn't seems to change anything)

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private Environment environment;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // other security configuration missing

        http.portMapper()
                .http(80) // http port defined in yml config file
                .mapsTo(443); // https port defined in yml config file

        // we only need https on /auth
        http.requiresChannel()
                .antMatchers("/auth/**").requiresSecure()
                .anyRequest().requiresInsecure();
    }
}

and this one ain't working too, the error is Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'resourceHandlerMapping' threw exception; nested exception is java.lang.IllegalStateException: No ServletContext set

@Bean
public TomcatServletWebServerFactory httpsRedirectConfig() {
    return new TomcatServletWebServerFactory () {
        @Override
        protected void postProcessContext(Context context) {
            SecurityConstraint securityConstraint = new SecurityConstraint();
            securityConstraint.setUserConstraint("CONFIDENTIAL");
            SecurityCollection collection = new SecurityCollection();
            collection.addPattern("/*");
            securityConstraint.addCollection(collection);
            context.addConstraint(securityConstraint);
        }
    };
}

and even this one with the java.lang.IllegalStateException: No ServletContext set error

  @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(redirectConnector());
        return tomcat;
    }

    private Connector redirectConnector() {
        Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
        connector.setScheme("http");
        connector.setPort(80);
        connector.setSecure(false);
        connector.setRedirectPort(443);
        return connector;
    }

Any suggestions?

ValerianTi
  • 81
  • 2
  • 11

1 Answers1

3

Got it. Thanks to EstebanGarciaAlonso and his answer ugrade spring boot 2.0.0.RC2 exception No ServletContext set

"After debugging, the problem is that mvc configuration class EnableWebMvcConfiguration load too early, servlet not loaded yet."

I spent a few hours on this. I managed to find a reason why this was happening. My config was split into several files and I was creating a MVC related bean in the Security Config (which was created earlier) forcing to use the MVC config before its time.

The solution was to move the @Bean instance from the security config to the MVC config. I hope it helps other people!

I moved following code to Application.java just before main method and all worked like miracle

   @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(redirectConnector());
        return tomcat;
    }

    private Connector redirectConnector() {
        Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
        connector.setScheme("http");
        connector.setPort(80);
        connector.setSecure(false);
        connector.setRedirectPort(443);
        return connector;
    }
ValerianTi
  • 81
  • 2
  • 11
  • 1
    What are the imports or dependencies necessary for this solution? When I paste in the code (I'm a Java noob), there's red squiggles everywhere, and when I hover over `TomcatServletWebServerFactory` the Quick Fix my IDE suggests is "create class" instead of doing an import. – redOctober13 Aug 11 '21 at 18:26
  • package org.springframework.boot.web.servlet.server; public interface ServletWebServerFactory package org.apache.catalina.connector; public class Connector package org.apache.tomcat.util.descriptor.web; public SecurityConstraint() – Sasha Bond Apr 20 '22 at 14:18
  • May be I am late, but the above code works fine in a separate configfile, created within the same package as the main application. For eg: if my main appln(main.java) is in package *com.test.main*, I created a config package *com.test.main.config* and copied the above code to the config.java file in the config package – RCB Apr 21 '22 at 10:12