Skip to content

Commit

Permalink
Filter MFAuthentication when obtaining current user detail
Browse files Browse the repository at this point in the history
Signed-off-by: John Niang <[email protected]>
  • Loading branch information
JohnNiang committed Jan 14, 2024
1 parent bbbd0c0 commit e85ef55
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -542,10 +544,11 @@ record ChangePasswordRequest(
@NonNull
Mono<ServerResponse> 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package run.halo.app.security.authentication.mfa;

public interface TwoFactorAuthService {
public interface TotpAuthService {

boolean validateTotp(String rawSecret, int code);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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
Expand All @@ -99,8 +99,8 @@ public Mono<Authentication> 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));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -169,7 +169,7 @@ private Mono<ServerResponse> 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)
Expand Down Expand Up @@ -218,11 +218,11 @@ private Mono<ServerResponse> 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);
Expand Down

0 comments on commit e85ef55

Please sign in to comment.