mkopylec / charon-spring-boot-starter

Reverse proxy implementation in form of a Spring Boot starter.
Apache License 2.0
240 stars 54 forks source link

reverse proxy after SSO #110

Open bhargaviaaa opened 3 years ago

bhargaviaaa commented 3 years ago

How to run ReverseProxyFilter after SSO is successfull. SSO is done using filter from external jar. Setting filter order to least precedence is not working. It is not taking to login page.

mkopylec commented 3 years ago

"Taking to login page" is probably done in the SSO filter by sending a redirect response (HTTP 301 with 'Location' header). The order of the ReverseProxyFilter can be set to either:

mkopylec commented 3 years ago

If the above is not your case, please provide some more details on how you expect Charon to work.

codebje commented 1 year ago

I have implemented this, using WebFlux. I used a typical SecurityWebFilterChain set to @Order(1) and set the Charon configuration to .filterOrder(2). The end result is that, depending on configuration in the security filter, an SSO login is required before proxying requests.

However, Charon's custom ClientRequest implementation introduces a wrinkle. Typically one might use the ServerOAuth2AuthorizedClientExchangeFilterFunction on a client request to introduce a Bearer token based on the OAuth2 user (or to redirect to the SSO provider if a fresh token is required), but like many filter functions this modifies the client request to add the appropriate header. It does so by calling ClientRequest.from(...) which in turn copies headers, attributes, body, http request consumer, and cookies from the existing request. The last part of that list is the problem, because attempting to read cookies from an HttpRequest throws an exception.

I have worked around it by first creating a ClientRequest by copying everything except cookies, then invoking the filter function - see below. I am not sure why HttpRequest doesn't forward the call to cookies down to its delegate, though: I think everything would just work as expected if it did.

    private static class NoCookesFilter implements ExchangeFilterFunction {
        @Override
        public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
            //noinspection ConstantConditions - disable @NotNull check for .httpRequest
            var noCookiesReq = ClientRequest.create(request.method(), request.url())
                    .headers(headers -> headers.addAll(request.headers()))
                    .attributes(attrs -> attrs.putAll(request.attributes()))
                    .body(request.body())
                    .httpRequest(request.httpRequest())
                    .build();
            return next.exchange(noCookiesReq);
        }
    }