diff --git a/application/src/main/java/org/thingsboard/server/config/JwtSettings.java b/application/src/main/java/org/thingsboard/server/config/JwtSettings.java index 95e510612a..1fc0b4bd8c 100644 --- a/application/src/main/java/org/thingsboard/server/config/JwtSettings.java +++ b/application/src/main/java/org/thingsboard/server/config/JwtSettings.java @@ -15,15 +15,30 @@ */ package org.thingsboard.server.config; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.RandomStringUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.AdminSettings; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.security.model.JwtToken; +import org.thingsboard.server.dao.settings.AdminSettingsService; + +import javax.annotation.PostConstruct; +import java.nio.charset.StandardCharsets; +import java.util.Base64; @Component @ConfigurationProperties(prefix = "security.jwt") @Data +@Slf4j public class JwtSettings { + static final String ADMIN_SETTINGS_JWT_KEY = "jwt"; + static final String TOKEN_SIGNING_KEY_DEFAULT = "thingsboardDefaultSigningKey"; /** * {@link JwtToken} will expire after this time. */ @@ -36,6 +51,7 @@ public class JwtSettings { /** * Key is used to sign {@link JwtToken}. + * Base64 encoded */ private String tokenSigningKey; @@ -44,4 +60,32 @@ public class JwtSettings { */ private Integer refreshTokenExpTime; + @JsonIgnore + @Autowired + private AdminSettingsService adminSettingsService; + + @PostConstruct + public void init() { + AdminSettings adminJwtSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, ADMIN_SETTINGS_JWT_KEY); + if (adminJwtSettings == null) { + if (TOKEN_SIGNING_KEY_DEFAULT.equals(tokenSigningKey)) { + log.warn("JWT token signing key is default. Generating a new random key"); + tokenSigningKey = Base64.getEncoder().encodeToString(RandomStringUtils.randomAlphanumeric(64).getBytes(StandardCharsets.UTF_8)); + } + adminJwtSettings = new AdminSettings(); + adminJwtSettings.setTenantId(TenantId.SYS_TENANT_ID); + adminJwtSettings.setKey(ADMIN_SETTINGS_JWT_KEY); + adminJwtSettings.setJsonValue(JacksonUtil.valueToTree(this)); + 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); + } else { + log.debug("Loading the JWT admin settings"); + JwtSettings jwtSettings = JacksonUtil.treeToValue(adminJwtSettings.getJsonValue(), JwtSettings.class); + this.setRefreshTokenExpTime(jwtSettings.getRefreshTokenExpTime()); + this.setTokenExpirationTime(jwtSettings.getTokenExpirationTime()); + this.setTokenIssuer(jwtSettings.getTokenIssuer()); + this.setTokenSigningKey(jwtSettings.getTokenSigningKey()); + } + } + } diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 17b996934e..a6e8637247 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -111,7 +111,7 @@ security: tokenExpirationTime: "${JWT_TOKEN_EXPIRATION_TIME:9000}" # Number of seconds (2.5 hours) refreshTokenExpTime: "${JWT_REFRESH_TOKEN_EXPIRATION_TIME:604800}" # Number of seconds (1 week) tokenIssuer: "${JWT_TOKEN_ISSUER:thingsboard.io}" - tokenSigningKey: "${JWT_TOKEN_SIGNING_KEY:thingsboardDefaultSigningKey}" + tokenSigningKey: "${JWT_TOKEN_SIGNING_KEY:thingsboardDefaultSigningKey}" # Base64 encoded # Enable/disable access to Tenant Administrators JWT token by System Administrator or Customer Users JWT token by Tenant Administrator user_token_access_enabled: "${SECURITY_USER_TOKEN_ACCESS_ENABLED:true}" # Enable/disable case-sensitive username login