Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using both Realm roles and ressource roles with Keycloak/SpringSecurity

I'm trying to use both realm and resource roles in a java application with spring-security and keycloak. Unfortunately, keycloak will only return one or the other depending on the value of :

keycloak.use-resource-role-mappings=true

You can still get both with custom code, but it messes up annotations such as @PreAuthorize or the spring-boot method .isUserInRole, which leads to ugly code.

Is there a way to override either the @PreAuthorize method or the JSON token Keycloak returns in order to use both realm and resource roles? Currently, my implementation of keyclaok use a custom method replacing the @PreAuthorize at the start of every method, and it isn't pretty.

Thank you in advance.

like image 630
Taarawa Kijaenb Avatar asked Feb 10 '20 09:02

Taarawa Kijaenb


Video Answer


1 Answers

Got it to work overriding the KeycloakAuthenticationProvider as I was using it in the SecurityConfig. Here's the code for the custom provider

public class CustomKeycloakAuthenticationProvider extends KeycloakAuthenticationProvider {
    private GrantedAuthoritiesMapper grantedAuthoritiesMapper;

    public void setGrantedAuthoritiesMapper(GrantedAuthoritiesMapper grantedAuthoritiesMapper) {
        this.grantedAuthoritiesMapper = grantedAuthoritiesMapper;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) authentication;
        List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();

        for (String role : token.getAccount().getRoles()) {
            grantedAuthorities.add(new KeycloakRole(role));
        }

// ADDING THE MODIFICATION AND ENABLING ROLE FROM RESSOURCE

        for (String role : token.getAccount().getKeycloakSecurityContext().getToken().getResourceAccess("CustomApplication").getRoles()) {
            grantedAuthorities.add(new KeycloakRole(role));
        }
        return new KeycloakAuthenticationToken(token.getAccount(), token.isInteractive(), mapAuthorities(grantedAuthorities));
    }

    private Collection<? extends GrantedAuthority> mapAuthorities(
            Collection<? extends GrantedAuthority> authorities) {
        return grantedAuthoritiesMapper != null
            ? grantedAuthoritiesMapper.mapAuthorities(authorities)
            : authorities;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return KeycloakAuthenticationToken.class.isAssignableFrom(aClass);
    }


}

And the modifications in SecurityConfig

@Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) {
        CustomKeycloakAuthenticationProvider keycloakAuthenticationProvider = CustomKeycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    private CustomKeycloakAuthenticationProvider CustomKeycloakAuthenticationProvider() {
        return new CustomKeycloakAuthenticationProvider();
    }

Thank you for the help Alexander !

like image 97
Taarawa Kijaenb Avatar answered Oct 11 '22 13:10

Taarawa Kijaenb