web-dev-qa-db-fra.com

Spring Boot redirige HTTP vers HTTPS

Pour les applications basées sur Spring Boot, j'ai configuré les propriétés SSL sur application.properties, voir ma configuration ici:

server.port=8443
server.ssl.key-alias=Tomcat
server.ssl.key-password=123456
server.ssl.key-store=classpath:key.p12
server.ssl.key-store-provider=SunJSSE
server.ssl.key-store-type=pkcs12

Et j'ai ajouté la connexion à Application.class, comme

@Bean
public EmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
    final TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
    factory.addAdditionalTomcatConnectors(this.createConnection());
    return factory;
}

private Connector createConnection() {
    final String protocol = "org.Apache.coyote.http11.Http11NioProtocol";
    final Connector connector = new Connector(protocol);

    connector.setScheme("http");
    connector.setPort(9090);
    connector.setRedirectPort(8443);
    return connector;
}

Mais quand j'essaye ce qui suit par

http://127.0.0.1:9090/

rediriger vers

https://127.0.0.1:8443/

n'est pas effectuée. Qui a fait face à un problème similaire?

32
Arseniy Ulakaiev

Pour que Tomcat effectue une redirection, vous devez la configurer avec une ou plusieurs contraintes de sécurité. Vous pouvez le faire en post-traitant la Context à l'aide d'une sous-classe TomcatEmbeddedServletContainerFactory.

Par exemple:

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);
    }
};

En raison de CONFIDENTIAL et /*, Tomcat redirigera chaque demande vers HTTPS. Vous pouvez configurer plusieurs modèles et plusieurs contraintes si vous avez besoin de plus de contrôle sur ce qui est et n'est pas redirigé.

31
Andy Wilkinson

Définir cette propriété sur votre fichier d'application * .properties (et la configuration spécifique au servlet correspondante pour les en-têtes HTTPS dans le cas où vous exécutez derrière un proxy) et avoir la configuration de Spring Security (par exemple, avoir org.springframework.boot: spring-boot-starter-security sur votre chemin de classe) devrait suffire:

security.require-ssl=true

Maintenant, pour une raison quelconque, la configuration n'est pas respectée lorsque l'authentification de base est désactivée (au moins sur les anciennes versions de Spring Boot). Donc, dans ce cas, vous devrez prendre une étape supplémentaire et l'honorer vous-même en configurant manuellement la sécurité de votre code, comme ceci:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Inject private SecurityProperties securityProperties;

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

Donc, au cas où vous utilisez Tomcat derrière un proxy, vous auriez toutes ces propriétés sur votre fichier d'application * .properties:

security.require-ssl=true

server.Tomcat.remote_ip_header=x-forwarded-for
server.Tomcat.protocol_header=x-forwarded-proto
27
Rodrigo Quesada

La réponse approuvée ne m'a pas suffi.

J'ai également dû ajouter ce qui suit à ma configuration de sécurité Web, car je n'utilise pas le port 8080 par défaut:

@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(Integer.parseInt(environment.getProperty("server.http.port"))) // http port defined in yml config file
                .mapsTo(Integer.parseInt(environment.getProperty("server.port"))); // https port defined in yml config file

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

Suivez seulement 2 étapes.

1- Ajouter une dépendance de sécurité Spring dans pom.xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

2- Ajoutez cette classe sur le package racine de votre application.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.requiresChannel().anyRequest().requiresSecure();
    }
}
7
rogue lad

Dans Spring-Boot, besoin d'une dépendance inférieure

Étape 1-

<dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Étape 2- Il suffit de faire les configurations ci-dessous sur le fichier application.properties

 - server.port=8443
 - server.ssl.key.alias=ode-https
 - server.ssl.key-store-type=JKS (just for testing i USED JSK, but for production normally use pkcs12)
 - server.ssl.key-password=password
 - server.ssl.key-store=classpath:ode-https.jks

L'étape 3 doit maintenant générer un certificat en utilisant les détails ci-dessus.

keytool -genkey -alias ode-https -storetype JKS -keyalg RSA -keys ize 2048 -validity 365 -keystore ode-https.jks

Étape 4 - déplacez le certificat vers le dossier des ressources de votre programme.

Étape 5- Créer une classe de configuration

@Configuration
public class HttpsConfiguration {
    @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;
    }

    @Value("${server.port.http}") //Defined in application.properties file
    int httpPort;

    @Value("${server.port}") //Defined in application.properties file
    int httpsPort;

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

c'est ça.

6
Arvind Pant

Depuis TomcatEmbeddedServletContainerFactory a été supprimé dans Spring Boot 2, utilisez ceci:

@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);
        }
    };
}
3
Mahozad

Pour Jetty (testé avec 9.2.14), vous devez ajouter une configuration supplémentaire au WebAppContext (ajustez le pathSpec à votre goût):

import org.Eclipse.jetty.security.ConstraintMapping;
import org.Eclipse.jetty.security.ConstraintSecurityHandler;
import org.Eclipse.jetty.util.security.Constraint;
import org.Eclipse.jetty.webapp.AbstractConfiguration;
import org.Eclipse.jetty.webapp.WebAppContext;

class HttpToHttpsJettyConfiguration extends AbstractConfiguration
{
    // http://wiki.Eclipse.org/Jetty/Howto/Configure_SSL#Redirecting_http_requests_to_https
    @Override
    public void configure(WebAppContext context) throws Exception
    {
        Constraint constraint = new Constraint();
        constraint.setDataConstraint(2);

        ConstraintMapping constraintMapping = new ConstraintMapping();
        constraintMapping.setPathSpec("/*");
        constraintMapping.setConstraint(constraint);

        ConstraintSecurityHandler constraintSecurityHandler = new ConstraintSecurityHandler();
        constraintSecurityHandler.addConstraintMapping(constraintMapping);

        context.setSecurityHandler(constraintSecurityHandler);
    }
}

Câblez ensuite cette classe en ajoutant un @Configuration classe implémentant EmbeddedServletContainerCustomizer avec un nouveau Connector qui écoute le port non sécurisé:

@Configuration
public class HttpToHttpsJettyCustomizer implements EmbeddedServletContainerCustomizer
{
    @Override
    public void customize(ConfigurableEmbeddedServletContainer container)
    {
        JettyEmbeddedServletContainerFactory containerFactory = (JettyEmbeddedServletContainerFactory) container;
        //Add a plain HTTP connector and a WebAppContext config to force redirect from http->https
        containerFactory.addConfigurations(new HttpToHttpsJettyConfiguration());

        containerFactory.addServerCustomizers(server -> {
            HttpConfiguration http = new HttpConfiguration();
            http.setSecurePort(443);
            http.setSecureScheme("https");

            ServerConnector connector = new ServerConnector(server);
            connector.addConnectionFactory(new HttpConnectionFactory(http));
            connector.setPort(80);

            server.addConnector(connector);
        });
    }
}

Cela implique que SSL Connector est déjà configuré et écoute sur le port 443 dans cet exemple.

3
jebeaudet