Lazy initialise spring security at runtime + reload spring security configuration

Viewed 856

Spring usually eagerly loading the spring security configuration while starting the application. I'm using OAuth with Spring Security

I'm maintaining a configuration table for storing the SSO related values (like jwk-url, client_id, client_secret). This values will be populated by an admin user via CRUD in the same spring boot application.

Then only the jwk-url is available to be configure in the Spring security configuration (refer below code - jwkSetUri(...)). This would not available at the application startup.

So I wanted to initialise the spring security configuration after the value is loaded into the table, like a lazy loading (@Lazy) at runtime. I know how to do Lazy loading of a regular class/service.

  1. But still I'm not sure how to invoke the configure(HttpSecurity http) method at runtime and how to p ass the HttpSecurity parameter. When I just try invoke new ResourceServerConfiguration() like a lazy loading at runtime, I don't see the configure() method is called. (Or) this class needs to be maintained as bean and lazy load whenever needed. But still not sure about how to call configure() in code.

  2. Another thing is how to refresh/reload the spring security configuration at runtime, if the JWK url is changed by admin. Then only the spring security configuration can take effect of the changes.

@Configuration
@EnableWebSecurity
public class ResourceServerConfiguration extends WebSecurityConfigurerAdapter {
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.cors()
                .and()
                .csrf().disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .oauth2ResourceServer()
                .authenticationEntryPoint(oAuth2AuthenticationEntryPoint)
                .accessDeniedHandler(oAuth2AccessDeniedHandler)
                .jwt()
                 // Some Auth server URL which would be fetch from table
                .jwkSetUri(ssoConfigService.getActiveSSOCertificateURL()); 
                 // Eg. http://localhost:8090/auth/realms/demo-app/protocol/openid-connect/certs
    }
}

I have already referred these links. But it doesn't help for my purpose. Any help would be appreciated.

How do I lazy load Spring Security?

How to reload the Configure method of WebSecurityConfigurerAdapter when the application is up and running

Modify Spring Security Config at Runtime

Configure Spring HTTP Security at Runtime

1 Answers

Please, check this link Customizing CORS Filtering at Runtime that include a similar use case related to your but for him, he needed to change allowed origins dynamically. They decide to create a new filter and simple extends OncePerRequestFilter.

Take in account to check the OAuth2ResourceServerProperties for your use case.

UPDATING: Try with this code for this scenario:

Another thing is how to refresh/reload the spring security configuration at runtime, if the JWK url is changed by admin. Then only the spring security configuration can take effect of the changes.

 @Override
    public void configure(HttpSecurity http) throws Exception {
        http.cors()
                .and()
                .csrf().disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .anyRequest().authenticated()

                // TODO: test with and without this and check if work for you
                .and()
                .oauth2ResourceServer()
                .authenticationEntryPoint(oAuth2AuthenticationEntryPoint)
                .accessDeniedHandler(oAuth2AccessDeniedHandler)
                .jwt()
                // Some Auth server URL which would be fetch from table
                .jwkSetUri(ssoConfigService.getActiveSSOCertificateURL());
        // Eg. http://localhost:8090/auth/realms/demo-app/protocol/openid-connect/certs

        http.addFilterBefore(new OncePerRequestFilter() {
            // Every time a request occur, this method will be called.
            @Override
            protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {

                try {
                    http.oauth2ResourceServer()
                            .authenticationEntryPoint(oAuth2AuthenticationEntryPoint)
                            .accessDeniedHandler(oAuth2AccessDeniedHandler)
                            .jwt()
                            // Some Auth server URL which would be fetch from table
                            .jwkSetUri(ssoConfigService.getActiveSSOCertificateURL());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, BasicAuthenticationFilter.class);
    }

I hope this info can help you.

Related