JwtSettingsService workout: Lazy and Optional clusterService, correctness on first Install and upgrade, reload JWT on cluster notification, update jwt settings using existing id
This commit is contained in:
parent
7186632e5a
commit
1a9b8a1ebe
@ -19,6 +19,8 @@ public interface JwtSettingsService {
|
|||||||
|
|
||||||
JwtSettings getJwtSettings();
|
JwtSettings getJwtSettings();
|
||||||
|
|
||||||
|
void reloadJwtSettings();
|
||||||
|
|
||||||
void createJwtAdminSettings();
|
void createJwtAdminSettings();
|
||||||
|
|
||||||
JwtSettings saveJwtSettings(JwtSettings jwtSettings);
|
JwtSettings saveJwtSettings(JwtSettings jwtSettings);
|
||||||
|
|||||||
@ -19,7 +19,10 @@ import lombok.Getter;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.core.env.Profiles;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.thingsboard.common.util.JacksonUtil;
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
import org.thingsboard.server.cluster.TbClusterService;
|
import org.thingsboard.server.cluster.TbClusterService;
|
||||||
@ -33,6 +36,7 @@ import javax.validation.ValidationException;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@ -42,24 +46,37 @@ public class JwtSettingsServiceDefault implements JwtSettingsService {
|
|||||||
static final String ADMIN_SETTINGS_JWT_KEY = "jwt";
|
static final String ADMIN_SETTINGS_JWT_KEY = "jwt";
|
||||||
static final String TOKEN_SIGNING_KEY_DEFAULT = "thingsboardDefaultSigningKey";
|
static final String TOKEN_SIGNING_KEY_DEFAULT = "thingsboardDefaultSigningKey";
|
||||||
static final String TB_ALLOW_DEFAULT_JWT_SIGNING_KEY = "TB_ALLOW_DEFAULT_JWT_SIGNING_KEY";
|
static final String TB_ALLOW_DEFAULT_JWT_SIGNING_KEY = "TB_ALLOW_DEFAULT_JWT_SIGNING_KEY";
|
||||||
|
@Lazy
|
||||||
private final AdminSettingsService adminSettingsService;
|
private final AdminSettingsService adminSettingsService;
|
||||||
private final TbClusterService tbClusterService;
|
@Lazy
|
||||||
|
private final Optional<TbClusterService> tbClusterService;
|
||||||
private final JwtSettingsValidator jwtSettingsValidator;
|
private final JwtSettingsValidator jwtSettingsValidator;
|
||||||
|
private final Environment environment;
|
||||||
@Getter
|
@Getter
|
||||||
private final JwtSettings jwtSettings;
|
private final JwtSettings jwtSettings;
|
||||||
|
@Value("${install.upgrade:false}")
|
||||||
|
private boolean isUpgrade;
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() {
|
public void init() {
|
||||||
|
if (!isFirstInstall()) {
|
||||||
reloadJwtSettings();
|
reloadJwtSettings();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void reloadJwtSettings() {
|
private boolean isInstall() {
|
||||||
|
return environment.acceptsProfiles(Profiles.of("install"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isFirstInstall() {
|
||||||
|
return isInstall() && !isUpgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reloadJwtSettings() {
|
||||||
AdminSettings adminJwtSettings = findJwtAdminSettings();
|
AdminSettings adminJwtSettings = findJwtAdminSettings();
|
||||||
if (adminJwtSettings != null) {
|
if (adminJwtSettings != null) {
|
||||||
log.debug("Loading the JWT admin settings from database");
|
log.info("Reloading the JWT admin settings from database");
|
||||||
JwtSettings jwtLoaded = mapAdminToJwtSettings(adminJwtSettings);
|
JwtSettings jwtLoaded = mapAdminToJwtSettings(adminJwtSettings);
|
||||||
jwtSettings.setRefreshTokenExpTime(jwtLoaded.getRefreshTokenExpTime());
|
jwtSettings.setRefreshTokenExpTime(jwtLoaded.getRefreshTokenExpTime());
|
||||||
jwtSettings.setTokenExpirationTime(jwtLoaded.getTokenExpirationTime());
|
jwtSettings.setTokenExpirationTime(jwtLoaded.getTokenExpirationTime());
|
||||||
@ -67,7 +84,7 @@ public class JwtSettingsServiceDefault implements JwtSettingsService {
|
|||||||
jwtSettings.setTokenSigningKey(jwtLoaded.getTokenSigningKey());
|
jwtSettings.setTokenSigningKey(jwtLoaded.getTokenSigningKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasDefaultTokenSigningKey()) {
|
if (hasDefaultTokenSigningKey() && !isFirstInstall()) {
|
||||||
log.warn("JWT token signing key is default. This is a security issue. Please, consider to set unique value");
|
log.warn("JWT token signing key is default. This is a security issue. Please, consider to set unique value");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,12 +124,20 @@ public class JwtSettingsServiceDefault implements JwtSettingsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JwtSettings saveJwtSettings(JwtSettings jwtSettings){
|
public JwtSettings saveJwtSettings(JwtSettings jwtSettings) {
|
||||||
jwtSettingsValidator.validate(jwtSettings);
|
jwtSettingsValidator.validate(jwtSettings);
|
||||||
AdminSettings adminJwtSettings = mapJwtToAdminSettings(jwtSettings);
|
final AdminSettings adminJwtSettings = mapJwtToAdminSettings(jwtSettings);
|
||||||
|
final AdminSettings existedSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, ADMIN_SETTINGS_JWT_KEY);
|
||||||
|
if (existedSettings != null) {
|
||||||
|
adminJwtSettings.setId(existedSettings.getId());
|
||||||
|
}
|
||||||
|
|
||||||
log.info("Saving new JWT admin settings. From this moment, the JWT parameters from YAML and ENV will be ignored");
|
log.info("Saving new JWT admin settings. From this moment, the JWT parameters from YAML and ENV will be ignored");
|
||||||
adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminJwtSettings);
|
adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminJwtSettings);
|
||||||
tbClusterService.broadcastEntityStateChangeEvent(TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID, ComponentLifecycleEvent.UPDATED);
|
|
||||||
|
if (!isInstall()) {
|
||||||
|
tbClusterService.orElseThrow().broadcastEntityStateChangeEvent(TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID, ComponentLifecycleEvent.UPDATED);
|
||||||
|
}
|
||||||
reloadJwtSettings();
|
reloadJwtSettings();
|
||||||
return getJwtSettings();
|
return getJwtSettings();
|
||||||
}
|
}
|
||||||
@ -122,12 +147,7 @@ public class JwtSettingsServiceDefault implements JwtSettingsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AdminSettings findJwtAdminSettings() {
|
AdminSettings findJwtAdminSettings() {
|
||||||
try {
|
|
||||||
return adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, ADMIN_SETTINGS_JWT_KEY);
|
return adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, ADMIN_SETTINGS_JWT_KEY);
|
||||||
} catch (InvalidDataAccessResourceUsageException ignored) {
|
|
||||||
log.debug("findAdminSettingsByKey is returning InvalidDataAccessResourceUsageException. This is an installation case when the database is not initialized yet");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import com.google.common.util.concurrent.MoreExecutors;
|
|||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import io.swagger.annotations.ApiParam;
|
import io.swagger.annotations.ApiParam;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
@ -68,6 +69,7 @@ public class AdminController extends BaseController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SystemSecurityService systemSecurityService;
|
private SystemSecurityService systemSecurityService;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
@Autowired
|
@Autowired
|
||||||
private JwtSettingsService jwtSettingsService;
|
private JwtSettingsService jwtSettingsService;
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType;
|
|||||||
import org.thingsboard.server.common.msg.queue.TbCallback;
|
import org.thingsboard.server.common.msg.queue.TbCallback;
|
||||||
import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
|
import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
|
||||||
import org.thingsboard.server.common.stats.StatsFactory;
|
import org.thingsboard.server.common.stats.StatsFactory;
|
||||||
|
import org.thingsboard.server.config.jwt.JwtSettingsService;
|
||||||
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
|
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
|
||||||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
|
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
|
||||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||||
@ -143,8 +144,9 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
|
|||||||
EdgeNotificationService edgeNotificationService,
|
EdgeNotificationService edgeNotificationService,
|
||||||
OtaPackageStateService firmwareStateService,
|
OtaPackageStateService firmwareStateService,
|
||||||
GitVersionControlQueueService vcQueueService,
|
GitVersionControlQueueService vcQueueService,
|
||||||
PartitionService partitionService) {
|
PartitionService partitionService,
|
||||||
super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer());
|
Optional<JwtSettingsService> jwtSettingsService) {
|
||||||
|
super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer(), jwtSettingsService);
|
||||||
this.mainConsumer = tbCoreQueueFactory.createToCoreMsgConsumer();
|
this.mainConsumer = tbCoreQueueFactory.createToCoreMsgConsumer();
|
||||||
this.usageStatsConsumer = tbCoreQueueFactory.createToUsageStatsServiceMsgConsumer();
|
this.usageStatsConsumer = tbCoreQueueFactory.createToUsageStatsServiceMsgConsumer();
|
||||||
this.firmwareStatesConsumer = tbCoreQueueFactory.createToOtaPackageStateServiceMsgConsumer();
|
this.firmwareStatesConsumer = tbCoreQueueFactory.createToOtaPackageStateServiceMsgConsumer();
|
||||||
|
|||||||
@ -70,6 +70,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -126,7 +127,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
|
|||||||
TbTenantProfileCache tenantProfileCache,
|
TbTenantProfileCache tenantProfileCache,
|
||||||
TbApiUsageStateService apiUsageStateService,
|
TbApiUsageStateService apiUsageStateService,
|
||||||
PartitionService partitionService, TbServiceInfoProvider serviceInfoProvider, QueueService queueService) {
|
PartitionService partitionService, TbServiceInfoProvider serviceInfoProvider, QueueService queueService) {
|
||||||
super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer());
|
super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer(), Optional.empty());
|
||||||
this.statisticsService = statisticsService;
|
this.statisticsService = statisticsService;
|
||||||
this.tbRuleEngineQueueFactory = tbRuleEngineQueueFactory;
|
this.tbRuleEngineQueueFactory = tbRuleEngineQueueFactory;
|
||||||
this.submitStrategyFactory = submitStrategyFactory;
|
this.submitStrategyFactory = submitStrategyFactory;
|
||||||
|
|||||||
@ -33,6 +33,7 @@ import org.thingsboard.server.common.msg.TbActorMsg;
|
|||||||
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
|
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
|
||||||
import org.thingsboard.server.common.msg.queue.ServiceType;
|
import org.thingsboard.server.common.msg.queue.ServiceType;
|
||||||
import org.thingsboard.server.common.msg.queue.TbCallback;
|
import org.thingsboard.server.common.msg.queue.TbCallback;
|
||||||
|
import org.thingsboard.server.config.jwt.JwtSettingsService;
|
||||||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
|
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
|
||||||
import org.thingsboard.server.queue.TbQueueConsumer;
|
import org.thingsboard.server.queue.TbQueueConsumer;
|
||||||
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
|
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
|
||||||
@ -76,11 +77,13 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
|
|||||||
protected final PartitionService partitionService;
|
protected final PartitionService partitionService;
|
||||||
|
|
||||||
protected final TbQueueConsumer<TbProtoQueueMsg<N>> nfConsumer;
|
protected final TbQueueConsumer<TbProtoQueueMsg<N>> nfConsumer;
|
||||||
|
protected final Optional<JwtSettingsService> jwtSettingsService;
|
||||||
|
|
||||||
|
|
||||||
public AbstractConsumerService(ActorSystemContext actorContext, DataDecodingEncodingService encodingService,
|
public AbstractConsumerService(ActorSystemContext actorContext, DataDecodingEncodingService encodingService,
|
||||||
TbTenantProfileCache tenantProfileCache, TbDeviceProfileCache deviceProfileCache,
|
TbTenantProfileCache tenantProfileCache, TbDeviceProfileCache deviceProfileCache,
|
||||||
TbAssetProfileCache assetProfileCache, TbApiUsageStateService apiUsageStateService,
|
TbAssetProfileCache assetProfileCache, TbApiUsageStateService apiUsageStateService,
|
||||||
PartitionService partitionService, TbQueueConsumer<TbProtoQueueMsg<N>> nfConsumer) {
|
PartitionService partitionService, TbQueueConsumer<TbProtoQueueMsg<N>> nfConsumer, Optional<JwtSettingsService> jwtSettingsService) {
|
||||||
this.actorContext = actorContext;
|
this.actorContext = actorContext;
|
||||||
this.encodingService = encodingService;
|
this.encodingService = encodingService;
|
||||||
this.tenantProfileCache = tenantProfileCache;
|
this.tenantProfileCache = tenantProfileCache;
|
||||||
@ -89,6 +92,7 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
|
|||||||
this.apiUsageStateService = apiUsageStateService;
|
this.apiUsageStateService = apiUsageStateService;
|
||||||
this.partitionService = partitionService;
|
this.partitionService = partitionService;
|
||||||
this.nfConsumer = nfConsumer;
|
this.nfConsumer = nfConsumer;
|
||||||
|
this.jwtSettingsService = jwtSettingsService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(String mainConsumerThreadName, String nfConsumerThreadName) {
|
public void init(String mainConsumerThreadName, String nfConsumerThreadName) {
|
||||||
@ -172,6 +176,9 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
|
|||||||
apiUsageStateService.onTenantProfileUpdate(tenantProfileId);
|
apiUsageStateService.onTenantProfileUpdate(tenantProfileId);
|
||||||
}
|
}
|
||||||
} else if (EntityType.TENANT.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
|
} else if (EntityType.TENANT.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
|
||||||
|
if (TenantId.SYS_TENANT_ID.equals(componentLifecycleMsg.getTenantId())) {
|
||||||
|
jwtSettingsService.ifPresent(JwtSettingsService::reloadJwtSettings);
|
||||||
|
} else {
|
||||||
tenantProfileCache.evict(componentLifecycleMsg.getTenantId());
|
tenantProfileCache.evict(componentLifecycleMsg.getTenantId());
|
||||||
partitionService.removeTenant(componentLifecycleMsg.getTenantId());
|
partitionService.removeTenant(componentLifecycleMsg.getTenantId());
|
||||||
if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.UPDATED)) {
|
if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.UPDATED)) {
|
||||||
@ -179,6 +186,7 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
|
|||||||
} else if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.DELETED)) {
|
} else if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.DELETED)) {
|
||||||
apiUsageStateService.onTenantDelete((TenantId) componentLifecycleMsg.getEntityId());
|
apiUsageStateService.onTenantDelete((TenantId) componentLifecycleMsg.getEntityId());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (EntityType.DEVICE_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
|
} else if (EntityType.DEVICE_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
|
||||||
deviceProfileCache.evict(componentLifecycleMsg.getTenantId(), new DeviceProfileId(componentLifecycleMsg.getEntityId().getId()));
|
deviceProfileCache.evict(componentLifecycleMsg.getTenantId(), new DeviceProfileId(componentLifecycleMsg.getEntityId().getId()));
|
||||||
} else if (EntityType.DEVICE.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
|
} else if (EntityType.DEVICE.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user