Peter Penzov
Peter Penzov

Reputation: 1682

Limit header forward to internal request

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

Answers (1)

Superman
Superman

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

Related Questions