Vinay
Vinay

Reputation: 163

Spring Boot Jetty Auto Redirect HTTP (Port 80) requests to HTTPS (Port 8443)

I have the following code to configure Jetty server:

@Configuration
public class RedirectHttpToHttpsOnJetty2Config {

    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
        JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
            factory.addServerCustomizers(new JettyServerCustomizer() {

                @Override
                public void customize(Server server) {
                    ServerConnector connector = new ServerConnector(server);
                    connector.setPort(80);
                    server.addConnector(connector);
                }
            });
        return factory;
    }
}

and

application.properties as

server.port=8443
server.ssl.key-store=classpath:keystore
server.ssl.key-store-password=xyzxyzxyz
server.ssl.key-password=xyzxyzxyz

My applications works expectedly when I access localhost:8443 but localhost:80 is not reachable. gradlew bootRun mentions

... Jetty started on port(s) 8443 (ssl, http/1.1), 80 (http/1.1) with context path '/' ...

but upon visiting http://localhost:80 I get the message

This site can’t be reached... localhost refused to connect.

I am looking for http://localhost:80 getting redirected to https://localhost:8443.

I had it working in Tomcat:

    @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("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(80);
        connector.setSecure(false);
        connector.setRedirectPort(8443);
        return connector;
    }

But unable to find an equivalent for Jetty. Any pointers much appreciated.

Upvotes: 3

Views: 3313

Answers (2)

manash
manash

Reputation: 7106

The following configuration will set up a redirect from HTTP to HTTPS. It assumes that you already configure Spring Boot to listen on port 443 and SSL is configured properly.

@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
    JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
    factory.addServerCustomizers(new JettyServerCustomizer() {
        @Override
        public void customize(Server server) {
            final HttpConnectionFactory httpConnectionFactory = server.getConnectors()[0].getConnectionFactory(HttpConnectionFactory.class);

            final ServerConnector httpConnector = new ServerConnector(server, httpConnectionFactory);
            httpConnector.setPort(80 /* HTTP */);
            server.addConnector(httpConnector);

            final HandlerList handlerList = new HandlerList();
            handlerList.addHandler(new SecuredRedirectHandler());
            for(Handler handler : server.getHandlers())
                handlerList.addHandler(handler);
            server.setHandler(handlerList);
        }
    });
    return factory;
}

Upvotes: 2

Joakim Erdfelt
Joakim Erdfelt

Reputation: 49462

You are missing the required HttpConfiguration on your port 80 ServerConnector to tell Jetty what your secure vs unsecured ports are.

The Jetty side SecuredRedirectHandler is how the redirect actually functions.

See: https://github.com/jetty-project/embedded-jetty-cookbook/blob/master/src/main/java/org/eclipse/jetty/cookbook/SecuredRedirectHandlerExample.java

SecuredRedirectHandlerExample.java

package org.eclipse.jetty.cookbook;

import java.net.URL;

import org.eclipse.jetty.cookbook.handlers.HelloHandler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.SecuredRedirectHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;

public class SecuredRedirectHandlerExample
{
    public static void main(String[] args) throws Exception
    {
        Server server = new Server();
        int httpPort = 8080;
        int httpsPort = 8443;

        // Setup HTTP Connector
        HttpConfiguration httpConf = new HttpConfiguration();
        httpConf.setSecurePort(httpsPort);
        httpConf.setSecureScheme("https");

        // Establish the HTTP ServerConnector
        ServerConnector httpConnector = new ServerConnector(server,
                new HttpConnectionFactory(httpConf));
        httpConnector.setPort(httpPort);
        server.addConnector(httpConnector);

        // Find Keystore for SSL
        ClassLoader cl = SecuredRedirectHandlerExample.class.getClassLoader();
        String keystoreResource = "ssl/keystore";
        URL f = cl.getResource(keystoreResource);
        if (f == null)
        {
            throw new RuntimeException("Unable to find " + keystoreResource);
        }

        // Setup SSL
        SslContextFactory sslContextFactory = new SslContextFactory();
        sslContextFactory.setKeyStorePath(f.toExternalForm());
        sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
        sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");

        // Setup HTTPS Configuration
        HttpConfiguration httpsConf = new HttpConfiguration(httpConf);
        httpsConf.addCustomizer(new SecureRequestCustomizer()); // adds ssl info to request object

        // Establish the HTTPS ServerConnector
        ServerConnector httpsConnector = new ServerConnector(server,
                new SslConnectionFactory(sslContextFactory,"http/1.1"),
                new HttpConnectionFactory(httpsConf));
        httpsConnector.setPort(httpsPort);

        server.addConnector(httpsConnector);

        // Add a Handlers for requests
        HandlerList handlers = new HandlerList();
        handlers.addHandler(new SecuredRedirectHandler()); // always first
        handlers.addHandler(new HelloHandler("Hello Secure World"));
        handlers.addHandler(new DefaultHandler()); // always last
        server.setHandler(handlers);

        server.start();
        server.join();
    }
}

Upvotes: 3

Related Questions