Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disable Keycloak authentication for a specific url in spring-boot

Front end of my spring-boot service gets rendered in a 3rd party dashboard. That dashboard also has a generic search bar which we want to use. Now, once we implemented Keycloak authentication, we started facing problems specifically in this search bar. All the other API's works fine because they are called from my front end only, But search API gets called by the 3rd party dashboard.

Weirdly, 3rd party calls my method using Http OPTION method, but my endpoint is registered as GET.

For an interim fix, we are trying to disable the auth on search API only and does not seems to work at all. My configurer is:

@KeycloakConfiguration
@Profile("!local") // in local profile InsecureLocalConfigurer must be included instead
public class KeycloakSecurityConfigurer extends KeycloakWebSecurityConfigurerAdapter {


    /**
     * Enable Keycloak configuration over Spring Boot config instead of {@code keycloak.json} file.
     *
     * @see <a href="https://www.keycloak.org/docs/latest/securing_apps/index.html#spring-boot-integration">
     * Spring Boot Integration</a>
     */
    @Bean
    @Nonnull
    public KeycloakConfigResolver keycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    /**
     * Registers the KeycloakAuthenticationProvider with the authentication manager.
     */
    @Autowired
    public void configureGlobal(@Nonnull final AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(keycloakAuthenticationProvider());
    }

