0
votes

The problem is as follows. I implemented the login through Keycloak Bearer Spring security like this

public class KeycloakSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
    keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
    auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Override
public void configure(HttpSecurity http) throws Exception {
    super.configure(http);
    http.sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .sessionAuthenticationStrategy(sessionAuthenticationStrategy())
            .and()
            .csrf().disable()
            .addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
            .addFilterBefore(keycloakAuthenticationProcessingFilter(),               X509AuthenticationFilter.class)
            .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
            .and()
            .authorizeRequests().antMatchers(Constants.API_BASE_PATH + "/**").authenticated();
    }

}

, when I send the Authorization request header empty, keycloak throws error 401. Which I cannot catch through @ExceptionHandler like this :

@ExceptionHandler(RuntimeException.class) protected ResponseEntity keycloakAuthenticationExceptionn(RuntimeException ex) { return buildResponseEntity(new ErrorResponseWrapper(BAD_REQUEST,new MessageResponse(ex.getLocalizedMessage()),ex,ErrorCode.NOT_AUTHORIZED)); } .

3

3 Answers

0
votes

I'm not sure about the answer but i faced something like your question. ExceptionHandler working after http filters, so maybe Keycloak exception throws in his filter, before the request can to be handled using your ExceptionHandler. So you can trace the whole logs to see from where the exception thrown. I hope that will help you

0
votes
**Thanks for answers!**

I think, this is the problem:

Earlier I used dependency keycloak version 4.0.0.Final
pom.xml dependency
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-spring-boot-starter</artifactId>
        <version>4.0.0.Final</version>
    </dependency>
 and spring boot version 1.5.4.RELEASE. Everything worked great.
Now I'm using spring boot version 2.1.5.RELEASE and keycloak version 10.0.1
pom.xml dependency
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-spring-boot-2-adapter</artifactId>
        <version>10.0.1</version>
    </dependency>
I checked it again from Postman when sending Authorization token "bearer " + "token" in the request header. I get a response with two the same WWW-Authenticate values ​​in the header.


Earlier, header came in a single copy.

Can you please tell me what the problem ?.
0
votes

KeyCloak has a KeycloakAuthenticationFailureHandler that handles authentication failures. I was able to solve a similar problem by creating a Custom KeycloakAuthenticationFailureHandler then set my Custom class while overriding the KeycloakAuthenticationProcessingFilter.

@Bean
    @Override
    protected KeycloakAuthenticationProcessingFilter keycloakAuthenticationProcessingFilter() throws Exception {
        KeycloakAuthenticationProcessingFilter filter = new KeycloakAuthenticationProcessingFilter(this.authenticationManagerBean());
        filter.setSessionAuthenticationStrategy(this.sessionAuthenticationStrategy());
        filter.setAuthenticationFailureHandler(new CustomKeycloakAuthenticationFailureHandler());
        return filter;
    }

Inside my Custom Class...

public class CustomKeycloakAuthenticationFailureHandler implements AuthenticationFailureHandler {

public CustomKeycloakAuthenticationFailureHandler() {}

@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
    if (!response.isCommitted()) {
        if (KeycloakCookieBasedRedirect.getRedirectUrlFromCookie(request) != null) {
            response.addCookie(KeycloakCookieBasedRedirect.createCookieFromRedirectUrl((String)null));
        }

        //response.sendError(401, "Unable to authenticate using the Authorization header");
        response.setContentType("application/json");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.getOutputStream().println("{ \"error\": \"" + exception.getMessage() + "\" }");
    } else if (200 <= response.getStatus() && response.getStatus() < 300) {
        throw new RuntimeException("Success response was committed while authentication failed!", exception);
    }
}

}

I am able to use the response OutputStream to customize my response to the client. I commented the default KeyCloak response.sendError line.

It looks like KeyCloak handles the exceptions internally.

This solution also solves the issue where the header: WWW-Authenticate is not duplicated in the response.

Turning on DEBUG for KeyCloak troubleshooting HELPS: logging.level.org.keycloak=DEBUG

Hope this helps.