mirror of https://github.com/halo-dev/halo
Add support to disable two-factor authentication (#6242)
#### What type of PR is this? /kind improvement /area core /milestone 2.17.0 #### What this PR does / why we need it: This PR provides a configuration property to control whether two-factor authentication is disabled. e.g.: ```yaml halo: security: two-factor-auth: disabled: true | false # Default is false. ``` #### Which issue(s) this PR fixes: Fixes #5640 #### Special notes for your reviewer: 1. Enable 2FA and configure TOTP 2. Disable 2FA by configuring property above 3. Restart Halo and try to login #### Does this PR introduce a user-facing change? ```release-note 支持通过配置的方式全局禁用二步验证 ```pull/6279/head
parent
0b7b74e826
commit
cc3564bf82
|
@ -127,8 +127,12 @@ public class WebServerSecurityConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
DefaultUserDetailService userDetailsService(UserService userService,
|
DefaultUserDetailService userDetailsService(UserService userService,
|
||||||
RoleService roleService) {
|
RoleService roleService,
|
||||||
return new DefaultUserDetailService(userService, roleService);
|
HaloProperties haloProperties) {
|
||||||
|
var userDetailService = new DefaultUserDetailService(userService, roleService);
|
||||||
|
var twoFactorAuthDisabled = haloProperties.getSecurity().getTwoFactorAuth().isDisabled();
|
||||||
|
userDetailService.setTwoFactorAuthDisabled(twoFactorAuthDisabled);
|
||||||
|
return userDetailService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
@ -16,6 +16,18 @@ public class SecurityProperties {
|
||||||
|
|
||||||
private final RememberMeOptions rememberMe = new RememberMeOptions();
|
private final RememberMeOptions rememberMe = new RememberMeOptions();
|
||||||
|
|
||||||
|
private final TwoFactorAuthOptions twoFactorAuth = new TwoFactorAuthOptions();
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class TwoFactorAuthOptions {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether two-factor authentication is disabled.
|
||||||
|
*/
|
||||||
|
private boolean disabled;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class FrameOptions {
|
public static class FrameOptions {
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import static run.halo.app.security.authorization.AuthorityUtils.ANONYMOUS_ROLE_
|
||||||
import static run.halo.app.security.authorization.AuthorityUtils.AUTHENTICATED_ROLE_NAME;
|
import static run.halo.app.security.authorization.AuthorityUtils.AUTHENTICATED_ROLE_NAME;
|
||||||
import static run.halo.app.security.authorization.AuthorityUtils.ROLE_PREFIX;
|
import static run.halo.app.security.authorization.AuthorityUtils.ROLE_PREFIX;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService;
|
import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService;
|
||||||
|
@ -31,6 +32,12 @@ public class DefaultUserDetailService
|
||||||
|
|
||||||
private final RoleService roleService;
|
private final RoleService roleService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether two-factor authentication is disabled.
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
private boolean twoFactorAuthDisabled;
|
||||||
|
|
||||||
public DefaultUserDetailService(UserService userService, RoleService roleService) {
|
public DefaultUserDetailService(UserService userService, RoleService roleService) {
|
||||||
this.userService = userService;
|
this.userService = userService;
|
||||||
this.roleService = roleService;
|
this.roleService = roleService;
|
||||||
|
@ -66,7 +73,9 @@ public class DefaultUserDetailService
|
||||||
return setAuthorities.then(Mono.fromSupplier(() -> {
|
return setAuthorities.then(Mono.fromSupplier(() -> {
|
||||||
var twoFactorAuthSettings = TwoFactorUtils.getTwoFactorAuthSettings(user);
|
var twoFactorAuthSettings = TwoFactorUtils.getTwoFactorAuthSettings(user);
|
||||||
return new HaloUser.Builder(userBuilder.build())
|
return new HaloUser.Builder(userBuilder.build())
|
||||||
.twoFactorAuthEnabled(twoFactorAuthSettings.isAvailable())
|
.twoFactorAuthEnabled(
|
||||||
|
(!twoFactorAuthDisabled) && twoFactorAuthSettings.isAvailable()
|
||||||
|
)
|
||||||
.totpEncryptedSecret(user.getSpec().getTotpEncryptedSecret())
|
.totpEncryptedSecret(user.getSpec().getTotpEncryptedSecret())
|
||||||
.build();
|
.build();
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -156,11 +156,27 @@ class DefaultUserDetailServiceTest {
|
||||||
.verifyComplete();
|
.verifyComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldFindHaloUserDetailsWith2faDisabledWhen2faDisabledGlobally() {
|
||||||
|
userDetailService.setTwoFactorAuthDisabled(true);
|
||||||
|
var fakeUser = createFakeUser();
|
||||||
|
fakeUser.getSpec().setTwoFactorAuthEnabled(true);
|
||||||
|
fakeUser.getSpec().setTotpEncryptedSecret("fake-totp-encrypted-secret");
|
||||||
|
when(userService.getUser("faker")).thenReturn(Mono.just(fakeUser));
|
||||||
|
when(roleService.listRoleRefs(any())).thenReturn(Flux.empty());
|
||||||
|
userDetailService.findByUsername("faker")
|
||||||
|
.as(StepVerifier::create)
|
||||||
|
.assertNext(userDetails -> {
|
||||||
|
assertInstanceOf(HaloUserDetails.class, userDetails);
|
||||||
|
assertFalse(((HaloUserDetails) userDetails).isTwoFactorAuthEnabled());
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldFindUserDetailsByExistingUsernameButKindOfRoleRefIsNotRole() {
|
void shouldFindUserDetailsByExistingUsernameButKindOfRoleRefIsNotRole() {
|
||||||
var foundUser = createFakeUser();
|
var foundUser = createFakeUser();
|
||||||
|
|
||||||
var roleGvk = new Role().groupVersionKind();
|
|
||||||
var roleRef = new RoleRef();
|
var roleRef = new RoleRef();
|
||||||
roleRef.setKind("FakeRole");
|
roleRef.setKind("FakeRole");
|
||||||
roleRef.setApiGroup("fake.halo.run");
|
roleRef.setApiGroup("fake.halo.run");
|
||||||
|
|
Loading…
Reference in New Issue