2FA backup codes
This commit is contained in:
parent
0bb9d531cc
commit
8eb75f6e16
@ -140,14 +140,18 @@ public class TwoFaConfigController extends BaseController {
|
|||||||
@PostMapping("/account/config")
|
@PostMapping("/account/config")
|
||||||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||||
public AccountTwoFaSettings verifyAndSaveTwoFaAccountConfig(@Valid @RequestBody TwoFaAccountConfig accountConfig,
|
public AccountTwoFaSettings verifyAndSaveTwoFaAccountConfig(@Valid @RequestBody TwoFaAccountConfig accountConfig,
|
||||||
@ApiParam(value = "6-digit code from an authenticator app in case of TOTP 2FA, or the one sent via an SMS or email message in case of SMS or EMAIL 2FA", required = true)
|
@RequestParam(required = false) String verificationCode) throws Exception {
|
||||||
@RequestParam String verificationCode) throws Exception {
|
|
||||||
SecurityUser user = getCurrentUser();
|
SecurityUser user = getCurrentUser();
|
||||||
if (twoFaConfigManager.getTwoFaAccountConfig(user.getTenantId(), user.getId(), accountConfig.getProviderType()).isPresent()) {
|
if (twoFaConfigManager.getTwoFaAccountConfig(user.getTenantId(), user.getId(), accountConfig.getProviderType()).isPresent()) {
|
||||||
throw new IllegalArgumentException("2FA provider is already configured");
|
throw new IllegalArgumentException("2FA provider is already configured");
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean verificationSuccess = twoFactorAuthService.checkVerificationCode(user, verificationCode, accountConfig, false);
|
boolean verificationSuccess;
|
||||||
|
if (accountConfig.getProviderType() != TwoFaProviderType.BACKUP_CODE) {
|
||||||
|
verificationSuccess = twoFactorAuthService.checkVerificationCode(user, verificationCode, accountConfig, false);
|
||||||
|
} else {
|
||||||
|
verificationSuccess = true;
|
||||||
|
}
|
||||||
if (verificationSuccess) {
|
if (verificationSuccess) {
|
||||||
return twoFaConfigManager.saveTwoFaAccountConfig(user.getTenantId(), user.getId(), accountConfig);
|
return twoFaConfigManager.saveTwoFaAccountConfig(user.getTenantId(), user.getId(), accountConfig);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -16,7 +16,6 @@
|
|||||||
package org.thingsboard.server.controller;
|
package org.thingsboard.server.controller;
|
||||||
|
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import io.swagger.annotations.ApiParam;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -34,11 +33,11 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
|
|||||||
import org.thingsboard.server.common.data.security.model.mfa.PlatformTwoFaSettings;
|
import org.thingsboard.server.common.data.security.model.mfa.PlatformTwoFaSettings;
|
||||||
import org.thingsboard.server.common.data.security.model.mfa.account.EmailTwoFaAccountConfig;
|
import org.thingsboard.server.common.data.security.model.mfa.account.EmailTwoFaAccountConfig;
|
||||||
import org.thingsboard.server.common.data.security.model.mfa.account.SmsTwoFaAccountConfig;
|
import org.thingsboard.server.common.data.security.model.mfa.account.SmsTwoFaAccountConfig;
|
||||||
|
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderType;
|
||||||
import org.thingsboard.server.dao.user.UserService;
|
import org.thingsboard.server.dao.user.UserService;
|
||||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||||
import org.thingsboard.server.service.security.auth.mfa.TwoFactorAuthService;
|
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.config.TwoFaConfigManager;
|
||||||
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderType;
|
|
||||||
import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails;
|
import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails;
|
||||||
import org.thingsboard.server.service.security.model.JwtTokenPair;
|
import org.thingsboard.server.service.security.model.JwtTokenPair;
|
||||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||||
@ -46,7 +45,6 @@ import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
|
|||||||
import org.thingsboard.server.service.security.system.SystemSecurityService;
|
import org.thingsboard.server.service.security.system.SystemSecurityService;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -90,7 +88,6 @@ public class TwoFactorAuthController extends BaseController {
|
|||||||
@PostMapping("/verification/check")
|
@PostMapping("/verification/check")
|
||||||
@PreAuthorize("hasAuthority('PRE_VERIFICATION_TOKEN')")
|
@PreAuthorize("hasAuthority('PRE_VERIFICATION_TOKEN')")
|
||||||
public JwtTokenPair checkTwoFaVerificationCode(@RequestParam TwoFaProviderType providerType,
|
public JwtTokenPair checkTwoFaVerificationCode(@RequestParam TwoFaProviderType providerType,
|
||||||
@ApiParam(value = "6-digit verification code", required = true)
|
|
||||||
@RequestParam String verificationCode, HttpServletRequest servletRequest) throws Exception {
|
@RequestParam String verificationCode, HttpServletRequest servletRequest) throws Exception {
|
||||||
SecurityUser user = getCurrentUser();
|
SecurityUser user = getCurrentUser();
|
||||||
boolean verificationSuccess = twoFactorAuthService.checkVerificationCode(user, providerType, verificationCode, true);
|
boolean verificationSuccess = twoFactorAuthService.checkVerificationCode(user, providerType, verificationCode, true);
|
||||||
|
|||||||
@ -122,7 +122,7 @@ public class DefaultTwoFactorAuthService implements TwoFactorAuthService {
|
|||||||
.orElseThrow(() -> PROVIDER_NOT_CONFIGURED_ERROR);
|
.orElseThrow(() -> PROVIDER_NOT_CONFIGURED_ERROR);
|
||||||
|
|
||||||
boolean verificationSuccess;
|
boolean verificationSuccess;
|
||||||
if (StringUtils.isNumeric(verificationCode) && verificationCode.length() == 6) {
|
if (StringUtils.isNotBlank(verificationCode)) {
|
||||||
verificationSuccess = getTwoFaProvider(accountConfig.getProviderType()).checkVerificationCode(user, verificationCode, providerConfig, accountConfig);
|
verificationSuccess = getTwoFaProvider(accountConfig.getProviderType()).checkVerificationCode(user, verificationCode, providerConfig, accountConfig);
|
||||||
} else {
|
} else {
|
||||||
verificationSuccess = false;
|
verificationSuccess = false;
|
||||||
|
|||||||
@ -30,7 +30,6 @@ import org.thingsboard.server.common.data.security.model.mfa.account.AccountTwoF
|
|||||||
import org.thingsboard.server.common.data.security.model.mfa.account.TwoFaAccountConfig;
|
import org.thingsboard.server.common.data.security.model.mfa.account.TwoFaAccountConfig;
|
||||||
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderConfig;
|
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.common.data.security.model.mfa.provider.TwoFaProviderType;
|
||||||
import org.thingsboard.server.dao.attributes.AttributesService;
|
|
||||||
import org.thingsboard.server.dao.service.ConstraintValidator;
|
import org.thingsboard.server.dao.service.ConstraintValidator;
|
||||||
import org.thingsboard.server.dao.settings.AdminSettingsDao;
|
import org.thingsboard.server.dao.settings.AdminSettingsDao;
|
||||||
import org.thingsboard.server.dao.settings.AdminSettingsService;
|
import org.thingsboard.server.dao.settings.AdminSettingsService;
|
||||||
@ -39,6 +38,7 @@ import org.thingsboard.server.service.security.auth.mfa.TwoFactorAuthService;
|
|||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@ -74,7 +74,9 @@ public class DefaultTwoFaConfigManager implements TwoFaConfigManager {
|
|||||||
return newUserAuthSettings;
|
return newUserAuthSettings;
|
||||||
});
|
});
|
||||||
userAuthSettings.setTwoFaSettings(settings);
|
userAuthSettings.setTwoFaSettings(settings);
|
||||||
|
settings.getConfigs().values().forEach(accountConfig -> accountConfig.setSerializeHiddenFields(true));
|
||||||
userAuthSettingsDao.save(tenantId, userAuthSettings);
|
userAuthSettingsDao.save(tenantId, userAuthSettings);
|
||||||
|
settings.getConfigs().values().forEach(accountConfig -> accountConfig.setSerializeHiddenFields(false));
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,12 +98,13 @@ public class DefaultTwoFaConfigManager implements TwoFaConfigManager {
|
|||||||
newSettings.setConfigs(new LinkedHashMap<>());
|
newSettings.setConfigs(new LinkedHashMap<>());
|
||||||
return newSettings;
|
return newSettings;
|
||||||
});
|
});
|
||||||
|
Map<TwoFaProviderType, TwoFaAccountConfig> configs = settings.getConfigs();
|
||||||
if (accountConfig.isUseByDefault()) {
|
if (accountConfig.isUseByDefault()) {
|
||||||
settings.getConfigs().values().forEach(config -> config.setUseByDefault(false));
|
configs.values().forEach(config -> config.setUseByDefault(false));
|
||||||
}
|
}
|
||||||
settings.getConfigs().put(accountConfig.getProviderType(), accountConfig);
|
configs.put(accountConfig.getProviderType(), accountConfig);
|
||||||
if (settings.getConfigs().values().stream().noneMatch(TwoFaAccountConfig::isUseByDefault)) {
|
if (configs.values().stream().noneMatch(TwoFaAccountConfig::isUseByDefault)) {
|
||||||
settings.getConfigs().values().stream().findFirst().ifPresent(config -> config.setUseByDefault(true));
|
configs.values().stream().findFirst().ifPresent(config -> config.setUseByDefault(true));
|
||||||
}
|
}
|
||||||
return saveAccountTwoFaSettings(tenantId, userId, settings);
|
return saveAccountTwoFaSettings(tenantId, userId, settings);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,7 @@ public interface TwoFaProvider<C extends TwoFaProviderConfig, A extends TwoFaAcc
|
|||||||
|
|
||||||
default void prepareVerificationCode(SecurityUser user, C providerConfig, A accountConfig) throws ThingsboardException {}
|
default void prepareVerificationCode(SecurityUser user, C providerConfig, A accountConfig) throws ThingsboardException {}
|
||||||
|
|
||||||
boolean checkVerificationCode(SecurityUser user, String verificationCode, C providerConfig, A accountConfig);
|
boolean checkVerificationCode(SecurityUser user, String code, C providerConfig, A accountConfig);
|
||||||
|
|
||||||
default void check(TenantId tenantId) throws ThingsboardException {};
|
default void check(TenantId tenantId) throws ThingsboardException {};
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2022 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.service.security.auth.mfa.provider.impl;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.thingsboard.common.util.CollectionsUtil;
|
||||||
|
import org.thingsboard.server.common.data.User;
|
||||||
|
import org.thingsboard.server.common.data.security.model.mfa.account.BackupCodeTwoFaAccountConfig;
|
||||||
|
import org.thingsboard.server.common.data.security.model.mfa.provider.BackupCodeTwoFaProviderConfig;
|
||||||
|
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderType;
|
||||||
|
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||||
|
import org.thingsboard.server.service.security.auth.mfa.config.TwoFaConfigManager;
|
||||||
|
import org.thingsboard.server.service.security.auth.mfa.provider.TwoFaProvider;
|
||||||
|
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@TbCoreComponent
|
||||||
|
public class BackupCodeTwoFaProvider implements TwoFaProvider<BackupCodeTwoFaProviderConfig, BackupCodeTwoFaAccountConfig> {
|
||||||
|
|
||||||
|
@Autowired @Lazy
|
||||||
|
private TwoFaConfigManager twoFaConfigManager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BackupCodeTwoFaAccountConfig generateNewAccountConfig(User user, BackupCodeTwoFaProviderConfig providerConfig) {
|
||||||
|
BackupCodeTwoFaAccountConfig config = new BackupCodeTwoFaAccountConfig();
|
||||||
|
config.setCodes(generateCodes(providerConfig.getCodesQuantity(), 8));
|
||||||
|
config.setSerializeHiddenFields(true);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<String> generateCodes(int count, int length) {
|
||||||
|
return Stream.generate(() -> RandomStringUtils.random(length, "0123456789abcdef"))
|
||||||
|
.distinct().limit(count)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkVerificationCode(SecurityUser user, String code, BackupCodeTwoFaProviderConfig providerConfig, BackupCodeTwoFaAccountConfig accountConfig) {
|
||||||
|
if (CollectionsUtil.contains(accountConfig.getCodes(), code)) {
|
||||||
|
accountConfig.getCodes().remove(code);
|
||||||
|
twoFaConfigManager.saveTwoFaAccountConfig(user.getTenantId(), user.getId(), accountConfig);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TwoFaProviderType getType() {
|
||||||
|
return TwoFaProviderType.BACKUP_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -48,7 +48,7 @@ public abstract class OtpBasedTwoFaProvider<C extends OtpBasedTwoFaProviderConfi
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean checkVerificationCode(SecurityUser user, String verificationCode, C providerConfig, A accountConfig) {
|
public final boolean checkVerificationCode(SecurityUser user, String code, C providerConfig, A accountConfig) {
|
||||||
Otp correctVerificationCode = verificationCodesCache.get(user.getId(), Otp.class);
|
Otp correctVerificationCode = verificationCodesCache.get(user.getId(), Otp.class);
|
||||||
if (correctVerificationCode != null) {
|
if (correctVerificationCode != null) {
|
||||||
if (System.currentTimeMillis() - correctVerificationCode.getTimestamp()
|
if (System.currentTimeMillis() - correctVerificationCode.getTimestamp()
|
||||||
@ -56,7 +56,7 @@ public abstract class OtpBasedTwoFaProvider<C extends OtpBasedTwoFaProviderConfi
|
|||||||
verificationCodesCache.evict(user.getId());
|
verificationCodesCache.evict(user.getId());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (verificationCode.equals(correctVerificationCode.getValue())
|
if (code.equals(correctVerificationCode.getValue())
|
||||||
&& accountConfig.equals(correctVerificationCode.getAccountConfig())) {
|
&& accountConfig.equals(correctVerificationCode.getAccountConfig())) {
|
||||||
verificationCodesCache.evict(user.getId());
|
verificationCodesCache.evict(user.getId());
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -45,9 +45,9 @@ public class TotpTwoFaProvider implements TwoFaProvider<TotpTwoFaProviderConfig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean checkVerificationCode(SecurityUser user, String verificationCode, TotpTwoFaProviderConfig providerConfig, TotpTwoFaAccountConfig accountConfig) {
|
public final boolean checkVerificationCode(SecurityUser user, String code, TotpTwoFaProviderConfig providerConfig, TotpTwoFaAccountConfig accountConfig) {
|
||||||
String secretKey = UriComponentsBuilder.fromUriString(accountConfig.getAuthUrl()).build().getQueryParams().getFirst("secret");
|
String secretKey = UriComponentsBuilder.fromUriString(accountConfig.getAuthUrl()).build().getQueryParams().getFirst("secret");
|
||||||
return new Totp(secretKey).verify(verificationCode);
|
return new Totp(secretKey).verify(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
|
|||||||
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2022 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.common.data.security.model.mfa.account;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderType;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class BackupCodeTwoFaAccountConfig extends TwoFaAccountConfig {
|
||||||
|
|
||||||
|
@NotEmpty
|
||||||
|
private Set<String> codes;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TwoFaProviderType getProviderType() {
|
||||||
|
return TwoFaProviderType.BACKUP_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@JsonGetter("codes")
|
||||||
|
private Set<String> getCodesForJson() {
|
||||||
|
if (serializeHiddenFields) {
|
||||||
|
return codes;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonGetter
|
||||||
|
private Integer getCodesLeft() {
|
||||||
|
if (codes != null) {
|
||||||
|
return codes.size();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -30,13 +30,17 @@ import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProvi
|
|||||||
@JsonSubTypes({
|
@JsonSubTypes({
|
||||||
@Type(name = "TOTP", value = TotpTwoFaAccountConfig.class),
|
@Type(name = "TOTP", value = TotpTwoFaAccountConfig.class),
|
||||||
@Type(name = "SMS", value = SmsTwoFaAccountConfig.class),
|
@Type(name = "SMS", value = SmsTwoFaAccountConfig.class),
|
||||||
@Type(name = "EMAIL", value = EmailTwoFaAccountConfig.class)
|
@Type(name = "EMAIL", value = EmailTwoFaAccountConfig.class),
|
||||||
|
@Type(name = "BACKUP_CODE", value = BackupCodeTwoFaAccountConfig.class)
|
||||||
})
|
})
|
||||||
@Data
|
@Data
|
||||||
public abstract class TwoFaAccountConfig {
|
public abstract class TwoFaAccountConfig {
|
||||||
|
|
||||||
private boolean useByDefault;
|
private boolean useByDefault;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
protected transient boolean serializeHiddenFields;
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public abstract TwoFaProviderType getProviderType();
|
public abstract TwoFaProviderType getProviderType();
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2022 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.common.data.security.model.mfa.provider;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Min;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class BackupCodeTwoFaProviderConfig implements TwoFaProviderConfig {
|
||||||
|
|
||||||
|
@Min(0)
|
||||||
|
private int codesQuantity;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TwoFaProviderType getProviderType() {
|
||||||
|
return TwoFaProviderType.BACKUP_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -28,7 +28,8 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|||||||
@JsonSubTypes({
|
@JsonSubTypes({
|
||||||
@Type(name = "TOTP", value = TotpTwoFaProviderConfig.class),
|
@Type(name = "TOTP", value = TotpTwoFaProviderConfig.class),
|
||||||
@Type(name = "SMS", value = SmsTwoFaProviderConfig.class),
|
@Type(name = "SMS", value = SmsTwoFaProviderConfig.class),
|
||||||
@Type(name = "EMAIL", value = EmailTwoFaProviderConfig.class)
|
@Type(name = "EMAIL", value = EmailTwoFaProviderConfig.class),
|
||||||
|
@Type(name = "BACKUP_CODE", value = BackupCodeTwoFaProviderConfig.class)
|
||||||
})
|
})
|
||||||
public interface TwoFaProviderConfig {
|
public interface TwoFaProviderConfig {
|
||||||
|
|
||||||
|
|||||||
@ -18,5 +18,6 @@ package org.thingsboard.server.common.data.security.model.mfa.provider;
|
|||||||
public enum TwoFaProviderType {
|
public enum TwoFaProviderType {
|
||||||
TOTP,
|
TOTP,
|
||||||
SMS,
|
SMS,
|
||||||
EMAIL
|
EMAIL,
|
||||||
|
BACKUP_CODE
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,4 +34,9 @@ public class CollectionsUtil {
|
|||||||
public static <T> Set<T> diffSets(Set<T> a, Set<T> b) {
|
public static <T> Set<T> diffSets(Set<T> a, Set<T> b) {
|
||||||
return b.stream().filter(p -> !a.contains(p)).collect(Collectors.toSet());
|
return b.stream().filter(p -> !a.contains(p)).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> boolean contains(Collection<T> collection, T element) {
|
||||||
|
return isNotEmpty(collection) && collection.contains(element);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user