Problem calling a “bearer-only” keycloak endpoint from a springboot (client app) to a also spring boot (bearer only app)

限于喜欢 提交于 2021-01-28 08:47:14

问题


Basically I'm trying to access a bearer-only endpoint from a client app which is using a "KeycloakRestTemplate".

I did follow this guidelines 1:1 (it is in German) : https://blog.codecentric.de/2017/09/keycloak-und-spring-security-teil-1-einrichtung-frontend/

My problem is that when I see the logs, the authentication on the side of the bearer only endpoint seems successful, as shown bellow:

 Found [1] values in authorization header, selecting the first value for Bearer.
o.k.a.BearerTokenRequestAuthenticator    : Verifying access_token
o.k.a.BearerTokenRequestAuthenticator    :  access_token: [LONG TOKEN HERE]
o.k.a.RefreshableKeycloakSecurityContext : checking whether to refresh.
org.keycloak.adapters.AdapterUtils       : use realm role mappings
org.keycloak.adapters.AdapterUtils       : Setting roles: 
org.keycloak.adapters.AdapterUtils       :    role: create_vouchers
org.keycloak.adapters.AdapterUtils       :    role: public_realm_access
org.keycloak.adapters.AdapterUtils       :    role: overview_orders
org.keycloak.adapters.AdapterUtils       :    role: uma_authorization
User 'c1500da2-855f-4306-ab65-662160558101' invoking 'http://localhost:8082/articles' on client 'articlesBearerOnlyService'
o.k.adapters.RequestAuthenticator        : Bearer AUTHENTICATED
.k.a.t.AbstractAuthenticatedActionsValve : AuthenticatedActionsValve.invoke /articles
o.k.a.AuthenticatedActionsHandler        : AuthenticatedActionsValve.invoke http://localhost:8082/articles
cors validation not needed as were not a secure session or origin header was null: {0}
o.k.a.AuthenticatedActionsHandler        : Policy enforcement is disabled.

but then directly afterwards on the logs comes this:

o.k.adapters.PreAuthActionsHandler       : adminRequest http://localhost:8082/login
o.k.adapters.PreAuthActionsHandler       : checkCorsPreflight http://localhost:8082/login
.k.a.t.AbstractAuthenticatedActionsValve : AuthenticatedActionsValve.invoke /login
o.k.a.AuthenticatedActionsHandler        : AuthenticatedActionsValve.invoke http://localhost:8082/login
o.k.a.AuthenticatedActionsHandler        : Origin: null uri: http://localhost:8082/login
o.k.a.AuthenticatedActionsHandler        : cors validation not needed as were not a secure session or origin header was null: {0}
o.k.a.AuthenticatedActionsHandler        : Policy enforcement is disabled.

so, it tries to redirect to adminRequest http://localhost:8082/login? why, and how could this be solved?

I did also also tried with postman (getting the acces-token from the token end-point) and pasting it on the Authorization header of this "bearer-only" endpoint, and similarly by seeing the logs, the user seems authorized exacltly like in the first log block above, the diference is that is doesn't try to redirect anywhere but I receive a 401.

{ "timestamp": "2019-09-05T11:18:51.347+0000", "status": 401, "error": "Unauthorized", "message": "Unauthorized", "path": "/articles" }

Could somebody please provide some guidance into a possible solution?

Thanks in advance!

---------------------------------------- EDITED ----------------------------------------

here is the application properties file:

server.port = 8082
spring.application.name = articleBearerOnlyService

keycloak.auth-server-url=http://localhost:8080/auth
keycloak.realm=[REALM]
keycloak.resource=articlesBearerOnlyService
keycloak.bearer-only=true
keycloak.cors=true
keycloak.credentials.secret=[SECRET]
keycloak.ssl-required = external

# access controlled through spring security
#keycloak.security-constraints[0].auth-roles[0]=overview_orders
#keycloak.security-constraints[0].security-collections[0].patterns[0]=/articles

logging.level.org.keycloak=TRACE

and here the SecurityConfig :

@KeycloakConfiguration
@EnableWebSecurity
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    private final KeycloakClientRequestFactory keycloakClientRequestFactory;

    public SecurityConfig(KeycloakClientRequestFactory keycloakClientRequestFactory) {
        this.keycloakClientRequestFactory = keycloakClientRequestFactory;
        //to use principal and authentication together with @async
        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
    }

    /* remove default spring "ROLE_" prefix appending to keycloak's roles*/
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        // NullAuthenticatedSessionStrategy() for bearer-only services
        return new NullAuthenticatedSessionStrategy();
    }

    /* configure cors & requests handling behaviour*/
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.cors()
                .and()
                .csrf()
                .disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .sessionAuthenticationStrategy(sessionAuthenticationStrategy())
                .and()
                .authorizeRequests()
                .antMatchers("/articles").hasRole("overview_orders")
                .anyRequest().permitAll();
    }


    // Spring boot integration
    @Bean
    public KeycloakConfigResolver keycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    // *************************** Avoid Bean redefinition ********************************
    @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;
    }

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

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

    @Bean
    @Override
    @ConditionalOnMissingBean(HttpSessionManager.class)
    protected HttpSessionManager httpSessionManager() {
        return new HttpSessionManager();
    }
}

回答1:


The @SpringBootApplication annotation is a composite of these three annotations: @EnableAutoConfiguration, @ComponentScan and @Configuration. Annotating a class e.g. com.example.demo.DemoApplication with @SpringBootApplication, results in Spring looking for other components, configurations, and services inside com.example.demo and all of its sub-packages.

A class like com.example.config.DemoConfig therefore cannot be found by Spring automatically. If you want, you can give hints to Spring where to look for components via @ComponentScan(basePackages = "com.some.package"). Check out this article if you like to know more.




回答2:


In this particular case, my @KeycloakConfiguration class SecurityConfig{...}, was completely ignored, and thus the application behaved as if none security config was provided at all.

Now, why was the SecurityConfig ignored? - it turned out to be (I almost feel shame) path location of the class; I usually would place such a class under:

com.[company].[domain].configuration

In my case (since I'm only prototyping with keycloak + spring and not particularly concerned with class location right now). I did place my SecurityConfig class under:

com.[company].configuration

This made spring boot completely ignore this class.

Follow up question: I'm new to Sprint boot, is it 100% necessary to place all code under "com.[company].[domain].configuration", without modifying the pom (just having a newly created vanilla springboot project via the initializr)?



来源:https://stackoverflow.com/questions/57804416/problem-calling-a-bearer-only-keycloak-endpoint-from-a-springboot-client-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!