Move username-password authentication into security filter chain (#5348)

#### What type of PR is this?

/kind cleanup
/area core
/milestone 2.13.x

#### What this PR does / why we need it:

UsernamePasswordAuthenticator is a normal webfilter instead of authentication webfilter in security filter chain. There does not guarentee expected results due to different in execution order. So this PR changes UsernamePasswordAuthenticator to AuthenticationWebFilter for managing the filter by security filter chain.

By the way, these changes will not affect any plugins.

#### Does this PR introduce a user-facing change?

```release-note
None
```
pull/5369/head^2
John Niang 2024-02-18 16:46:15 +08:00 committed by GitHub
parent 94a51aba4f
commit 8156d9da8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 19 additions and 39 deletions

View File

@ -2,14 +2,13 @@ package run.halo.app.security.authentication.login;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.micrometer.observation.ObservationRegistry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpMethod;
import org.springframework.lang.NonNull;
import org.springframework.security.authentication.ObservationReactiveAuthenticationManager;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
@ -18,21 +17,11 @@ import org.springframework.security.web.server.context.ServerSecurityContextRepo
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
import run.halo.app.plugin.extensionpoint.ExtensionGetter;
import run.halo.app.security.AdditionalWebFilter;
import run.halo.app.security.authentication.SecurityConfigurer;
/**
* Authentication filter for username and password.
*
* @author guqing
* @since 2.4.0
*/
@Slf4j
@Component
public class UsernamePasswordAuthenticator implements AdditionalWebFilter {
public class LoginSecurityConfigurer implements SecurityConfigurer {
private final ObservationRegistry observationRegistry;
@ -46,16 +35,17 @@ public class UsernamePasswordAuthenticator implements AdditionalWebFilter {
private final CryptoService cryptoService;
private final AuthenticationWebFilter authenticationWebFilter;
private final ExtensionGetter extensionGetter;
private final ServerResponse.Context context;
private final MessageSource messageSource;
private final RateLimiterRegistry rateLimiterRegistry;
public UsernamePasswordAuthenticator(ServerResponse.Context context,
ObservationRegistry observationRegistry, ReactiveUserDetailsService userDetailsService,
public LoginSecurityConfigurer(ObservationRegistry observationRegistry,
ReactiveUserDetailsService userDetailsService,
ReactiveUserDetailsPasswordService passwordService, PasswordEncoder passwordEncoder,
ServerSecurityContextRepository securityContextRepository, CryptoService cryptoService,
RateLimiterRegistry rateLimiterRegistry, MessageSource messageSource,
ExtensionGetter extensionGetter) {
ExtensionGetter extensionGetter, ServerResponse.Context context,
MessageSource messageSource, RateLimiterRegistry rateLimiterRegistry) {
this.observationRegistry = observationRegistry;
this.userDetailsService = userDetailsService;
this.passwordService = passwordService;
@ -63,27 +53,14 @@ public class UsernamePasswordAuthenticator implements AdditionalWebFilter {
this.securityContextRepository = securityContextRepository;
this.cryptoService = cryptoService;
this.extensionGetter = extensionGetter;
this.authenticationWebFilter = new AuthenticationWebFilter(authenticationManager());
configureAuthenticationWebFilter(this.authenticationWebFilter, context, messageSource,
rateLimiterRegistry);
this.context = context;
this.messageSource = messageSource;
this.rateLimiterRegistry = rateLimiterRegistry;
}
@Override
@NonNull
public Mono<Void> filter(@NonNull ServerWebExchange exchange, @NonNull WebFilterChain chain) {
return authenticationWebFilter.filter(exchange, chain);
}
@Override
public int getOrder() {
return SecurityWebFiltersOrder.FORM_LOGIN.getOrder();
}
void configureAuthenticationWebFilter(AuthenticationWebFilter filter,
ServerResponse.Context context,
MessageSource messageSource,
RateLimiterRegistry rateLimiterRegistry) {
public void configure(ServerHttpSecurity http) {
var filter = new AuthenticationWebFilter(authenticationManager());
var requiresMatcher = ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, "/login");
var handler = new UsernamePasswordHandler(context, messageSource);
var authConverter = new LoginAuthenticationConverter(cryptoService, rateLimiterRegistry);
@ -92,6 +69,8 @@ public class UsernamePasswordAuthenticator implements AdditionalWebFilter {
filter.setAuthenticationSuccessHandler(handler);
filter.setServerAuthenticationConverter(authConverter);
filter.setSecurityContextRepository(securityContextRepository);
http.addFilterAt(filter, SecurityWebFiltersOrder.FORM_LOGIN);
}
ReactiveAuthenticationManager authenticationManager() {
@ -106,5 +85,4 @@ public class UsernamePasswordAuthenticator implements AdditionalWebFilter {
manager.setUserDetailsPasswordService(passwordService);
return manager;
}
}

View File

@ -1,9 +1,11 @@
# TODO Remove the username-password-authenticator in the future.
apiVersion: plugin.halo.run/v1alpha1
kind: ExtensionDefinition
metadata:
name: username-password-authenticator
labels:
auth.halo.run/extension-point-name: "additional-webfilter"
deletionTimestamp: 2024-02-18T08:27:41.257531Z
spec:
className: run.halo.app.security.authentication.login.UsernamePasswordAuthenticator
extensionPointName: additional-webfilter