Browse Source

moved password history from tb_user to user_credential

pull/8110/head
dashevchenko 3 years ago
parent
commit
f5b029d43e
  1. 9
      application/src/main/data/upgrade/3.4.4/schema_update.sql
  2. 31
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
  3. 3
      application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java
  4. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java
  5. 23
      common/data/src/main/java/org/thingsboard/server/common/data/security/UserCredentials.java
  6. 1
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  7. 8
      dao/src/main/java/org/thingsboard/server/dao/model/sql/UserCredentialsEntity.java
  8. 7
      dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java
  9. 8
      dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java
  10. 40
      dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java
  11. 3
      dao/src/main/resources/sql/schema-entities.sql

9
application/src/main/data/upgrade/3.4.4/schema_update.sql

@ -32,11 +32,4 @@ CREATE TABLE IF NOT EXISTS user_settings (
);
ALTER TABLE user_credentials
ADD COLUMN IF NOT EXISTS additional_info varchar;
UPDATE user_credentials AS c
SET additional_info = u.additional_info FROM tb_user AS u
WHERE u.id = c.user_id AND u.additional_info is not null;
UPDATE tb_user
SET additional_info = null WHERE id is not null;
ADD COLUMN IF NOT EXISTS additional_info varchar NULL;

31
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.service.install;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
@ -24,8 +26,10 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
@ -34,6 +38,7 @@ import org.thingsboard.server.common.data.queue.ProcessingStrategyType;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.data.queue.SubmitStrategy;
import org.thingsboard.server.common.data.queue.SubmitStrategyType;
import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.dao.asset.AssetDao;
import org.thingsboard.server.dao.asset.AssetProfileService;
import org.thingsboard.server.dao.dashboard.DashboardService;
@ -44,6 +49,7 @@ import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.sql.tenant.TenantRepository;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.usagerecord.ApiUsageStateService;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration;
import org.thingsboard.server.service.install.sql.SqlDbHelper;
@ -110,6 +116,9 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
@Autowired
private TenantService tenantService;
@Autowired
private UserService userService;
@Autowired
private TenantRepository tenantRepository;
@ -701,6 +710,28 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
} catch (Exception e) {
}
PageLink pageLink = new PageLink(1000);
PageData<User> users;
do {
List<ListenableFuture<?>> futures = new ArrayList<>();
users = userService.findAllUsers(pageLink);
for (User user : users.getData()) {
futures.add(dbUpgradeExecutor.submit(() -> {
JsonNode additionalInfo = user.getAdditionalInfo();
if (additionalInfo.isObject() && additionalInfo.has("userPasswordHistory")){
UserCredentials creds = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
if (creds != null) {
creds.setAdditionalInfo(JacksonUtil.newObjectNode().set("userPasswordHistory", additionalInfo.get("userPasswordHistory")));
userService.saveUserCredentials(user.getTenantId(), creds);
}
((ObjectNode) additionalInfo).remove("userPasswordHistory");
userService.saveUser(user);
}}));
}
Futures.allAsList(futures).get();
pageLink = pageLink.nextPageLink();
} while (users.hasNext());
conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3005000;");
}
log.info("Schema updated.");

3
application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java

