Ensure at least one 2FA account config is default

This commit is contained in:
Viacheslav Klimov 2022-05-09 11:45:21 +03:00
parent 2ff2cf7ad8
commit d3c23c914d
4 changed files with 19 additions and 19 deletions

View File

@ -50,7 +50,6 @@ import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE; import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
@ -191,20 +190,10 @@ public class TwoFaConfigController extends BaseController {
@RequestBody TwoFaAccountConfigUpdateRequest updateRequest) throws ThingsboardException { @RequestBody TwoFaAccountConfigUpdateRequest updateRequest) throws ThingsboardException {
SecurityUser user = getCurrentUser(); SecurityUser user = getCurrentUser();
AccountTwoFaSettings settings = twoFaConfigManager.getAccountTwoFaSettings(user.getTenantId(), user.getId()) TwoFaAccountConfig accountConfig = twoFaConfigManager.getTwoFaAccountConfig(user.getTenantId(), user.getId(), providerType)
.orElseThrow(() -> new IllegalArgumentException("No 2FA config found")); .orElseThrow(() -> new IllegalArgumentException("Config for " + providerType + " 2FA provider not found"));
Map<TwoFaProviderType, TwoFaAccountConfig> configs = settings.getConfigs();
TwoFaAccountConfig accountConfig;
if ((accountConfig = configs.get(providerType)) == null) {
throw new IllegalArgumentException("Config for " + providerType + " 2FA provider not found");
}
if (updateRequest.isUseByDefault()) {
configs.values().forEach(config -> config.setUseByDefault(false));
}
accountConfig.setUseByDefault(updateRequest.isUseByDefault()); accountConfig.setUseByDefault(updateRequest.isUseByDefault());
return twoFaConfigManager.saveTwoFaAccountConfig(user.getTenantId(), user.getId(), accountConfig);
return twoFaConfigManager.saveAccountTwoFaSettings(user.getTenantId(), user.getId(), settings);
} }
@ApiOperation(value = "Delete 2FA account config (deleteTwoFaAccountConfig)", notes = @ApiOperation(value = "Delete 2FA account config (deleteTwoFaAccountConfig)", notes =

View File

@ -38,11 +38,10 @@ import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.dao.user.UserAuthSettingsDao; import org.thingsboard.server.dao.user.UserAuthSettingsDao;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@ -68,8 +67,7 @@ public class DefaultTwoFaConfigManager implements TwoFaConfigManager {
}); });
} }
@Override protected AccountTwoFaSettings saveAccountTwoFaSettings(TenantId tenantId, UserId userId, AccountTwoFaSettings settings) {
public AccountTwoFaSettings saveAccountTwoFaSettings(TenantId tenantId, UserId userId, AccountTwoFaSettings settings) {
UserAuthSettings userAuthSettings = Optional.ofNullable(userAuthSettingsDao.findByUserId(userId)) UserAuthSettings userAuthSettings = Optional.ofNullable(userAuthSettingsDao.findByUserId(userId))
.orElseGet(() -> { .orElseGet(() -> {
UserAuthSettings newUserAuthSettings = new UserAuthSettings(); UserAuthSettings newUserAuthSettings = new UserAuthSettings();
@ -99,7 +97,13 @@ public class DefaultTwoFaConfigManager implements TwoFaConfigManager {
newSettings.setConfigs(new LinkedHashMap<>()); newSettings.setConfigs(new LinkedHashMap<>());
return newSettings; return newSettings;
}); });
if (accountConfig.isUseByDefault()) {
settings.getConfigs().values().forEach(config -> config.setUseByDefault(false));
}
settings.getConfigs().put(accountConfig.getProviderType(), accountConfig); settings.getConfigs().put(accountConfig.getProviderType(), accountConfig);
if (settings.getConfigs().values().stream().noneMatch(TwoFaAccountConfig::isUseByDefault)) {
settings.getConfigs().values().stream().findFirst().ifPresent(config -> config.setUseByDefault(true));
}
return saveAccountTwoFaSettings(tenantId, userId, settings); return saveAccountTwoFaSettings(tenantId, userId, settings);
} }
@ -108,6 +112,11 @@ public class DefaultTwoFaConfigManager implements TwoFaConfigManager {
AccountTwoFaSettings settings = getAccountTwoFaSettings(tenantId, userId) AccountTwoFaSettings settings = getAccountTwoFaSettings(tenantId, userId)
.orElseThrow(() -> new IllegalArgumentException("2FA not configured")); .orElseThrow(() -> new IllegalArgumentException("2FA not configured"));
settings.getConfigs().remove(providerType); settings.getConfigs().remove(providerType);
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));
}
return saveAccountTwoFaSettings(tenantId, userId, settings); return saveAccountTwoFaSettings(tenantId, userId, settings);
} }

