Expected Behavior

Using an ObjectPostProcessor should be as easy as possible, in order to allow less verbose and error-prone overrides or additional configuration of framework-provided components. Ideally, it would be possible with a lambda expression.

Given:

OAuth2AuthorizationServerConfigurer<HttpSecurity> configurer =
    new OAuth2AuthorizationServerConfigurer<>(); // extends AbstractHttpConfigurer

Perhaps we could provide a lambda expression with the target type in the signature. For example:

configurer
    .postProcess((OAuth2AuthorizationCodeRequestAuthenticationProvider authenticationProvider) ->
        authenticationProvider.setAuthenticationValidatorResolver(createDefaultAuthenticationValidatorResolver()));

Or the alternate syntax of specifying the target type in angle brackets:

configurer
    .<OAuth2AuthorizationCodeRequestAuthenticationProvider>postProcess(authenticationProvider ->
        authenticationProvider.setAuthenticationValidatorResolver(createDefaultAuthenticationValidatorResolver()));

Another option could be to specify the type of the object as a class:

configurer
    .postProcess(OAuth2AuthorizationCodeRequestAuthenticationProvider.class, authenticationProvider ->
        authenticationProvider.setAuthenticationValidatorResolver(createDefaultAuthenticationValidatorResolver()));

Current Behavior

Defining an ObjectPostProcessor cannot be done via a lambda expression, and requires a complex anonymous class. For example:

configurer.withObjectPostProcessor(new ObjectPostProcessor<OAuth2AuthorizationCodeRequestAuthenticationProvider>() {
    @Override
    public <O extends OAuth2AuthorizationCodeRequestAuthenticationProvider> O postProcess(O object) {
        object.setAuthenticationValidatorResolver(createDefaultAuthenticationValidatorResolver());
        return object;
    }
});

However, the typical way is to override a component by re-defining the entire component. If it has dependencies also used by the framework, this further requires exposing things as beans that might have been defaulted. In Spring Authorization Server, this would be components such as OAuth2AuthorizationService and OAuth2AuthorizationConsentService, but there are many more such examples.

Context

Attempting to configure non-trivial components such as AuthenticationProviders and AuthenticationConverters to build new features on top of the framework could be made easier without providing every scenario in a configurer.

Comment From: jgrandja

I think this is a great idea @sjohnr that will allow for easier configuration.

I wonder if there is time to introduce this into Spring Security's AbstractHttpConfigurer before we release 5.6.0-RC1? It seems like it would be a fairly straight forward addition?

Comment From: sjohnr

Absolutely! I'll look into that.

Comment From: jzheaux

FWIW, I have never found a lot of utility in the fact that I can return a completely new instance of the object. I believe that a contract that takes a Consumer (instead of a Function) would be sufficient.

Comment From: sjohnr

Based on discussion with the team, I'm going to close this for now. Instead, we'll focus on enhancements to the authorization server DSL.