Skip to content

Commit

Permalink
Move username-password authentication into security filter chain (#5348)
Browse files Browse the repository at this point in the history
#### 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
```
  • Loading branch information
JohnNiang committed Feb 18, 2024
1 parent 94a51ab commit 8156d9d
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

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;
Expand All @@ -18,21 +17,11 @@
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;

Expand All @@ -46,44 +35,32 @@ 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;
this.passwordEncoder = passwordEncoder;
this.securityContextRepository = securityContextRepository;
this.cryptoService = cryptoService;
this.extensionGetter = extensionGetter;

this.authenticationWebFilter = new AuthenticationWebFilter(authenticationManager());
configureAuthenticationWebFilter(this.authenticationWebFilter, context, messageSource,
rateLimiterRegistry);
}

@Override
@NonNull
public Mono<Void> filter(@NonNull ServerWebExchange exchange, @NonNull WebFilterChain chain) {
return authenticationWebFilter.filter(exchange, chain);
this.context = context;
this.messageSource = messageSource;
this.rateLimiterRegistry = rateLimiterRegistry;
}

@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);
Expand All @@ -92,6 +69,8 @@ void configureAuthenticationWebFilter(AuthenticationWebFilter filter,
filter.setAuthenticationSuccessHandler(handler);
filter.setServerAuthenticationConverter(authConverter);
filter.setSecurityContextRepository(securityContextRepository);

http.addFilterAt(filter, SecurityWebFiltersOrder.FORM_LOGIN);
}

ReactiveAuthenticationManager authenticationManager() {
Expand All @@ -106,5 +85,4 @@ ReactiveAuthenticationManager defaultAuthenticationManager() {
manager.setUserDetailsPasswordService(passwordService);
return manager;
}

}
Original file line number Diff line number Diff line change
@@ -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
Expand Down

0 comments on commit 8156d9d

Please sign in to comment.