Reputation: 1682
I have Spring Gateway 2023.0.3 project which I want to configure to limit only internally to forward headers from network requests. Example request:
API client -> Spring gateway -> Spring Authorization server
After that Spring gateway gets Bearer token and makes requests to microservices.
I managed to make it work by adding:
@Component
@Order(2)
public class CustomAuthorizationFilter extends AbstractGatewayFilterFactory<CustomAuthorizationFilter.Config> {
public CustomAuthorizationFilter() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
final StringBuilder jwtToken = new StringBuilder();
exchange.getRequest().getHeaders().forEach((headerName, headerValues) -> {
for (String value : headerValues) {
if (value.contains("Bearer")) {
System.out.println("Header with Bearer token found: " + headerName + " = " + value);
jwtToken.append(value);
}
}
});
exchange.getRequest().mutate()
.header("Authorization", jwtToken.toString())
.build();
return chain.filter(exchange);
};
}
public static class Config {
}
}
.....
routes:
- id: auth
uri: lb://internal
predicates:
- Path=/platform/**
filters:
- name: CircuitBreaker
- name: CustomAuthorizationFilter
args:
name: auth
- RemoveResponseHeader=Cookie
Into very old version of Spring gateway it's working fine. But now request is not forwarded properly. I need to add and allow CustomAuthorizationFilter
. It's a security issue because external API clients should not be allowed to pass requests with Bearer token. Do you know any possible solution?
Upvotes: 1
Views: 213
Reputation: 462
You can try adding a logic to allow only internal requests (those coming from trusted sources, such as the Gateway itself) to forward the Bearer token header.
@Component
@Order(2)
public class CustomAuthorizationFilter extends AbstractGatewayFilterFactory<CustomAuthorizationFilter.Config> {
public CustomAuthorizationFilter() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
// Check if request is internal
String clientIp = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
if (isInternalRequest(clientIp)) {
final StringBuilder jwtToken = new StringBuilder();
exchange.getRequest().getHeaders().forEach((headerName, headerValues) -> {
for (String value : headerValues) {
if (value.contains("Bearer")) {
System.out.println("Header with Bearer token found: " + headerName + " = " + value);
jwtToken.append(value);
}
}
});
exchange.getRequest().mutate()
.header("Authorization", jwtToken.toString())
.build();
}
return chain.filter(exchange);
};
}
// Check if the request is from a trusted internal IP
private boolean isInternalRequest(String clientIp) {
// Add your logic here to verify only internal IP ranges or trusted proxies
return clientIp.startsWith("192.168.xxx") || clientIp.startsWith("10.xxx");
}
public static class Config {
}
}
And, ensure that only requests from the gateway or internal services can pass the Authorization
header. For this, you can add a RemoveRequestHeader
filter to strip the Authorization
header from any incoming requests from external clients before it reaches the CustomAuthorizationFilter
.
routes:
- id: auth
uri: lb://internal
predicates:
- Path=/platform/**
filters:
- RemoveRequestHeader=Authorization # Remove Authorization header from external requests
- CustomAuthorizationFilter # Add the token for internal use after validation
- name: CircuitBreaker
- RemoveResponseHeader=Cookie
With this setup, external clients' Authorization headers will be removed before forwarding, and the custom filter will re-add the Bearer token only if the request is from a trusted internal source.
Upvotes: 1