jhipster / generator-jhipster

JHipster is a development platform to quickly generate, develop, & deploy modern web applications & microservice architectures.
https://www.jhipster.tech
Apache License 2.0
21.6k stars 4.03k forks source link

Keycloak doesn't redirect to the proxy after authentication #26521

Closed henri-tremblay closed 5 months ago

henri-tremblay commented 5 months ago
Overview of the issue

If you do

docker compose -f src/main/docker/keycloak.yml up -d
./mvnw -Ptls
./npmw run start-tls

And I then authenticated, the redirect_uri sent to keycloak is https://localhost:8080/login/oauth2/code/oidc instead of port 9000, from browser-sync.

Motivation for or Use Case

If feel my flow is the normal development flow. UI should always be served by the proxy, so we would never use 8080 as the redirect_uri.

Suggest a Fix

The redirect_uri should be the one forwarded from the proxy but I am not sure how to do that yet.

JHipster Version(s)

I tried on 8.5.0 and earlier versions. It's been like this for a while.

JHipster configuration

"authenticationType": "oauth2"

Browsers and Operating System

Chrome on Mac

henri-tremblay commented 5 months ago

A possible solution that works for me is the following. Please tell me if you are alright with it before I create the PR.

Step 1: Pass forwarding headers

In webpack.custom.js, add this to the BrowserSyncPlugin configuration.

            proxyReq: [
              function(proxyReq) {
                proxyReq.setHeader('X-Forwarded-Host', 'localhost:9000');
                proxyReq.setHeader('X-Forwarded-Proto', 'https');
              }
            ]

Step 2: Add a Forward filter

In WebConfigurer.java add a new bean:

    @Bean
    @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
    FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
        FilterRegistrationBean<ForwardedHeaderFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new ForwardedHeaderFilter());
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return bean;
    }

The setOrder is required to make sure the filter is called before the oauth one. By default it's not the case and the redirect is done too soon.

mraible commented 5 months ago

I tried using the main branch to reproduce this problem. I started by running jhipster jdl blog-oauth2 and testing with mvn and npm start. Everything works as expected and I'm redirected back to http://localhost:9000 after authenticating with Keycloak.

When I try to run ./mvnw -Ptls, it results in an issue with @spring.profiles.active@.

Screenshot 2024-06-24 at 12 39 06
henri-tremblay commented 5 months ago

Interesting. I wasn't on the main branch. I'm on the release latest version. I haven't tried without tls. For me it makes sense to run in tls when using oath. I was also surprised that keycloak is not launched in tls. But I will give it a spin just to check.

mraible commented 5 months ago

I also have issues on the main branch with the prod profile. If I revert overriding the maven-resources-plugin in my project, it works. However, the tls profile still doesn't work.

@mshima FYI... it looks like we may have an issue with the prod and tls profiles on main.

mshima commented 5 months ago

I also have issues on the main branch with the prod profile. If I revert overriding the maven-resources-plugin in my project, it works. However, the tls profile still doesn't work.

What kind of problem?

@mshima FYI... it looks like we may have an issue with the prod and tls profiles on main.

Every CI samples uses prod profile except h2 tests.

Maven profiles removes default profiles so: ./mvnw -Ptls won't work without dev or prod. You should use ./mvnw -Pdev,tls or ./mvnw -Pprod,tls to make it work.

mraible commented 5 months ago

@mshima You answered and solved the problem while I was typing the message below.

It appears the tls profile is not supposed to be run by itself. If I use -Pprod,tls or -Pprod,dev, everything works as expected. I removed the maven-resources-plugin configuration and it works too.

@henri-tremblay I'm able to reproduce your issue and will try your fix.

mraible commented 5 months ago

@henri-tremblay Your fix does not work. I believe this is because Spring Security sets the redirect and it's not based off the referrer or any header that's passed in. According to this Stack Overflow Q&A, it looks like you can implement an authentication success handler to make things work.

mshima commented 5 months ago

We should drop custom BrowserSync config from wepback. Webpack should be replaced with esbuild based compiler.

henri-tremblay commented 5 months ago

@mshima Yes, sorry, I was launching from intellij the equivalent of ./mvnw dev,tls

henri-tremblay commented 5 months ago

@mraible What is happening on your side? For me the ForwardedHeaderFilter correctly picks up the X-*** to change the Host header (if I recall) that is then used to set the baseUrl for the redirect_uri (in DefaultOAuth2AuthorizationRequestResolver I think).

henri-tremblay commented 5 months ago

@mraible Reading your stack overflow, I do not even try to go back to where I was. I do https://localhost:9000 -> Sign in -> admin/admin on keycloak -> https:/localhost:8080 (or 9000 with my fix, which is what I want)

mraible commented 5 months ago

@henri-tremblay If you create a PR with your fix, I'd be happy to test it.

vishal423 commented 5 months ago

I think you don't need to define explicit bean to use forwarded headers. Setting below property should work :

server.forward-headers-strategy=NATIVE

Since enabling use of forwarded headers is a security risk, I suggest adding it under dev profile

henri-tremblay commented 5 months ago

You are right. Adding the property works as well. And yes, that's why my original forwarder was only in dev

henri-tremblay commented 5 months ago

PR created. I'm guessing the same fix is needed for vue and react. I wasn't sure which file to modify. I need to regenerate for those.