diff --git a/application/src/main/java/org/thingsboard/server/controller/TwoFaConfigController.java b/application/src/main/java/org/thingsboard/server/controller/TwoFaConfigController.java index 907618c26f..2dec65ed93 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TwoFaConfigController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TwoFaConfigController.java @@ -206,15 +206,13 @@ public class TwoFaConfigController extends BaseController { "If 2FA is not configured, then an empty response will be returned." + ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/settings") - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") public PlatformTwoFaSettings getPlatformTwoFaSettings() throws ThingsboardException { return twoFaConfigManager.getPlatformTwoFaSettings(getTenantId(), false).orElse(null); } @ApiOperation(value = "Save platform 2FA settings (savePlatformTwoFaSettings)", notes = "Save 2FA settings for platform. The settings have following properties:\n" + - "- `useSystemTwoFactorAuthSettings` - option for tenant admins to use 2FA settings configured by sysadmin. " + - "If this param is set to true, then the settings will not be validated for constraints (if it is a tenant admin; for sysadmin this param is ignored).\n" + "- `providers` - the list of 2FA providers' configs. Users will only be allowed to use 2FA providers from this list. \n\n" + "- `verificationCodeSendRateLimit` - rate limit configuration for verification code sending. " + "The format is standard: 'amountOfRequests:periodInSeconds'. The value of '1:60' would limit verification " + @@ -233,7 +231,6 @@ public class TwoFaConfigController extends BaseController { "- `verificationCodeLifetime` - the same as for SMS." + NEW_LINE + "Example of the settings:\n" + "```\n{\n" + - " \"useSystemTwoFactorAuthSettings\": false,\n" + " \"providers\": [\n" + " {\n" + " \"providerType\": \"TOTP\",\n" + @@ -256,7 +253,7 @@ public class TwoFaConfigController extends BaseController { "}\n```" + ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PostMapping("/settings") - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") public void savePlatformTwoFaSettings(@ApiParam(value = "Settings value", required = true) @RequestBody PlatformTwoFaSettings twoFaSettings) throws ThingsboardException { twoFaConfigManager.savePlatformTwoFaSettings(getTenantId(), twoFaSettings); diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/mfa/config/DefaultTwoFaConfigManager.java b/application/src/main/java/org/thingsboard/server/service/security/auth/mfa/config/DefaultTwoFaConfigManager.java index 8227a3596a..e27d3967ad 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/mfa/config/DefaultTwoFaConfigManager.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/mfa/config/DefaultTwoFaConfigManager.java @@ -16,18 +16,14 @@ package org.thingsboard.server.service.security.auth.mfa.config; import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.AdminSettings; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; -import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.security.UserAuthSettings; import org.thingsboard.server.common.data.security.model.mfa.PlatformTwoFaSettings; import org.thingsboard.server.common.data.security.model.mfa.account.AccountTwoFaSettings; @@ -41,11 +37,9 @@ import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.user.UserAuthSettingsDao; import org.thingsboard.server.service.security.auth.mfa.TwoFactorAuthService; -import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.Optional; -import java.util.concurrent.ExecutionException; @Service @RequiredArgsConstructor @@ -54,7 +48,6 @@ public class DefaultTwoFaConfigManager implements TwoFaConfigManager { private final UserAuthSettingsDao userAuthSettingsDao; private final AdminSettingsService adminSettingsService; private final AdminSettingsDao adminSettingsDao; - private final AttributesService attributesService; @Autowired @Lazy private TwoFactorAuthService twoFactorAuthService; @@ -132,60 +125,33 @@ public class DefaultTwoFaConfigManager implements TwoFaConfigManager { .flatMap(twoFaSettings -> twoFaSettings.getProviderConfig(providerType)); } - @SneakyThrows({InterruptedException.class, ExecutionException.class}) @Override public Optional getPlatformTwoFaSettings(TenantId tenantId, boolean sysadminSettingsAsDefault) { - if (tenantId.equals(TenantId.SYS_TENANT_ID)) { - return Optional.ofNullable(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, TWO_FACTOR_AUTH_SETTINGS_KEY)) - .map(adminSettings -> JacksonUtil.treeToValue(adminSettings.getJsonValue(), PlatformTwoFaSettings.class)); - } else { - Optional tenantTwoFaSettings = attributesService.find(TenantId.SYS_TENANT_ID, tenantId, - DataConstants.SERVER_SCOPE, TWO_FACTOR_AUTH_SETTINGS_KEY).get() - .map(adminSettingsAttribute -> JacksonUtil.fromString(adminSettingsAttribute.getJsonValue().get(), PlatformTwoFaSettings.class)); - if (sysadminSettingsAsDefault) { - if (tenantTwoFaSettings.isEmpty() || tenantTwoFaSettings.get().isUseSystemTwoFactorAuthSettings()) { - return getPlatformTwoFaSettings(TenantId.SYS_TENANT_ID, false); - } - } - return tenantTwoFaSettings; - } + return Optional.ofNullable(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, TWO_FACTOR_AUTH_SETTINGS_KEY)) + .map(adminSettings -> JacksonUtil.treeToValue(adminSettings.getJsonValue(), PlatformTwoFaSettings.class)); } - @SneakyThrows({InterruptedException.class, ExecutionException.class}) @Override public void savePlatformTwoFaSettings(TenantId tenantId, PlatformTwoFaSettings twoFactorAuthSettings) throws ThingsboardException { - if (tenantId.equals(TenantId.SYS_TENANT_ID) || !twoFactorAuthSettings.isUseSystemTwoFactorAuthSettings()) { - ConstraintValidator.validateFields(twoFactorAuthSettings); - } + ConstraintValidator.validateFields(twoFactorAuthSettings); for (TwoFaProviderConfig providerConfig : twoFactorAuthSettings.getProviders()) { twoFactorAuthService.checkProvider(tenantId, providerConfig.getProviderType()); } - if (tenantId.equals(TenantId.SYS_TENANT_ID)) { - AdminSettings settings = Optional.ofNullable(adminSettingsService.findAdminSettingsByKey(tenantId, TWO_FACTOR_AUTH_SETTINGS_KEY)) - .orElseGet(() -> { - AdminSettings newSettings = new AdminSettings(); - newSettings.setKey(TWO_FACTOR_AUTH_SETTINGS_KEY); - return newSettings; - }); - settings.setJsonValue(JacksonUtil.valueToTree(twoFactorAuthSettings)); - adminSettingsService.saveAdminSettings(tenantId, settings); - } else { - attributesService.save(TenantId.SYS_TENANT_ID, tenantId, DataConstants.SERVER_SCOPE, Collections.singletonList( - new BaseAttributeKvEntry(new JsonDataEntry(TWO_FACTOR_AUTH_SETTINGS_KEY, JacksonUtil.toString(twoFactorAuthSettings)), System.currentTimeMillis()) - )).get(); - } + + AdminSettings settings = Optional.ofNullable(adminSettingsService.findAdminSettingsByKey(tenantId, TWO_FACTOR_AUTH_SETTINGS_KEY)) + .orElseGet(() -> { + AdminSettings newSettings = new AdminSettings(); + newSettings.setKey(TWO_FACTOR_AUTH_SETTINGS_KEY); + return newSettings; + }); + settings.setJsonValue(JacksonUtil.valueToTree(twoFactorAuthSettings)); + adminSettingsService.saveAdminSettings(tenantId, settings); } - @SneakyThrows({InterruptedException.class, ExecutionException.class}) @Override public void deletePlatformTwoFaSettings(TenantId tenantId) { - if (tenantId.equals(TenantId.SYS_TENANT_ID)) { - Optional.ofNullable(adminSettingsService.findAdminSettingsByKey(tenantId, TWO_FACTOR_AUTH_SETTINGS_KEY)) - .ifPresent(adminSettings -> adminSettingsDao.removeById(tenantId, adminSettings.getId().getId())); - } else { - attributesService.removeAll(TenantId.SYS_TENANT_ID, tenantId, DataConstants.SERVER_SCOPE, - Collections.singletonList(TWO_FACTOR_AUTH_SETTINGS_KEY)).get(); - } + Optional.ofNullable(adminSettingsService.findAdminSettingsByKey(tenantId, TWO_FACTOR_AUTH_SETTINGS_KEY)) + .ifPresent(adminSettings -> adminSettingsDao.removeById(tenantId, adminSettings.getId().getId())); } } diff --git a/application/src/test/java/org/thingsboard/server/controller/TwoFactorAuthConfigTest.java b/application/src/test/java/org/thingsboard/server/controller/TwoFactorAuthConfigTest.java index 2c4bd9fdb9..d6fc640878 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TwoFactorAuthConfigTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/TwoFactorAuthConfigTest.java @@ -30,10 +30,8 @@ import org.springframework.web.util.UriComponentsBuilder; import org.thingsboard.rule.engine.api.SmsService; import org.thingsboard.server.common.data.CacheConstants; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.security.model.mfa.account.AccountTwoFaSettings; -import org.thingsboard.server.service.security.auth.mfa.TwoFactorAuthService; -import org.thingsboard.server.service.security.auth.mfa.config.TwoFaConfigManager; import org.thingsboard.server.common.data.security.model.mfa.PlatformTwoFaSettings; +import org.thingsboard.server.common.data.security.model.mfa.account.AccountTwoFaSettings; import org.thingsboard.server.common.data.security.model.mfa.account.SmsTwoFaAccountConfig; import org.thingsboard.server.common.data.security.model.mfa.account.TotpTwoFaAccountConfig; import org.thingsboard.server.common.data.security.model.mfa.account.TwoFaAccountConfig; @@ -41,6 +39,8 @@ import org.thingsboard.server.common.data.security.model.mfa.provider.SmsTwoFaPr import org.thingsboard.server.common.data.security.model.mfa.provider.TotpTwoFaProviderConfig; import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderConfig; import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderType; +import org.thingsboard.server.service.security.auth.mfa.TwoFactorAuthService; +import org.thingsboard.server.service.security.auth.mfa.config.TwoFaConfigManager; import org.thingsboard.server.service.security.auth.mfa.provider.impl.OtpBasedTwoFaProvider; import org.thingsboard.server.service.security.auth.mfa.provider.impl.TotpTwoFaProvider; @@ -85,15 +85,9 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest { @Test - public void testSavePlatformTwoFaSettingsForDifferentAuthorities() throws Exception { + public void testSavePlatformTwoFaSettings() throws Exception { loginSysAdmin(); - testSavePlatformTwoFaSettings(); - - loginTenantAdmin(); - testSavePlatformTwoFaSettings(); - } - private void testSavePlatformTwoFaSettings() throws Exception { TotpTwoFaProviderConfig totpTwoFaProviderConfig = new TotpTwoFaProviderConfig(); totpTwoFaProviderConfig.setIssuerName("tb"); SmsTwoFaProviderConfig smsTwoFaProviderConfig = new SmsTwoFaProviderConfig(); @@ -117,7 +111,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest { @Test public void testSavePlatformTwoFaSettings_validationError() throws Exception { - loginTenantAdmin(); + loginSysAdmin(); PlatformTwoFaSettings twoFaSettings = new PlatformTwoFaSettings(); twoFaSettings.setProviders(Collections.emptyList()); @@ -135,71 +129,6 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest { "maximum number of verification failure before user lockout must be positive", "total amount of time allotted for verification must be greater than 0" ); - - twoFaSettings.setUseSystemTwoFactorAuthSettings(true); - doPost("/api/2fa/settings", twoFaSettings) - .andExpect(status().isOk()); - - twoFaSettings.setVerificationCodeSendRateLimit(null); - twoFaSettings.setVerificationCodeCheckRateLimit(null); - twoFaSettings.setMaxVerificationFailuresBeforeUserLockout(0); - twoFaSettings.setTotalAllowedTimeForVerification(null); - - doPost("/api/2fa/settings", twoFaSettings) - .andExpect(status().isOk()); - } - - @Test - public void testGetPlatformTwoFaSettings_useSysadminSettingsAsDefault() throws Exception { - loginSysAdmin(); - PlatformTwoFaSettings sysadminTwoFaSettings = new PlatformTwoFaSettings(); - TotpTwoFaProviderConfig totpTwoFaProviderConfig = new TotpTwoFaProviderConfig(); - totpTwoFaProviderConfig.setIssuerName("tb"); - sysadminTwoFaSettings.setProviders(Collections.singletonList(totpTwoFaProviderConfig)); - sysadminTwoFaSettings.setMaxVerificationFailuresBeforeUserLockout(25); - doPost("/api/2fa/settings", sysadminTwoFaSettings).andExpect(status().isOk()); - - loginTenantAdmin(); - PlatformTwoFaSettings tenantTwoFaSettings = new PlatformTwoFaSettings(); - tenantTwoFaSettings.setUseSystemTwoFactorAuthSettings(true); - tenantTwoFaSettings.setProviders(Collections.emptyList()); - doPost("/api/2fa/settings", tenantTwoFaSettings).andExpect(status().isOk()); - PlatformTwoFaSettings twoFaSettings = readResponse(doGet("/api/2fa/settings").andExpect(status().isOk()), PlatformTwoFaSettings.class); - assertThat(twoFaSettings).isEqualTo(tenantTwoFaSettings); - - doPost("/api/2fa/account/config/generate?providerType=TOTP") - .andExpect(status().isOk()); - - tenantTwoFaSettings.setUseSystemTwoFactorAuthSettings(false); - tenantTwoFaSettings.setProviders(Collections.emptyList()); - tenantTwoFaSettings.setMaxVerificationFailuresBeforeUserLockout(10); - doPost("/api/2fa/settings", tenantTwoFaSettings).andExpect(status().isOk()); - twoFaSettings = readResponse(doGet("/api/2fa/settings").andExpect(status().isOk()), PlatformTwoFaSettings.class); - assertThat(twoFaSettings).isEqualTo(tenantTwoFaSettings); - - assertThat(getErrorMessage(doPost("/api/2fa/account/config/generate?providerType=TOTP") - .andExpect(status().isBadRequest()))).containsIgnoringCase("provider is not configured"); - - loginSysAdmin(); - sysadminTwoFaSettings.setProviders(Collections.emptyList()); - doPost("/api/2fa/settings", sysadminTwoFaSettings).andExpect(status().isOk()); - loginTenantAdmin(); - tenantTwoFaSettings.setUseSystemTwoFactorAuthSettings(true); - tenantTwoFaSettings.setProviders(Collections.singletonList(totpTwoFaProviderConfig)); - doPost("/api/2fa/settings", tenantTwoFaSettings).andExpect(status().isOk()); - - assertThat(getErrorMessage(doPost("/api/2fa/account/config/generate?providerType=TOTP") - .andExpect(status().isBadRequest()))).containsIgnoringCase("provider is not configured"); - - tenantTwoFaSettings.setUseSystemTwoFactorAuthSettings(false); - doPost("/api/2fa/settings", tenantTwoFaSettings).andExpect(status().isOk()); - - doPost("/api/2fa/account/config/generate?providerType=TOTP") - .andExpect(status().isOk()); - - loginSysAdmin(); - twoFaSettings = readResponse(doGet("/api/2fa/settings").andExpect(status().isOk()), PlatformTwoFaSettings.class); - assertThat(twoFaSettings).isEqualTo(sysadminTwoFaSettings); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/TwoFactorAuthTest.java b/application/src/test/java/org/thingsboard/server/controller/TwoFactorAuthTest.java index 74b95284aa..40070b0106 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TwoFactorAuthTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/TwoFactorAuthTest.java @@ -345,7 +345,6 @@ public abstract class TwoFactorAuthTest extends AbstractControllerTest { @Test public void testTwoFa_multipleProviders() throws Exception { PlatformTwoFaSettings platformTwoFaSettings = new PlatformTwoFaSettings(); - platformTwoFaSettings.setUseSystemTwoFactorAuthSettings(true); TotpTwoFaProviderConfig totpTwoFaProviderConfig = new TotpTwoFaProviderConfig(); totpTwoFaProviderConfig.setIssuerName("TB"); @@ -411,10 +410,9 @@ public abstract class TwoFactorAuthTest extends AbstractControllerTest { totpTwoFaProviderConfig.setIssuerName("tb"); PlatformTwoFaSettings twoFaSettings = new PlatformTwoFaSettings(); - twoFaSettings.setUseSystemTwoFactorAuthSettings(false); twoFaSettings.setProviders(Arrays.stream(new TwoFaProviderConfig[]{totpTwoFaProviderConfig}).collect(Collectors.toList())); Arrays.stream(customizer).forEach(c -> c.accept(twoFaSettings)); - twoFaConfigManager.savePlatformTwoFaSettings(tenantId, twoFaSettings); + twoFaConfigManager.savePlatformTwoFaSettings(TenantId.SYS_TENANT_ID, twoFaSettings); TotpTwoFaAccountConfig totpTwoFaAccountConfig = (TotpTwoFaAccountConfig) twoFactorAuthService.generateNewAccountConfig(user, TwoFaProviderType.TOTP); twoFaConfigManager.saveTwoFaAccountConfig(tenantId, user.getId(), totpTwoFaAccountConfig); @@ -428,9 +426,8 @@ public abstract class TwoFactorAuthTest extends AbstractControllerTest { Arrays.stream(customizer).forEach(c -> c.accept(smsTwoFaProviderConfig)); PlatformTwoFaSettings twoFaSettings = new PlatformTwoFaSettings(); - twoFaSettings.setUseSystemTwoFactorAuthSettings(false); twoFaSettings.setProviders(Arrays.stream(new TwoFaProviderConfig[]{smsTwoFaProviderConfig}).collect(Collectors.toList())); - twoFaConfigManager.savePlatformTwoFaSettings(tenantId, twoFaSettings); + twoFaConfigManager.savePlatformTwoFaSettings(TenantId.SYS_TENANT_ID, twoFaSettings); SmsTwoFaAccountConfig smsTwoFaAccountConfig = new SmsTwoFaAccountConfig(); smsTwoFaAccountConfig.setPhoneNumber("+38050505050"); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/model/mfa/PlatformTwoFaSettings.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/model/mfa/PlatformTwoFaSettings.java index 8d017cab20..39ca0349fb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/model/mfa/PlatformTwoFaSettings.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/model/mfa/PlatformTwoFaSettings.java @@ -28,7 +28,6 @@ import java.util.Optional; @Data public class PlatformTwoFaSettings { - private boolean useSystemTwoFactorAuthSettings; @Valid private List providers;