Merge branch 'develop/3.5' of github.com:thingsboard/thingsboard into develop/3.5
This commit is contained in:
commit
9c388c5135
@ -30,3 +30,12 @@ CREATE TABLE IF NOT EXISTS user_settings (
|
|||||||
settings varchar(100000),
|
settings varchar(100000),
|
||||||
CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES tb_user(id) ON DELETE CASCADE
|
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';
|
||||||
@ -228,8 +228,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
|
|||||||
|
|
||||||
if (userCredentials != null && isPositiveInteger(passwordPolicy.getPasswordReuseFrequencyDays())) {
|
if (userCredentials != null && isPositiveInteger(passwordPolicy.getPasswordReuseFrequencyDays())) {
|
||||||
long passwordReuseFrequencyTs = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(passwordPolicy.getPasswordReuseFrequencyDays());
|
long passwordReuseFrequencyTs = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(passwordPolicy.getPasswordReuseFrequencyDays());
|
||||||
User user = userService.findUserById(tenantId, userCredentials.getUserId());
|
JsonNode additionalInfo = userCredentials.getAdditionalInfo();
|
||||||
JsonNode additionalInfo = user.getAdditionalInfo();
|
|
||||||
if (additionalInfo instanceof ObjectNode && additionalInfo.has(UserServiceImpl.USER_PASSWORD_HISTORY)) {
|
if (additionalInfo instanceof ObjectNode && additionalInfo.has(UserServiceImpl.USER_PASSWORD_HISTORY)) {
|
||||||
JsonNode userPasswordHistoryJson = additionalInfo.get(UserServiceImpl.USER_PASSWORD_HISTORY);
|
JsonNode userPasswordHistoryJson = additionalInfo.get(UserServiceImpl.USER_PASSWORD_HISTORY);
|
||||||
Map<String, String> userPasswordHistoryMap = JacksonUtil.convertValue(userPasswordHistoryJson, new TypeReference<>() {});
|
Map<String, String> userPasswordHistoryMap = JacksonUtil.convertValue(userPasswordHistoryJson, new TypeReference<>() {});
|
||||||
|
|||||||
@ -15,10 +15,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.common.data.security;
|
package org.thingsboard.server.common.data.security;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.thingsboard.server.common.data.BaseData;
|
import org.thingsboard.server.common.data.BaseData;
|
||||||
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.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)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class UserCredentials extends BaseData<UserCredentialsId> {
|
public class UserCredentials extends BaseData<UserCredentialsId> {
|
||||||
@ -30,6 +40,20 @@ public class UserCredentials extends BaseData<UserCredentialsId> {
|
|||||||
private String password;
|
private String password;
|
||||||
private String activateToken;
|
private String activateToken;
|
||||||
private String resetToken;
|
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() {
|
public UserCredentials() {
|
||||||
super();
|
super();
|
||||||
@ -46,6 +70,7 @@ public class UserCredentials extends BaseData<UserCredentialsId> {
|
|||||||
this.enabled = userCredentials.isEnabled();
|
this.enabled = userCredentials.isEnabled();
|
||||||
this.activateToken = userCredentials.getActivateToken();
|
this.activateToken = userCredentials.getActivateToken();
|
||||||
this.resetToken = userCredentials.getResetToken();
|
this.resetToken = userCredentials.getResetToken();
|
||||||
|
setAdditionalInfo(userCredentials.getAdditionalInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserId getUserId() {
|
public UserId getUserId() {
|
||||||
|
|||||||
@ -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_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_ACTIVATE_TOKEN_PROPERTY = "activate_token";
|
||||||
public static final String USER_CREDENTIALS_RESET_TOKEN_PROPERTY = "reset_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_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";
|
public static final String USER_CREDENTIALS_BY_ACTIVATE_TOKEN_COLUMN_FAMILY_NAME = "user_credentials_by_activate_token";
|
||||||
|
|||||||
@ -15,8 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
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.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;
|
||||||
@ -50,6 +52,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.USER_CREDENTIALS_ADDITIONAL_PROPERTY)
|
||||||
|
private JsonNode additionalInfo;
|
||||||
|
|
||||||
public UserCredentialsEntity() {
|
public UserCredentialsEntity() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@ -66,6 +72,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 +86,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -127,7 +127,8 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
|
|||||||
userCredentials.setEnabled(false);
|
userCredentials.setEnabled(false);
|
||||||
userCredentials.setActivateToken(generateSafeToken(DEFAULT_TOKEN_LENGTH));
|
userCredentials.setActivateToken(generateSafeToken(DEFAULT_TOKEN_LENGTH));
|
||||||
userCredentials.setUserId(new UserId(savedUser.getUuidId()));
|
userCredentials.setUserId(new UserId(savedUser.getUuidId()));
|
||||||
saveUserCredentialsAndPasswordHistory(user.getTenantId(), userCredentials);
|
userCredentials.setAdditionalInfo(JacksonUtil.newObjectNode());
|
||||||
|
userCredentialsDao.save(user.getTenantId(), userCredentials);
|
||||||
}
|
}
|
||||||
return savedUser;
|
return savedUser;
|
||||||
}
|
}
|
||||||
@ -157,7 +158,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
|
|||||||
public UserCredentials saveUserCredentials(TenantId tenantId, UserCredentials userCredentials) {
|
public UserCredentials saveUserCredentials(TenantId tenantId, UserCredentials userCredentials) {
|
||||||
log.trace("Executing saveUserCredentials [{}]", userCredentials);
|
log.trace("Executing saveUserCredentials [{}]", userCredentials);
|
||||||
userCredentialsValidator.validate(userCredentials, data -> tenantId);
|
userCredentialsValidator.validate(userCredentials, data -> tenantId);
|
||||||
return saveUserCredentialsAndPasswordHistory(tenantId, userCredentials);
|
return userCredentialsDao.save(tenantId, userCredentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -175,7 +176,9 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
|
|||||||
userCredentials.setEnabled(true);
|
userCredentials.setEnabled(true);
|
||||||
userCredentials.setActivateToken(null);
|
userCredentials.setActivateToken(null);
|
||||||
userCredentials.setPassword(password);
|
userCredentials.setPassword(password);
|
||||||
|
if (userCredentials.getPassword() != null) {
|
||||||
|
updatePasswordHistory(userCredentials);
|
||||||
|
}
|
||||||
return saveUserCredentials(tenantId, userCredentials);
|
return saveUserCredentials(tenantId, userCredentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +214,10 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
|
|||||||
userCredentialsValidator.validate(userCredentials, data -> tenantId);
|
userCredentialsValidator.validate(userCredentials, data -> tenantId);
|
||||||
userCredentialsDao.removeById(tenantId, userCredentials.getUuidId());
|
userCredentialsDao.removeById(tenantId, userCredentials.getUuidId());
|
||||||
userCredentials.setId(null);
|
userCredentials.setId(null);
|
||||||
return saveUserCredentialsAndPasswordHistory(tenantId, userCredentials);
|
if (userCredentials.getPassword() != null) {
|
||||||
|
updatePasswordHistory(userCredentials);
|
||||||
|
}
|
||||||
|
return userCredentialsDao.save(tenantId, userCredentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -342,17 +348,8 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
|
|||||||
return failedLoginAttempts;
|
return failedLoginAttempts;
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserCredentials saveUserCredentialsAndPasswordHistory(TenantId tenantId, UserCredentials userCredentials) {
|
private void updatePasswordHistory(UserCredentials userCredentials) {
|
||||||
UserCredentials result = userCredentialsDao.save(tenantId, userCredentials);
|
JsonNode additionalInfo = userCredentials.getAdditionalInfo();
|
||||||
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();
|
|
||||||
if (!(additionalInfo instanceof ObjectNode)) {
|
if (!(additionalInfo instanceof ObjectNode)) {
|
||||||
additionalInfo = JacksonUtil.newObjectNode();
|
additionalInfo = JacksonUtil.newObjectNode();
|
||||||
}
|
}
|
||||||
@ -373,8 +370,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
|
|||||||
userPasswordHistoryJson = JacksonUtil.valueToTree(userPasswordHistoryMap);
|
userPasswordHistoryJson = JacksonUtil.valueToTree(userPasswordHistoryMap);
|
||||||
((ObjectNode) additionalInfo).set(USER_PASSWORD_HISTORY, userPasswordHistoryJson);
|
((ObjectNode) additionalInfo).set(USER_PASSWORD_HISTORY, userPasswordHistoryJson);
|
||||||
}
|
}
|
||||||
user.setAdditionalInfo(additionalInfo);
|
userCredentials.setAdditionalInfo(additionalInfo);
|
||||||
saveUser(user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final PaginatedRemover<TenantId, User> tenantAdminsRemover = new PaginatedRemover<>() {
|
private final PaginatedRemover<TenantId, User> tenantAdminsRemover = new PaginatedRemover<>() {
|
||||||
|
|||||||
@ -487,7 +487,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 DEFAULT '{}'
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS widget_type (
|
CREATE TABLE IF NOT EXISTS widget_type (
|
||||||
|
|||||||
@ -137,7 +137,7 @@ public class TbMsgGeneratorNode implements TbNode {
|
|||||||
}
|
}
|
||||||
lastScheduledTs = lastScheduledTs + delay;
|
lastScheduledTs = lastScheduledTs + delay;
|
||||||
long curDelay = Math.max(0L, (lastScheduledTs - curTs));
|
long curDelay = Math.max(0L, (lastScheduledTs - curTs));
|
||||||
TbMsg tickMsg = ctx.newMsg(null, TB_MSG_GENERATOR_NODE_MSG, ctx.getSelfId(), new TbMsgMetaData(), "");
|
TbMsg tickMsg = ctx.newMsg(config.getQueueName(), TB_MSG_GENERATOR_NODE_MSG, ctx.getSelfId(), new TbMsgMetaData(), "");
|
||||||
nextTickId = tickMsg.getId();
|
nextTickId = tickMsg.getId();
|
||||||
ctx.tellSelf(tickMsg, curDelay);
|
ctx.tellSelf(tickMsg, curDelay);
|
||||||
}
|
}
|
||||||
@ -145,14 +145,14 @@ public class TbMsgGeneratorNode implements TbNode {
|
|||||||
private ListenableFuture<TbMsg> generate(TbContext ctx, TbMsg msg) {
|
private ListenableFuture<TbMsg> generate(TbContext ctx, TbMsg msg) {
|
||||||
log.trace("generate, config {}", config);
|
log.trace("generate, config {}", config);
|
||||||
if (prevMsg == null) {
|
if (prevMsg == null) {
|
||||||
prevMsg = ctx.newMsg(null, "", originatorId, msg.getCustomerId(), new TbMsgMetaData(), "{}");
|
prevMsg = ctx.newMsg(config.getQueueName(), "", originatorId, msg.getCustomerId(), new TbMsgMetaData(), "{}");
|
||||||
}
|
}
|
||||||
if (initialized.get()) {
|
if (initialized.get()) {
|
||||||
ctx.logJsEvalRequest();
|
ctx.logJsEvalRequest();
|
||||||
return Futures.transformAsync(scriptEngine.executeGenerateAsync(prevMsg), generated -> {
|
return Futures.transformAsync(scriptEngine.executeGenerateAsync(prevMsg), generated -> {
|
||||||
log.trace("generate process response, generated {}, config {}", generated, config);
|
log.trace("generate process response, generated {}, config {}", generated, config);
|
||||||
ctx.logJsEvalResponse();
|
ctx.logJsEvalResponse();
|
||||||
prevMsg = ctx.newMsg(null, generated.getType(), originatorId, msg.getCustomerId(), generated.getMetaData(), generated.getData());
|
prevMsg = ctx.newMsg(config.getQueueName(), generated.getType(), originatorId, msg.getCustomerId(), generated.getMetaData(), generated.getData());
|
||||||
return Futures.immediateFuture(prevMsg);
|
return Futures.immediateFuture(prevMsg);
|
||||||
}, MoreExecutors.directExecutor()); //usually it runs on js-executor-remote-callback thread pool
|
}, MoreExecutors.directExecutor()); //usually it runs on js-executor-remote-callback thread pool
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,7 @@ public class TbMsgGeneratorNodeConfiguration implements NodeConfiguration<TbMsgG
|
|||||||
private ScriptLanguage scriptLang;
|
private ScriptLanguage scriptLang;
|
||||||
private String jsScript;
|
private String jsScript;
|
||||||
private String tbelScript;
|
private String tbelScript;
|
||||||
|
private String queueName;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TbMsgGeneratorNodeConfiguration defaultConfiguration() {
|
public TbMsgGeneratorNodeConfiguration defaultConfiguration() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user