Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot - How to disable Keycloak?

I have a Spring Boot project with keycloak integrated. Now I want to disable keycloak for testing purposes.

I tried by adding keycloak.enabled=false to application.properties as mentioned in Keycloak documentation but it didnt work.

So how do I disable it?

like image 532
Charlie Avatar asked Dec 18 '17 02:12

Charlie


2 Answers

My Workaround:

1. Create a Custom-Filter and add it to the (Spring) Security-Chain in early position.
2. Create a flag in the application.yml (securityEnabled)
3. Query the flag in the Custom-Filter. If 'true' simply go on with the next filter by calling chain.doFilter(). If 'false' create a dummy Keycloak-Account set the roles you need and set it to the context.
4. By the way the roles are also outsourced to the application.yml
5. Skip the rest of the filters in the Security-Chain (so no keycloak-stuff is executed and the corresponding Authorization happend)

In Detail:

1. Class of Custom-Filter

public class CustomFilter extends OncePerRequestFilter {

  @Value("${securityEnabled}")
  private boolean securityEnabled;

  @Value("${grantedRoles}")
  private String[] grantedRoles;

  @Override
  public void doFilterInternal(HttpServletRequest req, HttpServletResponse res,
                       FilterChain chain) throws IOException, ServletException {

      if (!securityEnabled){
          // Read roles from application.yml
          Set<String> roles = Arrays.stream(grantedRoles)
                  .collect(Collectors.toCollection(HashSet::new));
          // Dummy Keycloak-Account
          RefreshableKeycloakSecurityContext session = new RefreshableKeycloakSecurityContext(null, null, null, null, null, null, null);
          final KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = new KeycloakPrincipal<>("Dummy_Principal", session);
          final KeycloakAccount account = new SimpleKeycloakAccount(principal, roles, principal.getKeycloakSecurityContext());
          // Dummy Security Context
          SecurityContext context = SecurityContextHolder.createEmptyContext();
          context.setAuthentication(new KeycloakAuthenticationToken(account, false));
          SecurityContextHolder.setContext(context);

          // Skip the rest of the filters
          req.getRequestDispatcher(req.getServletPath()).forward(req, res);
      }

      chain.doFilter(req, res);
  }
}


2. Insert Custom-Filter in the http-Configuration of Spring-Security

protected void configure(HttpSecurity http) throws Exception {
    super.configure(http);
    http
            .cors()
            .and()
            .csrf()
            .disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .sessionAuthenticationStrategy(sessionAuthenticationStrategy())
            .and()
            .addFilterAfter(CustomFilter(), CsrfFilter.class)
            .authorizeRequests()
            .anyRequest().permitAll();
}

Have a look at the default Filter-Chain after configuring Keycloak:

Filter-Chain

So it´s obvious to insert the Custom-Filter at position 5 to avoid the whole Keycloak-Magic.

I have used this workaround to defeat the method security and it´s @Secured-Annotation.

like image 66
Twelve Avatar answered Oct 02 '22 20:10

Twelve


For anyone who might have the same trouble, here is what I did.

I didn't disable Keycloak but I made a separate a Keycloak config file for testing purposes.

Here is my config file

@Profile("test")
@Configuration
@EnableWebSecurity
public class SecurityTestConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/**").permitAll();
        http.headers().frameOptions().disable();
        http.csrf().disable();

    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/**");
    }

    @Bean
    @Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public AccessToken accessToken() {
        AccessToken accessToken = new AccessToken();
        accessToken.setSubject("abc");
        accessToken.setName("Tester");

        return accessToken;

    }

}

Please note it is important to use this only in a test environment and therefore I have annotated the config as @Profile("test"). I have also added an AccessToken bean since some of the auditing features in my application depend on it.

like image 32
Charlie Avatar answered Oct 02 '22 19:10

Charlie