Store 2FA account config is UserCredentials' additionalInfo
This commit is contained in:
parent
b7db4ed604
commit
95f41810ac
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.service.security.auth.mfa.config;
|
package org.thingsboard.server.service.security.auth.mfa.config;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
@ -22,13 +23,13 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.thingsboard.common.util.JacksonUtil;
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
import org.thingsboard.server.common.data.AdminSettings;
|
import org.thingsboard.server.common.data.AdminSettings;
|
||||||
import org.thingsboard.server.common.data.DataConstants;
|
import org.thingsboard.server.common.data.DataConstants;
|
||||||
import org.thingsboard.server.common.data.User;
|
|
||||||
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
|
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
|
||||||
import org.thingsboard.server.common.data.exception.ThingsboardException;
|
import org.thingsboard.server.common.data.exception.ThingsboardException;
|
||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.id.UserId;
|
import org.thingsboard.server.common.data.id.UserId;
|
||||||
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
|
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
|
||||||
import org.thingsboard.server.common.data.kv.JsonDataEntry;
|
import org.thingsboard.server.common.data.kv.JsonDataEntry;
|
||||||
|
import org.thingsboard.server.common.data.security.UserCredentials;
|
||||||
import org.thingsboard.server.dao.attributes.AttributesService;
|
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;
|
||||||
@ -41,6 +42,7 @@ import org.thingsboard.server.service.security.auth.mfa.provider.TwoFactorAuthPr
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
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
|
||||||
@ -62,9 +64,8 @@ public class DefaultTwoFactorAuthConfigManager implements TwoFactorAuthConfigMan
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<TwoFactorAuthAccountConfig> getTwoFaAccountConfig(TenantId tenantId, UserId userId) {
|
public Optional<TwoFactorAuthAccountConfig> getTwoFaAccountConfig(TenantId tenantId, UserId userId) {
|
||||||
User user = userService.findUserById(tenantId, userId);
|
return Optional.ofNullable(getAccountInfo(tenantId, userId).get(TWO_FACTOR_AUTH_ACCOUNT_CONFIG_KEY))
|
||||||
return Optional.ofNullable(user.getAdditionalInfo())
|
.filter(JsonNode::isObject)
|
||||||
.flatMap(additionalInfo -> Optional.ofNullable(additionalInfo.get(TWO_FACTOR_AUTH_ACCOUNT_CONFIG_KEY)).filter(jsonNode -> !jsonNode.isNull()))
|
|
||||||
.map(jsonNode -> JacksonUtil.treeToValue(jsonNode, TwoFactorAuthAccountConfig.class))
|
.map(jsonNode -> JacksonUtil.treeToValue(jsonNode, TwoFactorAuthAccountConfig.class))
|
||||||
.filter(twoFactorAuthAccountConfig -> {
|
.filter(twoFactorAuthAccountConfig -> {
|
||||||
return getTwoFaProviderConfig(tenantId, twoFactorAuthAccountConfig.getProviderType()).isPresent();
|
return getTwoFaProviderConfig(tenantId, twoFactorAuthAccountConfig.getProviderType()).isPresent();
|
||||||
@ -76,24 +77,33 @@ public class DefaultTwoFactorAuthConfigManager implements TwoFactorAuthConfigMan
|
|||||||
getTwoFaProviderConfig(tenantId, accountConfig.getProviderType())
|
getTwoFaProviderConfig(tenantId, accountConfig.getProviderType())
|
||||||
.orElseThrow(() -> new ThingsboardException("2FA provider is not configured", ThingsboardErrorCode.BAD_REQUEST_PARAMS));
|
.orElseThrow(() -> new ThingsboardException("2FA provider is not configured", ThingsboardErrorCode.BAD_REQUEST_PARAMS));
|
||||||
|
|
||||||
User user = userService.findUserById(tenantId, userId);
|
updateAccountInfo(tenantId, userId, accountInfo -> {
|
||||||
ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(user.getAdditionalInfo())
|
accountInfo.set(TWO_FACTOR_AUTH_ACCOUNT_CONFIG_KEY, JacksonUtil.valueToTree(accountConfig));
|
||||||
.orElseGet(JacksonUtil::newObjectNode);
|
});
|
||||||
additionalInfo.set(TWO_FACTOR_AUTH_ACCOUNT_CONFIG_KEY, JacksonUtil.valueToTree(accountConfig));
|
|
||||||
user.setAdditionalInfo(additionalInfo);
|
|
||||||
|
|
||||||
userService.saveUser(user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteTwoFaAccountConfig(TenantId tenantId, UserId userId) {
|
public void deleteTwoFaAccountConfig(TenantId tenantId, UserId userId) {
|
||||||
User user = userService.findUserById(tenantId, userId);
|
updateAccountInfo(tenantId, userId, accountInfo -> {
|
||||||
ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(user.getAdditionalInfo())
|
accountInfo.remove(TWO_FACTOR_AUTH_ACCOUNT_CONFIG_KEY);
|
||||||
.orElseGet(JacksonUtil::newObjectNode);
|
});
|
||||||
additionalInfo.remove(TWO_FACTOR_AUTH_ACCOUNT_CONFIG_KEY);
|
}
|
||||||
user.setAdditionalInfo(additionalInfo);
|
|
||||||
|
|
||||||
userService.saveUser(user);
|
private ObjectNode getAccountInfo(TenantId tenantId, UserId userId) {
|
||||||
|
return (ObjectNode) Optional.ofNullable(userService.findUserCredentialsByUserId(tenantId, userId).getAdditionalInfo())
|
||||||
|
.filter(JsonNode::isObject)
|
||||||
|
.orElseGet(JacksonUtil::newObjectNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME [viacheslav]: upgrade script for credentials' additional info
|
||||||
|
private void updateAccountInfo(TenantId tenantId, UserId userId, Consumer<ObjectNode> updater) {
|
||||||
|
UserCredentials credentials = userService.findUserCredentialsByUserId(tenantId, userId);
|
||||||
|
ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(credentials.getAdditionalInfo())
|
||||||
|
.filter(JsonNode::isObject)
|
||||||
|
.orElseGet(JacksonUtil::newObjectNode);
|
||||||
|
updater.accept(additionalInfo);
|
||||||
|
credentials.setAdditionalInfo(additionalInfo);
|
||||||
|
userService.saveUserCredentials(tenantId, credentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -51,24 +51,24 @@ public interface UserService {
|
|||||||
|
|
||||||
UserCredentials replaceUserCredentials(TenantId tenantId, UserCredentials userCredentials);
|
UserCredentials replaceUserCredentials(TenantId tenantId, UserCredentials userCredentials);
|
||||||
|
|
||||||
void deleteUser(TenantId tenantId, UserId userId);
|
void deleteUser(TenantId tenantId, UserId userId);
|
||||||
|
|
||||||
PageData<User> findUsersByTenantId(TenantId tenantId, PageLink pageLink);
|
PageData<User> findUsersByTenantId(TenantId tenantId, PageLink pageLink);
|
||||||
|
|
||||||
PageData<User> findTenantAdmins(TenantId tenantId, PageLink pageLink);
|
PageData<User> findTenantAdmins(TenantId tenantId, PageLink pageLink);
|
||||||
|
|
||||||
void deleteTenantAdmins(TenantId tenantId);
|
void deleteTenantAdmins(TenantId tenantId);
|
||||||
|
|
||||||
PageData<User> findCustomerUsers(TenantId tenantId, CustomerId customerId, PageLink pageLink);
|
PageData<User> findCustomerUsers(TenantId tenantId, CustomerId customerId, PageLink pageLink);
|
||||||
|
|
||||||
void deleteCustomerUsers(TenantId tenantId, CustomerId customerId);
|
void deleteCustomerUsers(TenantId tenantId, CustomerId customerId);
|
||||||
|
|
||||||
void setUserCredentialsEnabled(TenantId tenantId, UserId userId, boolean enabled);
|
void setUserCredentialsEnabled(TenantId tenantId, UserId userId, boolean enabled);
|
||||||
|
|
||||||
void resetFailedLoginAttempts(TenantId tenantId, UserId userId);
|
void resetFailedLoginAttempts(TenantId tenantId, UserId userId);
|
||||||
|
|
||||||
int increaseFailedLoginAttempts(TenantId tenantId, UserId userId);
|
int increaseFailedLoginAttempts(TenantId tenantId, UserId userId);
|
||||||
|
|
||||||
void setLastLoginTs(TenantId tenantId, UserId userId);
|
void setLastLoginTs(TenantId tenantId, UserId userId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,12 +16,12 @@
|
|||||||
package org.thingsboard.server.common.data.security;
|
package org.thingsboard.server.common.data.security;
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.thingsboard.server.common.data.BaseData;
|
import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
|
||||||
import org.thingsboard.server.common.data.id.UserCredentialsId;
|
import org.thingsboard.server.common.data.id.UserCredentialsId;
|
||||||
import org.thingsboard.server.common.data.id.UserId;
|
import org.thingsboard.server.common.data.id.UserId;
|
||||||
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class UserCredentials extends BaseData<UserCredentialsId> {
|
public class UserCredentials extends SearchTextBasedWithAdditionalInfo<UserCredentialsId> {
|
||||||
|
|
||||||
private static final long serialVersionUID = -2108436378880529163L;
|
private static final long serialVersionUID = -2108436378880529163L;
|
||||||
|
|
||||||
@ -87,6 +87,11 @@ public class UserCredentials extends BaseData<UserCredentialsId> {
|
|||||||
public void setResetToken(String resetToken) {
|
public void setResetToken(String resetToken) {
|
||||||
this.resetToken = resetToken;
|
this.resetToken = resetToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSearchText() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|||||||
@ -15,14 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.dao.model.sql;
|
package org.thingsboard.server.dao.model.sql;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.hibernate.annotations.Type;
|
||||||
|
import org.hibernate.annotations.TypeDef;
|
||||||
import org.thingsboard.server.common.data.id.UserCredentialsId;
|
import org.thingsboard.server.common.data.id.UserCredentialsId;
|
||||||
import org.thingsboard.server.common.data.id.UserId;
|
import org.thingsboard.server.common.data.id.UserId;
|
||||||
import org.thingsboard.server.common.data.security.UserCredentials;
|
import org.thingsboard.server.common.data.security.UserCredentials;
|
||||||
import org.thingsboard.server.dao.model.BaseEntity;
|
import org.thingsboard.server.dao.model.BaseEntity;
|
||||||
import org.thingsboard.server.dao.model.BaseSqlEntity;
|
import org.thingsboard.server.dao.model.BaseSqlEntity;
|
||||||
import org.thingsboard.server.dao.model.ModelConstants;
|
import org.thingsboard.server.dao.model.ModelConstants;
|
||||||
|
import org.thingsboard.server.dao.util.mapping.JsonStringType;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
@ -31,6 +35,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TypeDef(name = "json", typeClass = JsonStringType.class)
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = ModelConstants.USER_CREDENTIALS_COLUMN_FAMILY_NAME)
|
@Table(name = ModelConstants.USER_CREDENTIALS_COLUMN_FAMILY_NAME)
|
||||||
public final class UserCredentialsEntity extends BaseSqlEntity<UserCredentials> implements BaseEntity<UserCredentials> {
|
public final class UserCredentialsEntity extends BaseSqlEntity<UserCredentials> implements BaseEntity<UserCredentials> {
|
||||||
@ -50,6 +55,10 @@ public final class UserCredentialsEntity extends BaseSqlEntity<UserCredentials>
|
|||||||
@Column(name = ModelConstants.USER_CREDENTIALS_RESET_TOKEN_PROPERTY, unique = true)
|
@Column(name = ModelConstants.USER_CREDENTIALS_RESET_TOKEN_PROPERTY, unique = true)
|
||||||
private String resetToken;
|
private String resetToken;
|
||||||
|
|
||||||
|
@Type(type = "json")
|
||||||
|
@Column(name = ModelConstants.ADDITIONAL_INFO_PROPERTY)
|
||||||
|
private JsonNode additionalInfo;
|
||||||
|
|
||||||
public UserCredentialsEntity() {
|
public UserCredentialsEntity() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@ -66,6 +75,7 @@ public final class UserCredentialsEntity extends BaseSqlEntity<UserCredentials>
|
|||||||
this.password = userCredentials.getPassword();
|
this.password = userCredentials.getPassword();
|
||||||
this.activateToken = userCredentials.getActivateToken();
|
this.activateToken = userCredentials.getActivateToken();
|
||||||
this.resetToken = userCredentials.getResetToken();
|
this.resetToken = userCredentials.getResetToken();
|
||||||
|
this.additionalInfo = userCredentials.getAdditionalInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -79,6 +89,7 @@ public final class UserCredentialsEntity extends BaseSqlEntity<UserCredentials>
|
|||||||
userCredentials.setPassword(password);
|
userCredentials.setPassword(password);
|
||||||
userCredentials.setActivateToken(activateToken);
|
userCredentials.setActivateToken(activateToken);
|
||||||
userCredentials.setResetToken(resetToken);
|
userCredentials.setResetToken(resetToken);
|
||||||
|
userCredentials.setAdditionalInfo(additionalInfo);
|
||||||
return userCredentials;
|
return userCredentials;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -370,7 +370,8 @@ CREATE TABLE IF NOT EXISTS user_credentials (
|
|||||||
enabled boolean,
|
enabled boolean,
|
||||||
password varchar(255),
|
password varchar(255),
|
||||||
reset_token varchar(255) UNIQUE,
|
reset_token varchar(255) UNIQUE,
|
||||||
user_id uuid UNIQUE
|
user_id uuid UNIQUE,
|
||||||
|
additional_info varchar
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS widget_type (
|
CREATE TABLE IF NOT EXISTS widget_type (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user