cditcher
cditcher

Reputation: 358

Spring boot with keycloak using nginx proxy only works if redirect_uri localhost

I have been banging my head over this one.

I have a basic web application using Spring Boot running on localhost:8082, a dockerized keycloak server running on localhost:8081 and a dockerized nginx server running on port 80.

When I was using keycloak without spring security integration, a user accessing a secured resource would be redirected to the keycloak login page at http://{keycloak-server}/auth/realms/{myrealm}/protocol/openid-connect/auth/... and everything worked great.

When I added spring security into the mix, as per this tutorial and several others, suddenly my application attempts to redirect to http://{myapp}/sso/login where there is no /sso/login endpoint so I get a 404.

I was only able to get the application routing to the correct login end-point by accessing it directly at http://localhost:8082 and setting the redirect_uri in keycloak for the client to http://localhost:8082/*.

I suspect it may have something to do with nginx config, but again, it was working before I added spring security into the mix, so I am scratching my head. Here is my nginx.conf

worker_processes 2;

events {
    worker_connections 1024;
}

http {

    proxy_set_header    Host               $host;
    proxy_set_header    X-Real-IP          $remote_addr;
    proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;
    proxy_set_header    X-Forwarded-Host   $host;
    proxy_set_header    X-Forwarded-Server $host;
    proxy_set_header    X-Forwarded-Port   $server_port;
    proxy_set_header    X-Forwarded-Proto  $scheme;

    # auth local (keycloak)
    server {
        listen  80;
        server_name auth.local;

            location / {
                # keycloak
                proxy_pass http://host.docker.internal:8081/;
            }

        }

        server {
            listen  80;
            server_name guardian.local;

                location / {
                    # send to portal
                    rewrite ^/(.*)$ http://guardian.local/portal/$1 permanent;
                }

                location /portal {
                    # guardian web-portal
                    proxy_pass http://host.docker.internal:8082;
                }
            }

}

My security config class:

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    // Submits the KeycloakAuthenticationProvider to the AuthenticationManager
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    /**
     * Used by Spring Security to add Keycloak config from spring config resource (like application.properties).
     * @return
     */
    @Bean
    public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    // Specifies the session authentication strategy
    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.authorizeRequests()
                .antMatchers("/portal/client*")
                .hasRole("user")
                .anyRequest()
                .permitAll();
    }
}

And my application.properties

server.port = 8082

keycloak.auth-server-url = http://auth.local/auth
keycloak.realm = myRealm
keycloak.resource = guardian-web-portal
keycloak.public-client = true
keycloak.use-resource-role-mappings = true
keycloak.principal-attribute = preferred_username

Any help on this would be greatly appreciated. I am using keycloak-spring-boot-starter 12.0.4 and spring-boot-starter-security 2.4.5.

Upvotes: 1

Views: 2521

Answers (1)

Ferlorin
Ferlorin

Reputation: 54

Try to add the below and change the permitAll() to authenticated()

.antMatchers("/login*", "/error*", "/sso*" ).permitAll()

on your

@Override
protected void configure(HttpSecurity http) throws Exception {
    super.configure(http);
    http.authorizeRequests()
            .antMatchers("/portal/client*")
            .hasRole("user")
            .anyRequest()
            .permitAll();
}

so in the end you will have:

@Override
protected void configure(HttpSecurity http) throws Exception {
    super.configure(http);
    http.authorizeRequests()
            .antMatchers("/login*", "/error*", "/sso*" ).permitAll()
            .antMatchers("/portal/client*")
            .hasRole("user")
            .anyRequest()
            .authenticated();
}

Upvotes: 2

Related Questions