简体   繁体   中英

Spring RefreshableKeycloakSecurityContext Leak Memory

I am developing app in Spring Boot 2.0.3. Application after time has memory leak due to RefreshableKeycloakSecurityContext when a lot of REST requests with token are sent to it. Photo at the button of the post describe it.

keycloak dependencies:

    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-spring-boot-2-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-admin-client</artifactId>
        <version>3.4.0.Final</version>
        <type>jar</type>
    </dependency>
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-server-spi</artifactId>
        <version>3.4.3.Final</version>
        <type>jar</type>
    </dependency>
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-events-api</artifactId>
        <version>1.0.2.Final</version>
        <type>jar</type>
    </dependency>

SecurityConfig:

     public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        try {
            KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
            keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
            auth.authenticationProvider(keycloakAuthenticationProvider);
        }catch(Exception ex){
            log.error(ex);
        }
    }

    @Bean
    public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

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

    @Override
    protected void configure(HttpSecurity http) {
        try {
            super.configure(http);
            http
                    .cors()
                    .configurationSource(corsConfigurationSource())
                    .and()
                    .authorizeRequests()
                    .antMatchers("/api/public/**")
                    .permitAll();
                    http.csrf().disable();
        }catch (Exception ex){
            throw new RuntimeException("Problem podczas uprawnien " + ex);
        }

    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("Access-Control-Allow-Origin","Origin","Accept,X-Requested-With","Content-Type","Access-Control-Request-Method","Access-Control-Request-Headers","Authorization"));
        configuration.setMaxAge((long)1);
        configuration.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

}

Memory leak image

Could anybody help how to resolve this problem ?

The problem is in SecurityConfig class. You use:

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

inside this class you can see:

public class RegisterSessionAuthenticationStrategy implements SessionAuthenticationStrategy {
private final SessionRegistry sessionRegistry;

public RegisterSessionAuthenticationStrategy(SessionRegistry sessionRegistry) {
    Assert.notNull(sessionRegistry, "The sessionRegistry cannot be null");
    this.sessionRegistry = sessionRegistry;
}

public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
    this.sessionRegistry.registerNewSession(request.getSession().getId(), authentication.getPrincipal());
}

}

the code:

public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
    this.sessionRegistry.registerNewSession(request.getSession().getId(), authentication.getPrincipal());
}

causes your problem. All yours rests creates sessions that are remembered by the spring. To avoid this, you should use:

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

replace RegisterSessionAuthenticationStrategy with NullAuthenticatedSessionStrategy in SecurityConfig class.

After this move, your application will no longer remember the session. (Check memory dump after and before).

More information is here: https://github.com/dynamind/grails3-spring-security-keycloak-minimal/blob/master/README.md

I've never used Keycloak, and although you are not directly instantiating a RefreshableKeycloakSecurityContext, maybe any of the classes you are continuously allocating with new() such as KeycloakSpringBootConfigResolver is instantiating it each time.

In this situation, if you are not cleaning up all the references pointing to the object, they won't be Garbage collected.. and you will have a memory leak.

Did you try already with a memory analysis tool? Let me recommend you Eclipse MAT, you should be able to take a heap dump of your application and generate a memory leak report. You can also check the dominator tree to see who's keeping the reference to the leaked memory.

https://eclipsesource.com/blogs/2013/01/21/10-tips-for-using-the-eclipse-memory-analyzer/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM