web-dev-qa-db-fra.com

Comment configurer Spring Boot pour exécuter les ports HTTPS / HTTP

Spring Boot possède certaines propriétés pour configurer le port Web et les paramètres SSL, mais une fois qu'un certificat SSL est défini, le port http se transforme en port https.

Alors, comment puis-je faire fonctionner les deux ports, par exemple: 80 et 443 en même temps?

Comme vous pouvez le voir, il n'y a que des propriétés pour un port, dans ce cas "server.ssl" est activé, ce qui rend le port http désactivé automatiquement.

##############
### Server ###
##############
server.port=9043
server.session-timeout=1800
server.ssl.key-store=file:///C:/Temp/config/localhost.jks
server.ssl.key-store-password=localhost
server.ssl.key-password=localhost
server.ssl.trust-store=file:///C:/Temp/config/localhost.jks
server.ssl.trust-store-password=localhost

J'essaie d'utiliser même Tomcat ou Undertow. J'apprécierais toute aide!

30
Carlos Alberto

La configuration Spring Boot à l'aide des propriétés permet de configurer un seul connecteur. Vous avez besoin de plusieurs connecteurs et pour cela, vous devez écrire une classe de configuration. Suivez les instructions dans

https://docs.spring.io/spring-boot/docs/1.2.3.RELEASE/reference/html/howto-embedded-servlet-containers.html

Vous pouvez trouver un exemple de configuration de https via les propriétés, puis http via EmbeddedServletContainerCustomizer ci-dessous

http://izeye.blogspot.com/2015/01/configure-http-and-https-in-spring-boot.html?showComment=1461632100718#c4988529876932015554

server:
  port:
    8080
  ssl:
    enabled:
      true
    keyStoreType:
      PKCS12
    key-store:
      /path/to/keystore.p12
    key-store-password:
      password
  http:
    port:
      8079

@Configuration
public class TomcatConfig {

@Value("${server.http.port}")
private int httpPort;

@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
    return new EmbeddedServletContainerCustomizer() {
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            if (container instanceof TomcatEmbeddedServletContainerFactory) {
                TomcatEmbeddedServletContainerFactory containerFactory =
                        (TomcatEmbeddedServletContainerFactory) container;

                Connector connector = new Connector(TomcatEmbeddedServletContainerFactory.DEFAULT_PROTOCOL);
                connector.setPort(httpPort);
                containerFactory.addAdditionalTomcatConnectors(connector);
            }
        }
    };
}
}
37
Harish Gokavarapu

La réponse actuellement acceptée fonctionne parfaitement mais nécessite une certaine adaptation si vous souhaitez qu'elle fonctionne avec Spring Boot 2.0.0 et versions ultérieures:

@Component
public class HttpServer {
  @Bean
  public ServletWebServerFactory servletContainer(@Value("${server.http.port}") int httpPort) {
      Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
      connector.setPort(httpPort);

      TomcatServletWebServerFactory Tomcat = new TomcatServletWebServerFactory();
      Tomcat.addAdditionalTomcatConnectors(connector);
      return Tomcat;
  }
}

ou la version kotlin:

@Component
class HttpServer {
  @Bean
  fun servletContainer(@Value("\${server.http.port}") httpPort: Int): ServletWebServerFactory {
    val connector = Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL)
    connector.setPort(httpPort)

    val Tomcat = TomcatServletWebServerFactory()
    Tomcat.addAdditionalTomcatConnectors(connector)
    return Tomcat
  }
}
20
NickDK

Ci-dessous est un exemple simple de la façon d'activer les deux ports HTTP/HTTPS pour Undertow.

Spring Boot ne permet d'ouvrir qu'un port par configuration. Le deuxième port doit être ouvert par programme.

Ouvrez d'abord le port HTTP par programme.

import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;

@Configuration
public class UndertowConfig {

@Value("${server.http.port}")
private int httpPort;

@Value("${server.http.interface}")
private String httpInterface;

@Bean
public WebServerFactoryCustomizer<UndertowServletWebServerFactory> containerCustomizer() {
    return (WebServerFactoryCustomizer) factory -> {
        UndertowServletWebServerFactory undertowFactory = (UndertowServletWebServerFactory) factory;
        undertowFactory.getBuilderCustomizers().add(builder -> {
            builder.addHttpListener(httpPort, httpInterface);
        });
    };
}

}

