Summary

When using Spring's security with the Webflux framework, removing and adding users dynamically isn't straightforward.

Actual Behavior

MapReactiveUserDetailsService only has two public methods: find a user by name and update a user's password. These are defined by its two parent interfaces, ReactiveUserDetailsService and ReactiveUserDetailsPasswordService.

Unless you use the MapReactiveUserDetailsService(Map<String, UserDetails> users) constructor and keep a reference to the original map, there is no way to update users dynamically. This workaround seems quite brittle and won't work when using one of the class's two other constructors.

Expected Behavior

MapReactiveUserDetailsService should provide methods to conveniently add and remove users at any point in time. Should these methods be defined in the ReactiveUserDetailsService interface itself?

Version

Latest 5.2.1.RELEASE.

Comment From: fhanik

For feature parity it would be reasonable to expect a ReactiveUserDetailsManager interface similar to its servlet counterpart

I agree that keeping a reference to the user map is not an ideal solution. One should not expect that the reference is the source of data inside the implementation, but rather the seed for the initial user set.

Would you be interested in contributing a PR?

Comment From: PyvesB

Would you be interested in contributing a PR?

Yes, I can give it a go!

Comment From: PyvesB

For feature parity it would be reasonable to expect a ReactiveUserDetailsManager interface similar to its servlet counterpart

Just to clarify, are you suggesting to create a new ReactiveUserDetailsManager interface and make MapReactiveUserDetailsService implement it? If we closely follow the servlet equivalents, the hierarchy could look like the following:

ReactiveUserDetailsService
                      \            ReactiveUserDetailsPasswordService
    ReactiveUserDetailsManager            /
                         \               / 
                   MapReactiveUserDetailsService

The issue with this approach is that MapReactiveUserDetailsService would be somewhat misnamed, it should ideally be called MapReactiveUserDetailsManager to be consistent with servlet implementations of UserDetailsManager (e.g. InMemoryUserDetailsManager, JdbcUserDetailsManager, LdapUserDetailsManager). It may need to change packages as well to keep all managers together (org.springframework.security.core.userdetails -> org.springframework.security.provisioning?). Renaming and/or moving would be a breaking change for users. Are such breaking changes acceptable or are we comfortable with the slight naming inconsistency introduced by the above graph?

Alternatively, we could keep the simpler and flatter structure we have today for reactive user detail classes:

ReactiveUserDetailsService       ReactiveUserDetailsPasswordService
                     \               / 
               MapReactiveUserDetailsService

The new methods to add and remove users could simply be added to the existing ReactiveUserDetailsService interface. I'm leaning towards this approach as it doesn't directly impact users and keeps Spring's internal code simpler.

Comment From: marcusdacoregio

Closed since there is no need yet for this feature. See https://github.com/spring-projects/spring-security/pull/7762#issuecomment-981591388