@ -228,8 +228,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
if (userCredentials != null && isPositiveInteger(passwordPolicy.getPasswordReuseFrequencyDays())) {
long passwordReuseFrequencyTs = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(passwordPolicy.getPasswordReuseFrequencyDays());
User user = userService.findUserById(tenantId, userCredentials.getUserId());
JsonNode additionalInfo = user.getAdditionalInfo();
JsonNode additionalInfo = userCredentials.getAdditionalInfo();
if (additionalInfo instanceof ObjectNode && additionalInfo.has(UserServiceImpl.USER_PASSWORD_HISTORY)) {
JsonNode userPasswordHistoryJson = additionalInfo.get(UserServiceImpl.USER_PASSWORD_HISTORY);
Map<String, String> userPasswordHistoryMap = JacksonUtil.convertValue(userPasswordHistoryJson, new TypeReference<>() {});

2
common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java

@ -58,6 +58,8 @@ public interface UserService extends EntityDaoService {
PageData<User> findUsersByTenantId(TenantId tenantId, PageLink pageLink);
PageData<User> findAllUsers(PageLink pageLink);
PageData<User> findTenantAdmins(TenantId tenantId, PageLink pageLink);
void deleteTenantAdmins(TenantId tenantId);

23
common/data/src/main/java/org/thingsboard/server/common/data/security/UserCredentials.java

@ -24,10 +24,12 @@ import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.validation.Length;
import org.thingsboard.server.common.data.validation.NoXss;
import java.util.Arrays;
import java.util.Objects;
import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.getJson;
import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.setJson;
@EqualsAndHashCode(callSuper = true)
public class UserCredentials extends BaseData<UserCredentialsId> {
private static final long serialVersionUID = -2108436378880529163L;
@ -67,6 +69,7 @@ public class UserCredentials extends BaseData<UserCredentialsId> {
this.enabled = userCredentials.isEnabled();
this.activateToken = userCredentials.getActivateToken();
this.resetToken = userCredentials.getResetToken();
setAdditionalInfo(userCredentials.getAdditionalInfo());
}
public UserId getUserId() {
@ -109,6 +112,24 @@ public class UserCredentials extends BaseData<UserCredentialsId> {
this.resetToken = resetToken;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
UserCredentials that = (UserCredentials) o;
return enabled == that.enabled && userId.equals(that.userId) && Objects.equals(password, that.password)
&& Objects.equals(activateToken, that.activateToken) && Objects.equals(resetToken, that.resetToken)
&& Arrays.equals(additionalInfoBytes, that.additionalInfoBytes);
}
@Override
public int hashCode() {
int result = Objects.hash(super.hashCode(), userId, enabled, password, activateToken, resetToken);
result = 31 * result + Arrays.hashCode(additionalInfoBytes);
return result;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();

1
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -81,6 +81,7 @@ public class ModelConstants {
public static final String USER_CREDENTIALS_PASSWORD_PROPERTY = "password"; //NOSONAR, the constant used to identify password column name (not password value itself)
public static final String USER_CREDENTIALS_ACTIVATE_TOKEN_PROPERTY = "activate_token";
public static final String USER_CREDENTIALS_RESET_TOKEN_PROPERTY = "reset_token";
public static final String USER_CREDENTIALS_ADDITIONAL_PROPERTY = "additional_info";
public static final String USER_CREDENTIALS_BY_USER_COLUMN_FAMILY_NAME = "user_credentials_by_user";
public static final String USER_CREDENTIALS_BY_ACTIVATE_TOKEN_COLUMN_FAMILY_NAME = "user_credentials_by_activate_token";

8
dao/src/main/java/org/thingsboard/server/dao/model/sql/UserCredentialsEntity.java

@ -15,8 +15,10 @@
*/
package org.thingsboard.server.dao.model.sql;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Type;
import org.thingsboard.server.common.data.id.UserCredentialsId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.security.UserCredentials;
@ -50,6 +52,10 @@ public final class UserCredentialsEntity extends BaseSqlEntity<UserCredentials>
@Column(name = ModelConstants.USER_CREDENTIALS_RESET_TOKEN_PROPERTY, unique = true)
private String resetToken;
@Type(type = "json")
@Column(name = ModelConstants.USER_CREDENTIALS_ADDITIONAL_PROPERTY)
private JsonNode additionalInfo;
public UserCredentialsEntity() {
super();
}
@ -66,6 +72,7 @@ public final class UserCredentialsEntity extends BaseSqlEntity<UserCredentials>
this.password = userCredentials.getPassword();
this.activateToken = userCredentials.getActivateToken();
this.resetToken = userCredentials.getResetToken();
this.additionalInfo = userCredentials.getAdditionalInfo();
}
@Override
@ -79,6 +86,7 @@ public final class UserCredentialsEntity extends BaseSqlEntity<UserCredentials>
userCredentials.setPassword(password);
userCredentials.setActivateToken(activateToken);
userCredentials.setResetToken(resetToken);
userCredentials.setAdditionalInfo(additionalInfo);
return userCredentials;
}

7
dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java

@ -75,6 +75,13 @@ public class JpaUserDao extends JpaAbstractSearchTextDao<UserEntity, User> imple
DaoUtil.toPageable(pageLink)));
}
@Override
public PageData<User> findAll(PageLink pageLink) {
return DaoUtil.toPageData(
userRepository
.findAll(DaoUtil.toPageable(pageLink)));
}
@Override
public PageData<User> findTenantAdmins(UUID tenantId, PageLink pageLink) {
return DaoUtil.toPageData(

8
dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java

@ -60,6 +60,14 @@ public interface UserDao extends Dao<User>, TenantEntityDao {
*/
PageData<User> findByTenantId(UUID tenantId, PageLink pageLink);
/**
* Find users by page link.
*
* @param pageLink the page link
* @return the list of user entities
*/
PageData<User> findAll(PageLink pageLink);
/**
* Find tenant admin users by tenantId and page link.
*

40
dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java

@ -40,7 +40,6 @@ import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.common.data.security.UserSettings;
import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
@ -128,7 +127,10 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
userCredentials.setEnabled(false);
userCredentials.setActivateToken(StringUtils.randomAlphanumeric(DEFAULT_TOKEN_LENGTH));
userCredentials.setUserId(new UserId(savedUser.getUuidId()));
saveUserCredentialsAndPasswordHistory(user.getTenantId(), userCredentials);
if (userCredentials.getPassword() != null) {
updatePasswordHistory(userCredentials);
}
userCredentialsDao.save(user.getTenantId(), userCredentials);
}
return savedUser;
}
@ -158,7 +160,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
public UserCredentials saveUserCredentials(TenantId tenantId, UserCredentials userCredentials) {
log.trace("Executing saveUserCredentials [{}]", userCredentials);
userCredentialsValidator.validate(userCredentials, data -> tenantId);
return saveUserCredentialsAndPasswordHistory(tenantId, userCredentials);
return userCredentialsDao.save(tenantId, userCredentials);
}
@Override
@ -176,7 +178,9 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
userCredentials.setEnabled(true);
userCredentials.setActivateToken(null);
userCredentials.setPassword(password);
if (userCredentials.getPassword() != null) {
updatePasswordHistory(userCredentials);
}
return saveUserCredentials(tenantId, userCredentials);
}
@ -212,7 +216,10 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
userCredentialsValidator.validate(userCredentials, data -> tenantId);
userCredentialsDao.removeById(tenantId, userCredentials.getUuidId());
userCredentials.setId(null);
return saveUserCredentialsAndPasswordHistory(tenantId, userCredentials);
if (userCredentials.getPassword() != null) {
updatePasswordHistory(userCredentials);
}
return userCredentialsDao.save(tenantId, userCredentials);
}
@Override
@ -236,6 +243,13 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
return userDao.findByTenantId(tenantId.getId(), pageLink);
}
@Override
public PageData<User> findAllUsers(PageLink pageLink) {
log.trace("Executing findAllUsers, pageLink [{}]", pageLink);
validatePageLink(pageLink);
return userDao.findAll(pageLink);
}
@Override
public PageData<User> findTenantAdmins(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findTenantAdmins, tenantId [{}], pageLink [{}]", tenantId, pageLink);
@ -343,17 +357,8 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
return failedLoginAttempts;
}
private UserCredentials saveUserCredentialsAndPasswordHistory(TenantId tenantId, UserCredentials userCredentials) {
UserCredentials result = userCredentialsDao.save(tenantId, userCredentials);
User user = findUserById(tenantId, userCredentials.getUserId());
if (userCredentials.getPassword() != null) {
updatePasswordHistory(user, userCredentials);
}
return result;
}
private void updatePasswordHistory(User user, UserCredentials userCredentials) {
JsonNode additionalInfo = user.getAdditionalInfo();
private void updatePasswordHistory(UserCredentials userCredentials) {
JsonNode additionalInfo = userCredentials.getAdditionalInfo();
if (!(additionalInfo instanceof ObjectNode)) {
additionalInfo = JacksonUtil.newObjectNode();
}
@ -374,8 +379,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
userPasswordHistoryJson = JacksonUtil.valueToTree(userPasswordHistoryMap);
((ObjectNode) additionalInfo).set(USER_PASSWORD_HISTORY, userPasswordHistoryJson);
}
user.setAdditionalInfo(additionalInfo);
saveUser(user);
userCredentials.setAdditionalInfo(additionalInfo);
}
private final PaginatedRemover<TenantId, User> tenantAdminsRemover = new PaginatedRemover<>() {

3
dao/src/main/resources/sql/schema-entities.sql

@ -487,7 +487,8 @@ CREATE TABLE IF NOT EXISTS user_credentials (
enabled boolean,
password varchar(255),
reset_token varchar(255) UNIQUE,
user_id uuid UNIQUE
user_id uuid UNIQUE,
additional_info varchar
);
CREATE TABLE IF NOT EXISTS widget_type (

Loading…
Cancel
Save