View File

@ -28,7 +28,6 @@ public interface TwoFaConfigManager {
Optional<AccountTwoFaSettings> getAccountTwoFaSettings(TenantId tenantId, UserId userId); Optional<AccountTwoFaSettings> getAccountTwoFaSettings(TenantId tenantId, UserId userId);
AccountTwoFaSettings saveAccountTwoFaSettings(TenantId tenantId, UserId userId, AccountTwoFaSettings settings);
Optional<TwoFaAccountConfig> getTwoFaAccountConfig(TenantId tenantId, UserId userId, TwoFaProviderType providerType); Optional<TwoFaAccountConfig> getTwoFaAccountConfig(TenantId tenantId, UserId userId, TwoFaProviderType providerType);

View File

@ -303,6 +303,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
loginTenantAdmin(); loginTenantAdmin();
TotpTwoFaAccountConfig generatedTotpTwoFaAccountConfig = generateTotpTwoFaAccountConfig(totpTwoFaProviderConfig); TotpTwoFaAccountConfig generatedTotpTwoFaAccountConfig = generateTotpTwoFaAccountConfig(totpTwoFaProviderConfig);
generatedTotpTwoFaAccountConfig.setUseByDefault(true);
String secret = UriComponentsBuilder.fromUriString(generatedTotpTwoFaAccountConfig.getAuthUrl()).build() String secret = UriComponentsBuilder.fromUriString(generatedTotpTwoFaAccountConfig.getAuthUrl()).build()
.getQueryParams().getFirst("secret"); .getQueryParams().getFirst("secret");
@ -421,6 +422,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
SmsTwoFaAccountConfig smsTwoFaAccountConfig = new SmsTwoFaAccountConfig(); SmsTwoFaAccountConfig smsTwoFaAccountConfig = new SmsTwoFaAccountConfig();
smsTwoFaAccountConfig.setPhoneNumber("+38051889445"); smsTwoFaAccountConfig.setPhoneNumber("+38051889445");
smsTwoFaAccountConfig.setUseByDefault(true);
ArgumentCaptor<String> verificationCodeCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> verificationCodeCaptor = ArgumentCaptor.forClass(String.class);
doPost("/api/2fa/account/config/submit", smsTwoFaAccountConfig).andExpect(status().isOk()); doPost("/api/2fa/account/config/submit", smsTwoFaAccountConfig).andExpect(status().isOk());
@ -459,6 +461,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
SmsTwoFaAccountConfig initialSmsTwoFaAccountConfig = new SmsTwoFaAccountConfig(); SmsTwoFaAccountConfig initialSmsTwoFaAccountConfig = new SmsTwoFaAccountConfig();
initialSmsTwoFaAccountConfig.setPhoneNumber("+38051889445"); initialSmsTwoFaAccountConfig.setPhoneNumber("+38051889445");
initialSmsTwoFaAccountConfig.setUseByDefault(true);
ArgumentCaptor<String> verificationCodeCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> verificationCodeCaptor = ArgumentCaptor.forClass(String.class);
doPost("/api/2fa/account/config/submit", initialSmsTwoFaAccountConfig).andExpect(status().isOk()); doPost("/api/2fa/account/config/submit", initialSmsTwoFaAccountConfig).andExpect(status().isOk());