    /**
     * Accept only bearer token authentication.
     *
     * @see <a href="https://www.keycloak.org/docs/latest/securing_apps/index.html#spring-security-configuration">
     *     Spring Security Configuration</a>
     * @see NullAuthenticatedSessionStrategy
     * @return {@link NullAuthenticatedSessionStrategy} instance.
     */
    @Override
    @Nonnull
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new NullAuthenticatedSessionStrategy();
    }

    /**
     * All request are checked regarding valid token, except <code>/health</code> check.
     * If configuration property <code>rca.security.enable</code> is set to <code>false</code>false
     * (default is true) then all requests are permitted without authentication.
     *
     * <p>
     * <b>CSRF security is disabled</b> since our app is not multipart web form app.
     * See more at: <ul>
     *
     * <li><a href="https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-security.html#boot-features-security-csrf">
     * Cross Site Request Forgery Protection</a></li>
     * <li><a href="https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html">
     * Cross Site Request Forgery (CSRF)</a></li>
     * </ul>
     *
     * @param http the {@link HttpSecurity} to modify
     * @throws Exception if an error occurs
     */
    @Override
    protected void configure(@Nonnull final HttpSecurity http) throws Exception {
        super.configure(http);

        http.csrf().disable();

        http
                .cors()
                .and()
                .authorizeRequests()
                .antMatchers("/health", "/error").permitAll()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .anyRequest().authenticated();
    }

    /**
     * Avoid double {@link KeycloakAuthenticationProcessingFilter} bean registration.
     *
     * <p>
     * This will set {@link AbstractAuthenticationProcessingFilter#continueChainBeforeSuccessfulAuthentication} to
     * {@code false}, meaning that <b>after success authentication by this Keycloak filter -
     * further filters will be skipped</b>. See
     * {@link KeycloakAuthenticationProcessingFilter#KeycloakAuthenticationProcessingFilter(
     * org.springframework.security.authentication.AuthenticationManager,
     * org.springframework.security.web.util.matcher.RequestMatcher) KeycloakAuthenticationProcessingFilter constructor}
     *
     * @param filter {@link KeycloakAuthenticationProcessingFilter} auth processing filter
     * @return disabled {@link FilterRegistrationBean}
     * @see <a href="https://www.keycloak.org/docs/latest/securing_apps/index.html#avoid-double-filter-bean-registration">
     * Avoid double Filter bean registration</a>
     */
    @Bean
    @Nonnull
    public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(
            @Nonnull final KeycloakAuthenticationProcessingFilter filter) {

        final FilterRegistrationBean<KeycloakAuthenticationProcessingFilter> registrationBean =
                new FilterRegistrationBean<>(filter);

        registrationBean.setEnabled(false);
        return registrationBean;
    }

    /**
     * Avoid double {@link KeycloakPreAuthActionsFilter} bean registration.
     *
     * @param filter {@link KeycloakPreAuthActionsFilter} filter
     * @return disabled {@link FilterRegistrationBean}
     * @see <a href="https://www.keycloak.org/docs/latest/securing_apps/index.html#avoid-double-filter-bean-registration">
     * Avoid double Filter bean registration</a>
     */
    @Bean
    @Nonnull
    public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(
            @Nonnull final KeycloakPreAuthActionsFilter filter) {
        final FilterRegistrationBean<KeycloakPreAuthActionsFilter> registrationBean =
                new FilterRegistrationBean<>(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    /**
     * Avoid double {@link KeycloakAuthenticatedActionsFilter} bean registration.
     *
     * @param filter {@link KeycloakAuthenticatedActionsFilter} filter
     * @return disabled {@link FilterRegistrationBean}
     * @see <a href="https://www.keycloak.org/docs/latest/securing_apps/index.html#avoid-double-filter-bean-registration">
     * Avoid double Filter bean registration</a>
     */
    @Bean
    public FilterRegistrationBean keycloakAuthenticatedActionsFilterBean(
            @Nonnull final KeycloakAuthenticatedActionsFilter filter) {
        final FilterRegistrationBean<KeycloakAuthenticatedActionsFilter> registrationBean =
                new FilterRegistrationBean<>(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    /**
     * Avoid double {@link KeycloakSecurityContextRequestFilter} bean registration.
     *
     * @param filter {@link KeycloakSecurityContextRequestFilter} filter
     * @return disabled {@link FilterRegistrationBean}
     * @see <a href="https://www.keycloak.org/docs/latest/securing_apps/index.html#avoid-double-filter-bean-registration">
     * Avoid double Filter bean registration</a>
     */
    @Bean
    public FilterRegistrationBean keycloakSecurityContextRequestFilterBean(
            @Nonnull final KeycloakSecurityContextRequestFilter filter) {

        final FilterRegistrationBean<KeycloakSecurityContextRequestFilter> registrationBean =
                new FilterRegistrationBean<>(filter);

        registrationBean.setEnabled(false);
        return registrationBean;
    }
}

I've tried multiple approaches but none of them works. Sometimes I start getting CORS exception, once I fix it, it again starts throwing unauthorised user error. Kindly help in identifying what I am doing wrong.

Stuff which I tried yet:

  1.         super.configure(http);
            http.csrf().disable();
    
            http
    
    
               .cors()
                .and()
                .authorizeRequests()
                .antMatchers("/health", "/error").permitAll()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .anyRequest().authenticated();
    
  2. @Override public void configure(final WebSecurity web) { web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**"); }

  3. ` http.csrf().disable();

    http
            .cors()
            .and()
            .authorizeRequests()
            .antMatchers("/health", "/error").permitAll()
            .antMatchers(HttpMethod.OPTIONS, "/item/search").permitAll()
            .antMatchers(HttpMethod.OPTIONS, "/item/search/").permitAll()
            .antMatchers(HttpMethod.OPTIONS, "/item/search/**").permitAll()
            .antMatchers(HttpMethod.OPTIONS, "/**/search").permitAll()
            .antMatchers(HttpMethod.OPTIONS, "/**/search/").permitAll()
            .antMatchers(HttpMethod.OPTIONS, "/**/search/**").permitAll()
            .anyRequest().authenticated();`
    
like image 993
diwakarb Avatar asked Nov 16 '22 18:11

diwakarb


1 Answers

Maybe not related to you, but my issue was that the /error path should be whitelisted as well.

The fact that the my call ended up in error made a redirect to /error and since /error was secure I got the redirect to the login.

@Override
protected void configure(HttpSecurity http) throws Exception {
    super.configure(http);
    http
        .authorizeRequests()
        .antMatchers("/public/**").permitAll()
        .antMatchers("/secure/**").hasAuthority(...)
        .antMatchers("/error").permitAll()
}
like image 163
gaetanc Avatar answered Dec 04 '22 12:12

gaetanc