HTTPS par configuration

Spring peut ouvrir une propriété de lecture de port HTTP ou HTTPS à partir d'une source de propriété disponible. Si vous ajoutez la configuration appropriée comme indiqué ci-dessous, il serait suffisant d'avoir le port HTTP ouvert.

#default secured port (Spring will open it automatically)
server.port=8443
#additional HTTP port (will open it in UndertowConfig)
server.http.port=8080
#Open to the world
server.http.interface=0.0.0.0
#These settings tell Spring to open SSL port
server.ssl.keystore=file:${APP_BASE}/conf/server/ssl_selfsigned/server.keystore
server.ssl.key-store-password=xyz
server.ssl.key-password=xyz

HTTPS par configuration manuelle

Vous pouvez ouvrir un autre port SSL de la même manière que vous avez ouvert le port HTTP si vous le souhaitez en procédant ainsi

 .addHttpsListener(ssl_port, httpInterface, getSSLContext());

Voici comment créer un contexte SSL

import javax.net.ssl.*;
import Java.io.InputStream;
import Java.nio.file.Files;
import Java.nio.file.Paths;
import Java.security.KeyStore;

public SSLContext getSSLContext() throws Exception
{
    return createSSLContext(loadKeyStore(serverKeystore,keyStorePassword),
            loadKeyStore(serverTruststore,trustStorePassword));

}


private SSLContext createSSLContext(final KeyStore keyStore,
                                    final KeyStore trustStore) throws Exception {

    KeyManager[] keyManagers;
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
    keyManagers = keyManagerFactory.getKeyManagers();

    TrustManager[] trustManagers;
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(trustStore);
    trustManagers = trustManagerFactory.getTrustManagers();

    SSLContext sslContext;
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(keyManagers, trustManagers, null);

    return sslContext;
}


private static KeyStore loadKeyStore(final String storeLoc, final String storePw) throws Exception {
    InputStream stream = Files.newInputStream(Paths.get(storeLoc));
    if(stream == null) {
        throw new IllegalArgumentException("Could not load keystore");
    }
    try(InputStream is = stream) {
        KeyStore loadedKeystore = KeyStore.getInstance("JKS");
        loadedKeystore.load(is, storePw.toCharArray());
        return loadedKeystore;
    }
}
4
Stan Sokolov

Une autre solution Spring boot 2.x:

private static final int HTTP_PORT = 80;
private static final int HTTPS_PORT = 443;
private static final String HTTP = "http";
private static final String USER_CONSTRAINT = "CONFIDENTIAL";

@Bean
public ServletWebServerFactory servletContainer() {
    TomcatServletWebServerFactory Tomcat = new TomcatServletWebServerFactory() {
        @Override
        protected void postProcessContext(Context context) {
            SecurityConstraint securityConstraint = new SecurityConstraint();
            securityConstraint.setUserConstraint(USER_CONSTRAINT);
            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(HTTP_PORT);
    connector.setSecure(false);
    connector.setRedirectPort(HTTPS_PORT);
    return connector;
}

Et définissez vos propriétés server.port = 44

2
max

Jetez un œil à: https://github.com/creactiviti/spring-boot-starter-acme . Il est très facile de générer automatiquement un certificat SSL basé sur LetsEncrypt.

Du README:

  1. Ajoutez le module à votre fichier pom.xml en tant que dépendance.

  2. Construisez votre projet.

  3. Déployez-le sur une machine cible et pointez votre nom de domaine vers l'adresse IP de cette machine. LetsEncrypt valide votre propriété du domaine en effectuant un rappel au point de terminaison http: //your-domain/.well-known/acme-challenge/ {token} exposé par ce module.

  4. Assurez-vous que votre serveur a openssl disponible sur son $ PATH.

  5. Pour activer spring-boot-starter-acme et générer un certificat, exécutez:

    Sudo Java -Dserver.port=80 -Dacme.enabled=true -Dacme.domain-name=<YOUR_DOMAIN_NAME> -Dacme.accept-terms-of-service=true -jar mysecureapp-0.0.1-SNAPSHOT.jar

  6. Vérifiez sur votre console que le certificat a bien été généré.

  7. Arrêtez votre application et configurez-la pour utiliser le certificat généré:

    server.port=443 server.ssl.key-store=keystore.p12 server.ssl.key-store-password=password server.ssl.keyStoreType=PKCS12

1
acohen