Improvements for 2FA
This commit is contained in:
parent
67e969fd75
commit
eeb7dc2338
@ -258,9 +258,9 @@ public class TwoFaConfigController extends BaseController {
|
||||
ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
|
||||
@PostMapping("/settings")
|
||||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
|
||||
public void savePlatformTwoFaSettings(@ApiParam(value = "Settings value", required = true)
|
||||
public PlatformTwoFaSettings savePlatformTwoFaSettings(@ApiParam(value = "Settings value", required = true)
|
||||
@RequestBody PlatformTwoFaSettings twoFaSettings) throws ThingsboardException {
|
||||
twoFaConfigManager.savePlatformTwoFaSettings(getTenantId(), twoFaSettings);
|
||||
return twoFaConfigManager.savePlatformTwoFaSettings(getTenantId(), twoFaSettings);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -99,6 +99,9 @@ public class DefaultTwoFaConfigManager implements TwoFaConfigManager {
|
||||
return newSettings;
|
||||
});
|
||||
Map<TwoFaProviderType, TwoFaAccountConfig> configs = settings.getConfigs();
|
||||
if (configs.isEmpty() && accountConfig.getProviderType() == TwoFaProviderType.BACKUP_CODE) {
|
||||
throw new IllegalArgumentException("To use 2FA backup codes you first need to configure at least one provider");
|
||||
}
|
||||
if (accountConfig.isUseByDefault()) {
|
||||
configs.values().forEach(config -> config.setUseByDefault(false));
|
||||
}
|
||||
@ -114,7 +117,11 @@ public class DefaultTwoFaConfigManager implements TwoFaConfigManager {
|
||||
AccountTwoFaSettings settings = getAccountTwoFaSettings(tenantId, userId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("2FA not configured"));
|
||||
settings.getConfigs().remove(providerType);
|
||||
if (!settings.getConfigs().isEmpty() && settings.getConfigs().values().stream().noneMatch(TwoFaAccountConfig::isUseByDefault)) {
|
||||
if (settings.getConfigs().size() == 1) {
|
||||
settings.getConfigs().remove(TwoFaProviderType.BACKUP_CODE);
|
||||
}
|
||||
if (!settings.getConfigs().isEmpty() && settings.getConfigs().values().stream()
|
||||
.noneMatch(TwoFaAccountConfig::isUseByDefault)) {
|
||||
settings.getConfigs().values().stream()
|
||||
.min(Comparator.comparing(TwoFaAccountConfig::getProviderType))
|
||||
.ifPresent(config -> config.setUseByDefault(true));
|
||||
@ -135,7 +142,7 @@ public class DefaultTwoFaConfigManager implements TwoFaConfigManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void savePlatformTwoFaSettings(TenantId tenantId, PlatformTwoFaSettings twoFactorAuthSettings) throws ThingsboardException {
|
||||
public PlatformTwoFaSettings savePlatformTwoFaSettings(TenantId tenantId, PlatformTwoFaSettings twoFactorAuthSettings) throws ThingsboardException {
|
||||
ConstraintValidator.validateFields(twoFactorAuthSettings);
|
||||
for (TwoFaProviderConfig providerConfig : twoFactorAuthSettings.getProviders()) {
|
||||
twoFactorAuthService.checkProvider(tenantId, providerConfig.getProviderType());
|
||||
@ -149,6 +156,7 @@ public class DefaultTwoFaConfigManager implements TwoFaConfigManager {
|
||||
});
|
||||
settings.setJsonValue(JacksonUtil.valueToTree(twoFactorAuthSettings));
|
||||
adminSettingsService.saveAdminSettings(tenantId, settings);
|
||||
return twoFactorAuthSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -39,7 +39,7 @@ public interface TwoFaConfigManager {
|
||||
|
||||
Optional<PlatformTwoFaSettings> getPlatformTwoFaSettings(TenantId tenantId, boolean sysadminSettingsAsDefault);
|
||||
|
||||
void savePlatformTwoFaSettings(TenantId tenantId, PlatformTwoFaSettings twoFactorAuthSettings) throws ThingsboardException;
|
||||
PlatformTwoFaSettings savePlatformTwoFaSettings(TenantId tenantId, PlatformTwoFaSettings twoFactorAuthSettings) throws ThingsboardException;
|
||||
|
||||
void deletePlatformTwoFaSettings(TenantId tenantId);
|
||||
|
||||
|
||||
@ -55,7 +55,9 @@ public class RestAwareAuthenticationSuccessHandler implements AuthenticationSucc
|
||||
|
||||
if (authentication instanceof MfaAuthenticationToken) {
|
||||
int preVerificationTokenLifetime = twoFaConfigManager.getPlatformTwoFaSettings(securityUser.getTenantId(), true)
|
||||
.flatMap(settings -> Optional.ofNullable(settings.getTotalAllowedTimeForVerification())).orElse((int) TimeUnit.MINUTES.toSeconds(30));
|
||||
.flatMap(settings -> Optional.ofNullable(settings.getTotalAllowedTimeForVerification())
|
||||
.filter(time -> time > 0))
|
||||
.orElse((int) TimeUnit.MINUTES.toSeconds(30));
|
||||
tokenPair.setToken(tokenFactory.createPreVerificationToken(securityUser, preVerificationTokenLifetime).getToken());
|
||||
tokenPair.setRefreshToken(null);
|
||||
tokenPair.setScope(Authority.PRE_VERIFICATION_TOKEN);
|
||||
|
||||
@ -172,11 +172,12 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
|
||||
return;
|
||||
}
|
||||
|
||||
if (twoFaSettings.getMaxVerificationFailuresBeforeUserLockout() > 0
|
||||
&& failedVerificationAttempts >= twoFaSettings.getMaxVerificationFailuresBeforeUserLockout()) {
|
||||
Integer maxVerificationFailures = twoFaSettings.getMaxVerificationFailuresBeforeUserLockout();
|
||||
if (maxVerificationFailures != null && maxVerificationFailures > 0
|
||||
&& failedVerificationAttempts >= maxVerificationFailures) {
|
||||
userService.setUserCredentialsEnabled(TenantId.SYS_TENANT_ID, userId, false);
|
||||
SecuritySettings securitySettings = self.getSecuritySettings(tenantId);
|
||||
lockAccount(userId, securityUser.getEmail(), securitySettings.getUserLockoutNotificationEmail(), twoFaSettings.getMaxVerificationFailuresBeforeUserLockout());
|
||||
lockAccount(userId, securityUser.getEmail(), securitySettings.getUserLockoutNotificationEmail(), maxVerificationFailures);
|
||||
throw new LockedException("User account was locked due to exceeded 2FA verification attempts");
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ public class PlatformTwoFaSettings {
|
||||
@Pattern(regexp = "[1-9]\\d*:[1-9]\\d*", message = "verification code check rate limit configuration is invalid")
|
||||
private String verificationCodeCheckRateLimit;
|
||||
@Min(value = 0, message = "maximum number of verification failure before user lockout must be positive")
|
||||
private int maxVerificationFailuresBeforeUserLockout;
|
||||
private Integer maxVerificationFailuresBeforeUserLockout;
|
||||
@Min(value = 1, message = "total amount of time allotted for verification must be greater than 0")
|
||||
private Integer totalAllowedTimeForVerification;
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ import javax.validation.constraints.Min;
|
||||
@Data
|
||||
public class BackupCodeTwoFaProviderConfig implements TwoFaProviderConfig {
|
||||
|
||||
@Min(0)
|
||||
@Min(1)
|
||||
private int codesQuantity;
|
||||
|
||||
@Override
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user