[keycloak-user] Can I pass a principal with rest template if I'm using an async task wiht Spring Boot and Keycloak?

Matteo Salvetti teo.salv at gmail.com
Wed May 2 12:46:16 EDT 2018


Hi all,

I'm using Spring Boot and Keycloak to develop a web-app. Then I wrote a
scheduled task where I'm using the KeycloakRestTemplate to ask some data to
another app, as you can see below:

    @Override
    @Scheduled(cron="0 50 09 * * MON-FRI")
    public void concludiCommessa() {

        try {
            FDto[] ftts = new
ObjectMapper().readValue(restTemplate.getForEntity(URI.create(MY_URL),
String.class).getBody(), FDto[].class);

             ..............................
            }
        } catch (RestClientException | IOException e) {
        }
    }

If I run it on the server I have the following error:

2018-04-18 09:50:00.067 ERROR 2503 --- [pool-8-thread-1]
o.s.s.s.TaskUtils$LoggingErrorHandler    : Unexpected error occurred
in scheduled task.

java.lang.IllegalStateException: Cannot set authorization header
because there is no authenticated principal
    at org.keycloak.adapters.springsecurity.client.KeycloakClientRequestFactory.getKeycloakSecurityContext(KeycloakClientRequestFactory.java:70)
~[keycloak-spring-security-adapter-3.4.2.Final.jar:3.4.2.Final]
    at org.keycloak.adapters.springsecurity.client.KeycloakClientRequestFactory.postProcessHttpRequest(KeycloakClientRequestFactory.java:55)
~[keycloak-spring-security-adapter-3.4.2.Final.jar:3.4.2.Final]
    at org.springframework.http.client.HttpComponentsClientHttpRequestFactory.createRequest(HttpComponentsClientHttpRequestFactory.java:207)
~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
    at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.java:85)
~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:656)
~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:636)
~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
    at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:336)
~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
    at it.edile.service.api.ApiServiceImpl.concludiCommessa(ApiServiceImpl.java:287)
~[classes/:0.0.1-SNAPSHOT]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
~[na:1.8.0_161]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
~[na:1.8.0_161]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
~[na:1.8.0_161]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_161]
    at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
~[spring-context-4.3.14.RELEASE.jar:4.3.14.RELEASE]
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
~[spring-context-4.3.14.RELEASE.jar:4.3.14.RELEASE]
    at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
[spring-context-4.3.14.RELEASE.jar:4.3.14.RELEASE]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
[na:1.8.0_161]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_161]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
[na:1.8.0_161]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
[na:1.8.0_161]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[na:1.8.0_161]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[na:1.8.0_161]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_161]

Why?

How can I pass a principal if I'm using an async task?

This is my security configuration:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
    auth.authenticationProvider(keycloakAuthenticationProvider());
}

@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
    return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}

@Bean
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public KeycloakRestTemplate keycloakRestTemplate() {
    return new KeycloakRestTemplate(keycloakClientRequestFactory);
}

@Bean
public KeycloakConfigResolver keycloakConfigResolver() {
    return new KeycloakSpringBootConfigResolver();
}

 This is my keycloak properties:

#######################################
#             KEYCLOAK                #
#######################################
keycloak.realm=MY_REALM
keycloak.auth-server-url=MY_URL/auth
keycloak.ssl-required=external
keycloak.resource=EdilGest
keycloak.credentials.jwt.client-key-password=PWD
keycloak.credentials.jwt.client-keystore-file=classpath:CLIENT.jks
keycloak.credentials.jwt.client-keystore-password=PWD
keycloak.use-resource-role-mappings=true
keycloak.principal-attribute=preferred_username

I'm also trying to use the Service Account now, but it doesn't work at the
moment... Reading here:
https://www.keycloak.org/docs/latest/server_admin/index.html#_service_accounts

I have to send a request like:

POST /auth/realms/demo/protocol/openid-connect/token
    Authorization: Basic cHJvZHVjdC1zYS1jbGllbnQ6cGFzc3dvcmQ=
    Content-Type: application/x-www-form-urlencoded

    grant_type=client_credentials

to keycloak, but how can I send it using Spring? and how can I set the jks
instead of client and secret?


My security config

onfiguration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
@KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    @Autowired
    public KeycloakClientRequestFactory keycloakClientRequestFactory;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);

        http
            .httpBasic()
            .disable();

        http
        .authorizeRequests()
            .antMatchers("/webjars/**").permitAll()
            .antMatchers("/resources/**").permitAll()
            .anyRequest().hasAuthority("......")
        .and()
        .logout()
            .logoutUrl("/logout")
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
            .permitAll()
            .logoutSuccessUrl(mux)
            .invalidateHttpSession(true);

    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(keycloakAuthenticationProvider());
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new
SessionRegistryImpl());
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public KeycloakRestTemplate keycloakRestTemplate() {
        return new KeycloakRestTemplate(keycloakClientRequestFactory);
    }

    @Bean
    public KeycloakConfigResolver keycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    @Bean
    public FilterRegistrationBean
keycloakAuthenticationProcessingFilterRegistrationBean(KeycloakAuthenticationProcessingFilter
filter) {
        FilterRegistrationBean registrationBean = new
FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean
keycloakPreAuthActionsFilterRegistrationBean(KeycloakPreAuthActionsFilter
filter) {
        FilterRegistrationBean registrationBean = new
FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web
           .ignoring()
           .antMatchers("/resources/**", "/static/**", "/css/**",
"/js/**", "/images/**", "/webjars/**");
    }

}


If you want, please take a look here:
https://stackoverflow.com/questions/49900124/can-i-pass-a-principal-with-rest-template-if-im-using-an-async-task-wiht-spring


More information about the keycloak-user mailing list