Home > Blockchain >  Spring boot with keycloak add api key auth for specific endpoint
Spring boot with keycloak add api key auth for specific endpoint

Time:11-18

in spring boot app I have:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
@Slf4j
public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    @Autowired
    List<String> aIPWhiteList;

    @Autowired
    List<String> bIPWhiteList;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        String aIPAddressesFilterStr = defineIPFilters(aIPWhiteList);
        String bIPAddressesPFilterStr = defineIPFiltersbIPWhiteList);

        http.authorizeRequests()
                .antMatchers("/order/a/**").access(aIPAddressesFilterStr)
                .antMatchers("/b/order").access(bIPAddressesFilterStr)
                .anyRequest().permitAll();

        http.cors().and().csrf().disable();
    }

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

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

    private String defineP4IPFilters(List<String> whiteList) {
        StringBuilder ipAddressesFilterStr = new StringBuilder();
        for (String ip: whiteList) {
            ipAddressesFilterStr.append("hasIpAddress('").append(ip).append("') or ");
        }
        return ipAddressesFilterStr.substring(0, ipAddressesFilterStr.length() - 4);
    }
    
}

I wonder how can I for this "b/order" make another auth, based on API Key stored in headers. Basically only for this 1 endpoint I want authorize users differently. Other endpoints are authorized by keycloak, are done from registered users. But here I would like to auth it only by api key that is static.

any ideas ?

thanks!

CodePudding user response:

I have two ideas which should save you quite some trouble, even if does not answer directly your question:

Do not use KeycloakWebSecurityConfigurerAdapter

It is part of the (very) deprecated Keycloak adapters for spring. Use spring-boot-starter-oauth2-resource-server instead. Refer to those tutorials for various ways to do it (with Keycloak)

Use OAuth2 client-credentials flow in place of API key

It serves that exact purpose: authenticate a trusted programmatic clients with "static" secrets.

With Keycloak, just declare "confidential" clients ("Client authentication" set to "On" and "Service Accounts Roles" enabled). Secret is to be retrieved from a "credentials" tab for this clients in Keycloak admin console. You can then define and assign different roles for each client if needed (such roles will appear in access-tokens, so you'll be able to use it in spring-security access control decisions)

Such clients will authorize their requests to resource-server(s) with access-tokens issued by your Keycloak instance just as other clients (used by humans) do. Only the protocol to get tokens (OAuth2 flow) differs: client-credentials for "robots" and authorization-code for "humans".

From the resource-server point of view, there will be absolutely no difference: all requests will be authorized with access-tokens issued by the same authorization-server => no need for a different authentication mechanism on some endpoints, just apply regular role-based access-control or wahtever else written with spring-security expressions.

  • Related