5

How should I configure Jetty with SSL connector in Spring Boot 1.2.x ?

The following configuration is working for Spring boot 1.1.6 but gives 'SslSocketConnector cannot be resolved to a type' error for the version 1.2.1.

@Configuration
@EnableAutoConfiguration
public class OptosoftOAuthSecurityApplication implements
        EmbeddedServletContainerCustomizer {

    public static void main(String[] args) {
        SpringApplication.run(OptosoftOAuthSecurityApplication.class, args);
    }

    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {
        if (container instanceof JettyEmbeddedServletContainerFactory) {
            customizeJetty((JettyEmbeddedServletContainerFactory) container);
        }
    }

    public void customizeJetty(
            JettyEmbeddedServletContainerFactory containerFactory) {
        containerFactory.addServerCustomizers(jettyServerCustomizer());
    }

    @Bean
    public JettyServerCustomizer jettyServerCustomizer() {
        return new JettyServerCustomizer() {

            @Override
            public void customize(Server server) {
                SslContextFactory sslContextFactory = new SslContextFactory();
                sslContextFactory.setKeyStorePassword("jetty6");
                try {
                    sslContextFactory.setKeyStorePath(ResourceUtils.getFile(
                            "classpath:jetty-ssl.keystore").getAbsolutePath());
                } catch (FileNotFoundException ex) {
                    throw new IllegalStateException("Could not load keystore",
                            ex);
                }

                // THIS CLASS cannot be resolved !!!!!!  
                SslSocketConnector sslConnector = new SslSocketConnector(
                        sslContextFactory);
                sslConnector.setPort(9443);
                sslConnector.setMaxIdleTime(60000);
                server.addConnector(sslConnector);
            }
        };
    }

    @Bean
    @ConditionalOnMissingBean(RequestContextListener.class)
    public RequestContextListener requestContextListener() {
        return new RequestContextListener();
    }
}

My pom.xml (Spring Boot version is 1.2.1 in parent POM):-

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
        </dependency>
    </dependencies>
Kumar Sambhav
  • 7,503
  • 15
  • 63
  • 86

1 Answers1

8

The class you're trying to use is specific to Jetty 8 but Spring Boot 1.2.x uses Jetty 9 by default. In Spring Boot 1.2 you can now configure SSL declaratively in application.properties. This is illustrated in spring-boot-sample-jetty-ssl.

You can replace your EmbeddedServletContainerCustomizer implementation with the following properties declared in application.properties:

server.port = 9443
server.ssl.key-store = classpath:jetty-ssl.keystore
server.ssl.key-store-password = jetty6

Spring Boot only supports declarative configuration of a single connector. If you want the server to be accessible via HTTP and HTTPS then you'll have to configure one of them programatically. I'd recommend that the HTTP connector is configured programatically as there's less code involved:

@Bean
public EmbeddedServletContainerCustomizer servletContainerCustomizer() {
    return new EmbeddedServletContainerCustomizer() {

        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            if (container instanceof JettyEmbeddedServletContainerFactory) {
                configureJetty((JettyEmbeddedServletContainerFactory) container);
            }
        }

        private void configureJetty(JettyEmbeddedServletContainerFactory jettyFactory) {
            jettyFactory.addServerCustomizers(new JettyServerCustomizer() {

                @Override
                public void customize(Server server) {
                    ServerConnector serverConnector = new ServerConnector(server);
                    serverConnector.setPort(8080);
                    server.addConnector(serverConnector);
                }
            });
        }
    };
}
Andy Wilkinson
  • 108,729
  • 24
  • 257
  • 242
  • How to do I specify HTTP port? – Kumar Sambhav Feb 04 '15 at 16:16
  • You'd like to configure both HTTPS and HTTP access? – Andy Wilkinson Feb 04 '15 at 16:17
  • 1
    You'll need to configure one of the programatically. I've updated my answer. – Andy Wilkinson Feb 04 '15 at 16:29
  • The logs says;"Started ServerConnector@5032f2b7{SSL-HTTP/1.1}{0.0.0.0:8443} Started ServerConnector@40dcf583{HTTP/1.1}{0.0.0.0:8080} .s.b.c.e.j.JettyEmbeddedServletContainer : Jetty started on port(s) 8443 (ssl-http/1.1, http/1.1), 8080 (http/1.1) " But, I am not able to hit any endpoint using https:// https://localhost:8443/. Any clue what can be causing this? – Kumar Sambhav Feb 04 '15 at 16:46
  • 1
    Hard to tell without knowing what the error is. Perhaps there's problem with your certificate? Take a look at the sample that I linked to earlier and see if that helps. You can add the EmbeddedServletContainerCustomizer bean to it to get two connectors and see that it works with both HTTP and HTTPS. – Andy Wilkinson Feb 04 '15 at 16:56