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();
|
||||
|
||||
void reloadJwtSettings();
|
||||
|
||||
void createJwtAdminSettings();
|
||||
|
||||
JwtSettings saveJwtSettings(JwtSettings jwtSettings);
|
||||
|
||||
@ -19,7 +19,10 @@ import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.server.cluster.TbClusterService;
|
||||
@ -33,6 +36,7 @@ import javax.validation.ValidationException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@ -42,24 +46,37 @@ public class JwtSettingsServiceDefault implements JwtSettingsService {
|
||||
static final String ADMIN_SETTINGS_JWT_KEY = "jwt";
|
||||
static final String TOKEN_SIGNING_KEY_DEFAULT = "thingsboardDefaultSigningKey";
|
||||
static final String TB_ALLOW_DEFAULT_JWT_SIGNING_KEY = "TB_ALLOW_DEFAULT_JWT_SIGNING_KEY";
|
||||
|
||||
@Lazy
|
||||
private final AdminSettingsService adminSettingsService;
|
||||
private final TbClusterService tbClusterService;
|
||||
|
||||
@Lazy
|
||||
private final Optional<TbClusterService> tbClusterService;
|
||||
private final JwtSettingsValidator jwtSettingsValidator;
|
||||
|
||||
private final Environment environment;
|
||||
@Getter
|
||||
private final JwtSettings jwtSettings;
|
||||
@Value("${install.upgrade:false}")
|
||||
private boolean isUpgrade;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
reloadJwtSettings();
|
||||
if (!isFirstInstall()) {
|
||||
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();
|
||||
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.setRefreshTokenExpTime(jwtLoaded.getRefreshTokenExpTime());
|
||||
jwtSettings.setTokenExpirationTime(jwtLoaded.getTokenExpirationTime());
|
||||
@ -67,7 +84,7 @@ public class JwtSettingsServiceDefault implements JwtSettingsService {
|
||||
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");
|
||||
}
|
||||
}
|
||||
@ -107,12 +124,20 @@ public class JwtSettingsServiceDefault implements JwtSettingsService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtSettings saveJwtSettings(JwtSettings jwtSettings){
|
||||
public JwtSettings saveJwtSettings(JwtSettings 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");
|
||||
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();
|
||||
return getJwtSettings();
|
||||
}
|
||||
@ -122,12 +147,7 @@ public class JwtSettingsServiceDefault implements JwtSettingsService {
|
||||
}
|
||||
|
||||
AdminSettings findJwtAdminSettings() {
|
||||
try {
|
||||
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;
|
||||
}
|
||||
return adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, ADMIN_SETTINGS_JWT_KEY);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -22,6 +22,7 @@ import com.google.common.util.concurrent.MoreExecutors;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
@ -68,6 +69,7 @@ public class AdminController extends BaseController {
|
||||
@Autowired
|
||||
private SystemSecurityService systemSecurityService;
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
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.rpc.FromDeviceRpcResponse;
|
||||
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.dao.tenant.TbTenantProfileCache;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
@ -143,8 +144,9 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
|
||||
EdgeNotificationService edgeNotificationService,
|
||||
OtaPackageStateService firmwareStateService,
|
||||
GitVersionControlQueueService vcQueueService,
|
||||
PartitionService partitionService) {
|
||||
super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer());
|
||||
PartitionService partitionService,
|
||||
Optional<JwtSettingsService> jwtSettingsService) {
|
||||
super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer(), jwtSettingsService);
|
||||
this.mainConsumer = tbCoreQueueFactory.createToCoreMsgConsumer();
|
||||
this.usageStatsConsumer = tbCoreQueueFactory.createToUsageStatsServiceMsgConsumer();
|
||||
this.firmwareStatesConsumer = tbCoreQueueFactory.createToOtaPackageStateServiceMsgConsumer();
|
||||
|
||||
@ -70,6 +70,7 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@ -126,7 +127,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
|
||||
TbTenantProfileCache tenantProfileCache,
|
||||
TbApiUsageStateService apiUsageStateService,
|
||||
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.tbRuleEngineQueueFactory = tbRuleEngineQueueFactory;
|
||||
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.queue.ServiceType;
|
||||
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.queue.TbQueueConsumer;
|
||||
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 TbQueueConsumer<TbProtoQueueMsg<N>> nfConsumer;
|
||||
protected final Optional<JwtSettingsService> jwtSettingsService;
|
||||
|
||||
|
||||
public AbstractConsumerService(ActorSystemContext actorContext, DataDecodingEncodingService encodingService,
|
||||
TbTenantProfileCache tenantProfileCache, TbDeviceProfileCache deviceProfileCache,
|
||||
TbAssetProfileCache assetProfileCache, TbApiUsageStateService apiUsageStateService,
|
||||
PartitionService partitionService, TbQueueConsumer<TbProtoQueueMsg<N>> nfConsumer) {
|
||||
PartitionService partitionService, TbQueueConsumer<TbProtoQueueMsg<N>> nfConsumer, Optional<JwtSettingsService> jwtSettingsService) {
|
||||
this.actorContext = actorContext;
|
||||
this.encodingService = encodingService;
|
||||
this.tenantProfileCache = tenantProfileCache;
|
||||
@ -89,6 +92,7 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
|
||||
this.apiUsageStateService = apiUsageStateService;
|
||||
this.partitionService = partitionService;
|
||||
this.nfConsumer = nfConsumer;
|
||||
this.jwtSettingsService = jwtSettingsService;
|
||||
}
|
||||
|
||||
public void init(String mainConsumerThreadName, String nfConsumerThreadName) {
|
||||
@ -172,12 +176,16 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
|
||||
apiUsageStateService.onTenantProfileUpdate(tenantProfileId);
|
||||
}
|
||||
} else if (EntityType.TENANT.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
|
||||
tenantProfileCache.evict(componentLifecycleMsg.getTenantId());
|
||||
partitionService.removeTenant(componentLifecycleMsg.getTenantId());
|
||||
if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.UPDATED)) {
|
||||
apiUsageStateService.onTenantUpdate(componentLifecycleMsg.getTenantId());
|
||||
} else if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.DELETED)) {
|
||||
apiUsageStateService.onTenantDelete((TenantId) componentLifecycleMsg.getEntityId());
|
||||
if (TenantId.SYS_TENANT_ID.equals(componentLifecycleMsg.getTenantId())) {
|
||||
jwtSettingsService.ifPresent(JwtSettingsService::reloadJwtSettings);
|
||||
} else {
|
||||
tenantProfileCache.evict(componentLifecycleMsg.getTenantId());
|
||||
partitionService.removeTenant(componentLifecycleMsg.getTenantId());
|
||||
if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.UPDATED)) {
|
||||
apiUsageStateService.onTenantUpdate(componentLifecycleMsg.getTenantId());
|
||||
} else if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.DELETED)) {
|
||||
apiUsageStateService.onTenantDelete((TenantId) componentLifecycleMsg.getEntityId());
|
||||
}
|
||||
}
|
||||
} else if (EntityType.DEVICE_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
|
||||
deviceProfileCache.evict(componentLifecycleMsg.getTenantId(), new DeviceProfileId(componentLifecycleMsg.getEntityId().getId()));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user