Run a Spring-Boot application on OpenShift behind HTTPS only
When a Spring-Boot application is deployed on OpenShift, it can be reached both with a HTTP URL and a HTTPS URL. This is because OpenShift runs a proxy in front of the application which in case of HTTP just routes the request to the application. If a request comes in via HTTPS, the proxy does all the encryption handling with the client and then passes the decrypted request on to the application – on the HTTP channel – and encrypts the response before sending it to the client.
The advantage for an application developer is that you do not need to bother about the details of encryption, you just write your application and leave the rest to OpenShift.
This post shows how to setup and modify your application so that it only can be reached by HTTPS and so enforces the use of a secure conversation channel. To know how to set up a Spring-Boot application on OpenShift you might read this post.
Add the security to your project and set it to ssl only
When you setup your project with the Spring Initializr include the core/security. If you have an existing project, add the following dependency to your pom.xml
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
This enables Spring security and secures your application with the user named user and a password that is displayed on the console during startup. To force the use of HTTPS you normally only need to add the following entry to the application.properties file:
security.require-ssl=true
Now you would have an application that will automatically redirect to HTTPS (the default port in Spring Boot for HTTPS is 8443 when running on unsecure port 8080) when called on port 8080. Besides not having a certificate and the configuration to run on HTTPS, we don’t need the Basic Authentication for our purpose of running HTTPS only. So we can disable it by adding the following entry to the application.properties file:
security.basic.enabled=false
When restarting the application the need for Basic Authentication is gone, but this also disables the require-ssl setting, so we can access our application as before on the normal HTTP port.
The solution to this problem is to provide a custom configuration class:
/**
* Copyright (c) 2015 sothawo
*
*
*/
package com.sothawo.sayservice;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
/**
* Security configuration.
*
* @author P.J. Meisch (pj.meisch@sothawo.com).
*/
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requiresChannel().anyRequest().requiresSecure();
http.csrf().disable();
}
}
After adding this class to our project (as I in this case don’t need CSRF for a pure REST service behind HTTPS, I disable it here), all requests to the HTTP port are redirected to HTTPS and the Basic Authentication is still disabled (you can remove the server-require-ssl entry from the config file). So far so good.
Fix eternal redirection on OpenShift
After deploying the application in this stage to OpenShift you will notice that both requests, HTTP on port 80 and HTTPS on port 443 result in an eternal redirection to the HTTPS URL. This happens because when the application is accessed by HTTPS, the OpenShift proxy does the HTTPS handling and then contacts the application on the normal internal HTTP port. The application checks the channel and sends a redirect request to the secure channel to the client which in turn request the application from the HTTPS proxy, which will strip the HTTPS part and so on.
To fix this you need to make your application honour two special HTTP headers. Add the following lines to the application.properties file:
server.tomcat.remote_ip_header=x-forwarded-for
server.tomcat.protocol_header=x-forwarded-proto
The x-forwarded- headers are set by the proxy and by putting these settings in your configuration, the embedded tomcat checks these headers when deciding whether a redirect is needed and so even when the application is called from the proxy on HTTP, a redirect will only be requested when the proxy itself was not accessed by a secure channel.
That’s all that’s needed to run your application HTTPS only.