Spring Boot: Set Proxy For Embedded Tomcat Via YAML
Hey guys! Ever found yourself wrestling with proxy configurations in your Spring Boot application, especially when dealing with embedded Tomcat instances? It can be a bit tricky, particularly when you need to ensure that your application correctly handles things like SAML SSO assertions with Okta. Today, we're going to dive deep into how you can set proxyName
and proxyPort
values directly in your application.yml
file. This is super useful when your app sits behind a proxy and needs to know its external-facing identity. Let's get started!
Understanding the Need for Proxy Configuration
Before we jump into the how-to, let's quickly cover the why. Proxy configurations become essential when your Spring Boot application is deployed behind a proxy server. Think of it like this: your app is inside a building (the network), and the proxy server is the front desk. When external requests come in, they hit the proxy first. If your application isn't aware of the proxy, it might generate URLs and redirects using its internal address, which won't work for external users.
This is especially crucial when dealing with protocols like SAML (Security Assertion Markup Language). SAML is often used for Single Sign-On (SSO), where your application relies on an Identity Provider (IdP) like Okta to authenticate users. When your app receives a SAML assertion, it needs to validate it. Part of this validation involves checking the issuer and other URLs within the assertion. If your app doesn't know it's behind a proxy, it might use the wrong hostname or port, leading to validation failures and SSO headaches.
So, setting the proxyName
and proxyPort
ensures that your application generates the correct URLs, matching the external view of your application. This is vital for seamless SSO and other proxy-aware functionalities. We'll walk through the specific steps to configure this in your application.yml
file, making sure your Spring Boot app plays nice with your proxy setup.
Step-by-Step Guide to Setting Proxy Properties in application.yml
Alright, let's get our hands dirty with some code! The beauty of Spring Boot is its convention-over-configuration approach, and setting proxy properties is no exception. We'll leverage Spring Boot's built-in properties to configure our embedded Tomcat instance. The key is to use the server.tomcat
namespace in your application.yml
file. This namespace allows us to directly configure Tomcat-specific settings.
Here’s how you can set the proxyName
and proxyPort
:
server:
port: 8080 # Your application port
tomcat:
protocol-header: X-Forwarded-Proto # Most proxies forward the protocol in this header
remote-ip-header: X-Forwarded-For # Most proxies forward the client IP in this header
port-header: X-Forwarded-Port # Most proxies forward the port in this header
proxies-header: X-Forwarded-Host # Most proxies forward the Host in this header
proxy-port: 443 # The external port your application is accessed on
proxy-name: yourdomain.com # The external hostname or domain
Let’s break down each of these properties:
server.port
: This is the port your application listens on internally. It's a standard Spring Boot property, but it's worth mentioning for context.server.tomcat.protocol-header
: This tells Tomcat which header contains the protocol used by the client (e.g.,http
orhttps
). Most proxies useX-Forwarded-Proto
.server.tomcat.remote-ip-header
: This specifies the header that contains the client's IP address. Proxies commonly useX-Forwarded-For
.server.tomcat.port-header
: This indicates the header that holds the client's port.X-Forwarded-Port
is a frequent choice.server.tomcat.proxies-header
: Tells Tomcat which header contains the list of proxies that have been traversed. This is often set toX-Forwarded-Host
.server.tomcat.proxy-port
: This is the external port on which your application is accessed. For instance, if your application is accessed via HTTPS on port 443, you'd set this to443
.server.tomcat.proxy-name
: This is the external hostname or domain name used to access your application. For example,yourdomain.com
.
Important Note: The protocol-header
, remote-ip-header
, port-header
, and proxies-header
properties are crucial for Tomcat to correctly handle requests that come through the proxy. Without these, Tomcat might not recognize that it's behind a proxy and could use the internal IP address and port, leading to issues.
By setting these properties in your application.yml
, you're telling the embedded Tomcat instance to be aware of the proxy and use the correct external-facing information. Remember to replace yourdomain.com
and 443
with your actual domain and port. This configuration ensures that your application generates the correct URLs and handles redirects properly, especially vital for SAML SSO and other scenarios where the external view of your application matters.
Ensuring Secure Communication: The Role of secure
and scheme
While setting proxyName
and proxyPort
is a big step, it's also crucial to ensure that your application knows whether it's communicating over a secure connection (HTTPS). This is where the secure
and scheme
properties come into play. These properties work hand-in-hand with the proxyName
and proxyPort
to provide a complete picture of your application's external identity.
Let's delve into why these properties are important. When your application is behind a proxy, the connection between the client and the proxy might be HTTPS, while the connection between the proxy and your application could be HTTP. In such cases, your application needs to know that the external connection is secure, even if the internal connection isn't. This is essential for generating correct URLs and ensuring that security-sensitive operations, like setting cookies, are done over HTTPS.
In the context of SAML SSO, the secure
and scheme
properties are vital for validating assertions. The SAML assertion might contain URLs that specify HTTPS. If your application doesn't recognize that it's being accessed over HTTPS, the validation will fail, and the SSO process will break down. Think of it as your application needing to wear the right glasses to see the world correctly – the secure
and scheme
properties are those glasses.
So, how do we configure these properties? Unfortunately, there isn't a direct server.tomcat.secure
or server.tomcat.scheme
property in Spring Boot's default configuration. However, we can achieve the same result by using a combination of the properties we've already discussed and a bit of conditional logic in our application.
Here’s how you can approach it:
- Leverage
protocol-header
: As we saw earlier, theserver.tomcat.protocol-header
property tells Tomcat which header contains the protocol. If your proxy sets theX-Forwarded-Proto
header tohttps
, Tomcat can infer that the connection is secure. - Conditional Logic (if needed): In some cases, you might need to explicitly set the scheme in your application code. For instance, if you're generating URLs, you can check the value of the
X-Forwarded-Proto
header and set the scheme accordingly. This can be done using Spring'sHttpServletRequest
object.
Here’s a snippet of code that demonstrates how you might do this:
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
public class URLHelper {
public static String buildURL(HttpServletRequest request, String path) {
ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromRequestUri(request);
if (