From e85ef55b869de28c328192f17c5c73125c2aedeb Mon Sep 17 00:00:00 2001 From: John Niang Date: Sun, 14 Jan 2024 14:58:25 +0800 Subject: [PATCH] Filter MFAuthentication when obtaining current user detail Signed-off-by: John Niang --- .../app/core/extension/endpoint/UserEndpoint.java | 11 +++++++---- ...uthService.java => DefaultTotpAuthService.java} | 8 ++++---- .../authentication/mfa/MfaSecurityConfigurer.java | 8 ++++---- ...FactorAuthService.java => TotpAuthService.java} | 2 +- .../mfa/TotpAuthenticationFilter.java | 14 +++++++------- .../authentication/mfa/TwoFactorAuthEndpoint.java | 12 ++++++------ 6 files changed, 29 insertions(+), 26 deletions(-) rename application/src/main/java/run/halo/app/security/authentication/mfa/{DefaultTwoFactorAuthService.java => DefaultTotpAuthService.java} (94%) rename application/src/main/java/run/halo/app/security/authentication/mfa/{TwoFactorAuthService.java => TotpAuthService.java} (85%) diff --git a/application/src/main/java/run/halo/app/core/extension/endpoint/UserEndpoint.java b/application/src/main/java/run/halo/app/core/extension/endpoint/UserEndpoint.java index 50564c6a0f2..63532b9b854 100644 --- a/application/src/main/java/run/halo/app/core/extension/endpoint/UserEndpoint.java +++ b/application/src/main/java/run/halo/app/core/extension/endpoint/UserEndpoint.java @@ -82,11 +82,13 @@ import run.halo.app.extension.MetadataUtil; import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.extension.router.IListRequest; +import run.halo.app.infra.AnonymousUserConst; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.SystemSetting; import run.halo.app.infra.ValidationUtils; import run.halo.app.infra.exception.RateLimitExceededException; import run.halo.app.infra.utils.JsonUtils; +import run.halo.app.security.authentication.mfa.MfaAuthentication; @Component @RequiredArgsConstructor @@ -542,10 +544,11 @@ record ChangePasswordRequest( @NonNull Mono me(ServerRequest request) { return ReactiveSecurityContextHolder.getContext() - .flatMap(ctx -> { - var name = ctx.getAuthentication().getName(); - return userService.getUser(name); - }) + .map(SecurityContext::getAuthentication) + .filter(obj -> !(obj instanceof MfaAuthentication)) + .map(Authentication::getName) + .defaultIfEmpty(AnonymousUserConst.PRINCIPAL) + .flatMap(userService::getUser) .flatMap(this::toDetailedUser) .flatMap(user -> ServerResponse.ok() .contentType(MediaType.APPLICATION_JSON) diff --git a/application/src/main/java/run/halo/app/security/authentication/mfa/DefaultTwoFactorAuthService.java b/application/src/main/java/run/halo/app/security/authentication/mfa/DefaultTotpAuthService.java similarity index 94% rename from application/src/main/java/run/halo/app/security/authentication/mfa/DefaultTwoFactorAuthService.java rename to application/src/main/java/run/halo/app/security/authentication/mfa/DefaultTotpAuthService.java index 3d2d333d576..48292c5099f 100644 --- a/application/src/main/java/run/halo/app/security/authentication/mfa/DefaultTwoFactorAuthService.java +++ b/application/src/main/java/run/halo/app/security/authentication/mfa/DefaultTotpAuthService.java @@ -27,17 +27,17 @@ @Slf4j @Component -public class DefaultTwoFactorAuthService implements TwoFactorAuthService { +public class DefaultTotpAuthService implements TotpAuthService { private final BytesEncryptor encryptor; - public DefaultTwoFactorAuthService(HaloProperties haloProperties) { + public DefaultTotpAuthService(HaloProperties haloProperties) { // init secret key var keysRoot = haloProperties.getWorkDir().resolve("keys"); - this.encryptor = createEncryptor(keysRoot); + this.encryptor = loadOrCreateEncryptor(keysRoot); } - private BytesEncryptor createEncryptor(Path keysRoot) { + private BytesEncryptor loadOrCreateEncryptor(Path keysRoot) { try { if (Files.notExists(keysRoot)) { Files.createDirectories(keysRoot); diff --git a/application/src/main/java/run/halo/app/security/authentication/mfa/MfaSecurityConfigurer.java b/application/src/main/java/run/halo/app/security/authentication/mfa/MfaSecurityConfigurer.java index 9240664fab5..d8d64468d65 100644 --- a/application/src/main/java/run/halo/app/security/authentication/mfa/MfaSecurityConfigurer.java +++ b/application/src/main/java/run/halo/app/security/authentication/mfa/MfaSecurityConfigurer.java @@ -10,18 +10,18 @@ public class MfaSecurityConfigurer implements SecurityConfigurer { private final ServerSecurityContextRepository securityContextRepository; - private final TwoFactorAuthService twoFactorAuthService; + private final TotpAuthService totpAuthService; public MfaSecurityConfigurer(ServerSecurityContextRepository securityContextRepository, - TwoFactorAuthService twoFactorAuthService) { + TotpAuthService totpAuthService) { this.securityContextRepository = securityContextRepository; - this.twoFactorAuthService = twoFactorAuthService; + this.totpAuthService = totpAuthService; } @Override public void configure(ServerHttpSecurity http) { http.addFilterAfter(new TotpAuthenticationFilter(securityContextRepository, - twoFactorAuthService), SecurityWebFiltersOrder.AUTHENTICATION); + totpAuthService), SecurityWebFiltersOrder.AUTHENTICATION); } } diff --git a/application/src/main/java/run/halo/app/security/authentication/mfa/TwoFactorAuthService.java b/application/src/main/java/run/halo/app/security/authentication/mfa/TotpAuthService.java similarity index 85% rename from application/src/main/java/run/halo/app/security/authentication/mfa/TwoFactorAuthService.java rename to application/src/main/java/run/halo/app/security/authentication/mfa/TotpAuthService.java index cad756a65d7..3fb4e17c387 100644 --- a/application/src/main/java/run/halo/app/security/authentication/mfa/TwoFactorAuthService.java +++ b/application/src/main/java/run/halo/app/security/authentication/mfa/TotpAuthService.java @@ -1,6 +1,6 @@ package run.halo.app.security.authentication.mfa; -public interface TwoFactorAuthService { +public interface TotpAuthService { boolean validateTotp(String rawSecret, int code); diff --git a/application/src/main/java/run/halo/app/security/authentication/mfa/TotpAuthenticationFilter.java b/application/src/main/java/run/halo/app/security/authentication/mfa/TotpAuthenticationFilter.java index eca01e0cd45..ad5870abe5f 100644 --- a/application/src/main/java/run/halo/app/security/authentication/mfa/TotpAuthenticationFilter.java +++ b/application/src/main/java/run/halo/app/security/authentication/mfa/TotpAuthenticationFilter.java @@ -23,8 +23,8 @@ public class TotpAuthenticationFilter extends AuthenticationWebFilter { public TotpAuthenticationFilter(ServerSecurityContextRepository securityContextRepository, - TwoFactorAuthService twoFactorAuthService) { - super(new MfaAuthenticationManager(twoFactorAuthService)); + TotpAuthService totpAuthService) { + super(new MfaAuthenticationManager(totpAuthService)); setSecurityContextRepository(securityContextRepository); setRequiresAuthenticationMatcher(pathMatchers(HttpMethod.POST, "/login/mfa/totp")); setServerAuthenticationConverter(new TotpCodeAuthenticationConverter()); @@ -73,10 +73,10 @@ public MfaAuthenticationException(String msg) { private static class MfaAuthenticationManager implements ReactiveAuthenticationManager { - private final TwoFactorAuthService twoFactorAuthService; + private final TotpAuthService totpAuthService; - private MfaAuthenticationManager(TwoFactorAuthService twoFactorAuthService) { - this.twoFactorAuthService = twoFactorAuthService; + private MfaAuthenticationManager(TotpAuthService totpAuthService) { + this.totpAuthService = totpAuthService; } @Override @@ -99,8 +99,8 @@ public Mono authenticate(Authentication authentication) { if (StringUtils.isBlank(encryptedSecret)) { throw new MfaAuthenticationException("Empty secret configured"); } - var rawSecret = twoFactorAuthService.decryptSecret(encryptedSecret); - var validated = twoFactorAuthService.validateTotp(rawSecret, code); + var rawSecret = totpAuthService.decryptSecret(encryptedSecret); + var validated = totpAuthService.validateTotp(rawSecret, code); if (!validated) { throw (new MfaAuthenticationException("Invalid TOTP code" + code)); } diff --git a/application/src/main/java/run/halo/app/security/authentication/mfa/TwoFactorAuthEndpoint.java b/application/src/main/java/run/halo/app/security/authentication/mfa/TwoFactorAuthEndpoint.java index 247e17817ef..3634c0e3daf 100644 --- a/application/src/main/java/run/halo/app/security/authentication/mfa/TwoFactorAuthEndpoint.java +++ b/application/src/main/java/run/halo/app/security/authentication/mfa/TwoFactorAuthEndpoint.java @@ -39,7 +39,7 @@ public class TwoFactorAuthEndpoint implements CustomEndpoint { private final UserService userService; - private final TwoFactorAuthService twoFactorAuthService; + private final TotpAuthService totpAuthService; private final Validator validator; @@ -49,13 +49,13 @@ public class TwoFactorAuthEndpoint implements CustomEndpoint { public TwoFactorAuthEndpoint(ReactiveExtensionClient client, UserService userService, - TwoFactorAuthService twoFactorAuthService, + TotpAuthService totpAuthService, Validator validator, PasswordEncoder passwordEncoder, ExternalUrlSupplier externalUrl) { this.client = client; this.userService = userService; - this.twoFactorAuthService = twoFactorAuthService; + this.totpAuthService = totpAuthService; this.validator = validator; this.passwordEncoder = passwordEncoder; this.externalUrl = externalUrl; @@ -169,7 +169,7 @@ private Mono getTotpAuthLink(ServerRequest request) { var url = externalUrl.getURL(request.exchange().getRequest()); var authority = url.getAuthority(); var authKeyId = username + ":" + authority; - var rawSecret = twoFactorAuthService.generateTotpSecret(); + var rawSecret = totpAuthService.generateTotpSecret(); var authLink = UriComponentsBuilder.fromUriString("otpauth://totp") .path(authKeyId) .queryParam("secret", rawSecret) @@ -218,11 +218,11 @@ private Mono configureTotp(ServerRequest request) { } catch (NumberFormatException e) { throw new ServerWebInputException("Invalid code"); } - var validated = twoFactorAuthService.validateTotp(rawSecret, code); + var validated = totpAuthService.validateTotp(rawSecret, code); if (!validated) { throw new ServerWebInputException("Invalid secret or code"); } - var encryptedSecret = twoFactorAuthService.encryptSecret(rawSecret); + var encryptedSecret = totpAuthService.encryptSecret(rawSecret); user.getSpec().setTotpEncryptedSecret(encryptedSecret); }) .flatMap(client::update);