Browse Source

Merge pull request #8110 from dashevchenko/passwordHistoryTable

Moved password history from tb_user to user_credentials
pull/8175/head
Andrew Shvayka 3 years ago
committed by GitHub
parent
commit
07d985f20f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      application/src/main/data/upgrade/3.4.4/schema_update.sql
  2. 3
      application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java
  3. 25
      common/data/src/main/java/org/thingsboard/server/common/data/security/UserCredentials.java
  4. 1
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  5. 8
      dao/src/main/java/org/thingsboard/server/dao/model/sql/UserCredentialsEntity.java
  6. 30
      dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java
  7. 3
      dao/src/main/resources/sql/schema-entities.sql

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

@ -30,3 +30,12 @@ CREATE TABLE IF NOT EXISTS user_settings (
settings varchar(100000),
CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES tb_user(id) ON DELETE CASCADE
);
ALTER TABLE user_credentials
ADD COLUMN IF NOT EXISTS additional_info varchar NOT NULL DEFAULT '{}';
UPDATE user_credentials
SET additional_info = json_build_object('userPasswordHistory', (u.additional_info::json -> 'userPasswordHistory'))
FROM tb_user u WHERE user_credentials.user_id = u.id AND u.additional_info::jsonb ? 'userPasswordHistory';
UPDATE tb_user SET additional_info = tb_user.additional_info::jsonb - 'userPasswordHistory';

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<>() {});

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

@ -15,10 +15,20 @@
*/
package org.thingsboard.server.common.data.security;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.id.UserCredentialsId;
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> {
@ -30,6 +40,20 @@ public class UserCredentials extends BaseData<UserCredentialsId> {
private String password;
private String activateToken;
private String resetToken;
@NoXss
private transient JsonNode additionalInfo;
@JsonIgnore
private byte[] additionalInfoBytes;
public JsonNode getAdditionalInfo() {
return getJson(() -> additionalInfo, () -> additionalInfoBytes);
}
public void setAdditionalInfo(JsonNode settings) {
setJson(settings, json -> this.additionalInfo = json, bytes -> this.additionalInfoBytes = bytes);
}
public UserCredentials() {
super();
@ -46,6 +70,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() {

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;
}

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

@ -127,7 +127,8 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
userCredentials.setEnabled(false);
userCredentials.setActivateToken(generateSafeToken(DEFAULT_TOKEN_LENGTH));
userCredentials.setUserId(new UserId(savedUser.getUuidId()));
saveUserCredentialsAndPasswordHistory(user.getTenantId(), userCredentials);
userCredentials.setAdditionalInfo(JacksonUtil.newObjectNode());
userCredentialsDao.save(user.getTenantId(), userCredentials);
}
return savedUser;
}
@ -157,7 +158,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
@ -175,7 +176,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);
}
@ -211,7 +214,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
@ -342,17 +348,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();
}
@ -373,8 +370,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 DEFAULT '{}'
);
CREATE TABLE IF NOT EXISTS widget_type (

Loading…
Cancel
Save