jwt settings added message on base64 validation exception, default key is to be validated ok, tests added
This commit is contained in:
parent
335d88c82e
commit
46b2adeb2c
@ -15,15 +15,22 @@
|
||||
*/
|
||||
package org.thingsboard.server.config.jwt;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.data.security.model.JwtToken;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "security.jwt")
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
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.
|
||||
*/
|
||||
|
||||
@ -37,13 +37,14 @@ import java.util.Base64;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.thingsboard.server.config.jwt.JwtSettings.ADMIN_SETTINGS_JWT_KEY;
|
||||
import static org.thingsboard.server.config.jwt.JwtSettings.TOKEN_SIGNING_KEY_DEFAULT;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class JwtSettingsServiceDefault implements JwtSettingsService {
|
||||
|
||||
static final String ADMIN_SETTINGS_JWT_KEY = "jwt";
|
||||
static final String TOKEN_SIGNING_KEY_DEFAULT = "thingsboardDefaultSigningKey";
|
||||
@Lazy
|
||||
private final AdminSettingsService adminSettingsService;
|
||||
@Lazy
|
||||
|
||||
@ -26,6 +26,8 @@ import java.util.Base64;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.thingsboard.server.config.jwt.JwtSettings.TOKEN_SIGNING_KEY_DEFAULT;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class JwtSettingsValidatorDefault implements JwtSettingsValidator {
|
||||
@ -58,7 +60,7 @@ public class JwtSettingsValidatorDefault implements JwtSettingsValidator {
|
||||
if (Arrays.isNullOrEmpty(decodedKey)) {
|
||||
throw new DataValidationException("JWT token signing key should be non-empty after Base64 decoding!");
|
||||
}
|
||||
if (decodedKey.length * Byte.SIZE < 256) {
|
||||
if (decodedKey.length * Byte.SIZE < 256 && !TOKEN_SIGNING_KEY_DEFAULT.equals(jwtSettings.getTokenSigningKey())) {
|
||||
throw new DataValidationException("JWT token signing key should be a Base64 encoded string representing at least 256 bits of data!");
|
||||
}
|
||||
|
||||
|
||||
@ -17,14 +17,22 @@ package org.thingsboard.server.controller;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.MailService;
|
||||
import org.thingsboard.server.common.data.AdminSettings;
|
||||
import org.thingsboard.server.config.jwt.JwtSettings;
|
||||
import org.thingsboard.server.config.jwt.JwtSettingsService;
|
||||
import org.thingsboard.server.service.mail.DefaultMailService;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
@ -32,8 +40,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
|
||||
@Slf4j
|
||||
public abstract class BaseAdminControllerTest extends AbstractControllerTest {
|
||||
final JwtSettings defaultJwtSettings = new JwtSettings(9000, "thingsboard.io", "thingsboardDefaultSigningKey", 604800);
|
||||
|
||||
@Autowired
|
||||
MailService mailService;
|
||||
@ -45,23 +54,23 @@ public abstract class BaseAdminControllerTest extends AbstractControllerTest {
|
||||
public void testFindAdminSettingsByKey() throws Exception {
|
||||
loginSysAdmin();
|
||||
doGet("/api/admin/settings/general")
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$.id", notNullValue()))
|
||||
.andExpect(jsonPath("$.key", is("general")))
|
||||
.andExpect(jsonPath("$.jsonValue.baseUrl", is("http://localhost:8080")));
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$.id", notNullValue()))
|
||||
.andExpect(jsonPath("$.key", is("general")))
|
||||
.andExpect(jsonPath("$.jsonValue.baseUrl", is("http://localhost:8080")));
|
||||
|
||||
doGet("/api/admin/settings/mail")
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$.id", notNullValue()))
|
||||
.andExpect(jsonPath("$.key", is("mail")))
|
||||
.andExpect(jsonPath("$.jsonValue.smtpProtocol", is("smtp")))
|
||||
.andExpect(jsonPath("$.jsonValue.smtpHost", is("localhost")))
|
||||
.andExpect(jsonPath("$.jsonValue.smtpPort", is("25")));
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$.id", notNullValue()))
|
||||
.andExpect(jsonPath("$.key", is("mail")))
|
||||
.andExpect(jsonPath("$.jsonValue.smtpProtocol", is("smtp")))
|
||||
.andExpect(jsonPath("$.jsonValue.smtpHost", is("localhost")))
|
||||
.andExpect(jsonPath("$.jsonValue.smtpPort", is("25")));
|
||||
|
||||
doGet("/api/admin/settings/unknown")
|
||||
.andExpect(status().isNotFound());
|
||||
.andExpect(status().isNotFound());
|
||||
|
||||
}
|
||||
|
||||
@ -77,15 +86,15 @@ public abstract class BaseAdminControllerTest extends AbstractControllerTest {
|
||||
doPost("/api/admin/settings", adminSettings).andExpect(status().isOk());
|
||||
|
||||
doGet("/api/admin/settings/general")
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$.jsonValue.baseUrl", is("http://myhost.org")));
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$.jsonValue.baseUrl", is("http://myhost.org")));
|
||||
|
||||
((ObjectNode) jsonValue).put("baseUrl", "http://localhost:8080");
|
||||
adminSettings.setJsonValue(jsonValue);
|
||||
|
||||
doPost("/api/admin/settings", adminSettings)
|
||||
.andExpect(status().isOk());
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -94,8 +103,8 @@ public abstract class BaseAdminControllerTest extends AbstractControllerTest {
|
||||
AdminSettings adminSettings = doGet("/api/admin/settings/mail", AdminSettings.class);
|
||||
adminSettings.setKey(null);
|
||||
doPost("/api/admin/settings", adminSettings)
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(statusReason(containsString("Key should be specified")));
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(statusReason(containsString("Key should be specified")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -104,8 +113,8 @@ public abstract class BaseAdminControllerTest extends AbstractControllerTest {
|
||||
AdminSettings adminSettings = doGet("/api/admin/settings/mail", AdminSettings.class);
|
||||
adminSettings.setKey("newKey");
|
||||
doPost("/api/admin/settings", adminSettings)
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(statusReason(containsString("is prohibited")));
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(statusReason(containsString("is prohibited")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -113,7 +122,7 @@ public abstract class BaseAdminControllerTest extends AbstractControllerTest {
|
||||
loginSysAdmin();
|
||||
AdminSettings adminSettings = doGet("/api/admin/settings/mail", AdminSettings.class);
|
||||
doPost("/api/admin/settings/testMail", adminSettings)
|
||||
.andExpect(status().isOk());
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -139,4 +148,48 @@ public abstract class BaseAdminControllerTest extends AbstractControllerTest {
|
||||
doPost("/api/admin/settings/testMail", adminSettings).andExpect(status().is5xxServerError());
|
||||
Mockito.doNothing().when(mailService).sendTestMail(Mockito.any(), Mockito.any());
|
||||
}
|
||||
|
||||
void resetJwtSettingsToDefault() throws Exception {
|
||||
loginSysAdmin();
|
||||
doPost("/api/admin/jwtSettings", defaultJwtSettings).andExpect(status().isOk()); // jwt test scenarios are always started from
|
||||
loginTenantAdmin();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAndSaveDefaultJwtSettings() throws Exception {
|
||||
JwtSettings jwtSettings;
|
||||
loginSysAdmin();
|
||||
|
||||
jwtSettings = doGet("/api/admin/jwtSettings", JwtSettings.class);
|
||||
assertThat(jwtSettings).isEqualTo(defaultJwtSettings);
|
||||
|
||||
doPost("/api/admin/jwtSettings", jwtSettings).andExpect(status().isOk());
|
||||
|
||||
jwtSettings = doGet("/api/admin/jwtSettings", JwtSettings.class);
|
||||
assertThat(jwtSettings).isEqualTo(defaultJwtSettings);
|
||||
|
||||
resetJwtSettingsToDefault();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateJwtSettings() throws Exception {
|
||||
loginSysAdmin();
|
||||
|
||||
JwtSettings jwtSettings = doGet("/api/admin/jwtSettings", JwtSettings.class);
|
||||
assertThat(jwtSettings).isEqualTo(defaultJwtSettings);
|
||||
|
||||
jwtSettings.setTokenSigningKey(Base64.getEncoder().encodeToString(
|
||||
RandomStringUtils.randomAlphanumeric(256 / Byte.SIZE).getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
doPost("/api/admin/jwtSettings", jwtSettings).andExpect(status().isOk());
|
||||
|
||||
doGet("/api/admin/jwtSettings").andExpect(status().isUnauthorized()); //the old JWT token does not work after signing key was changed!
|
||||
|
||||
loginSysAdmin();
|
||||
JwtSettings newJwtSettings = doGet("/api/admin/jwtSettings", JwtSettings.class);
|
||||
assertThat(jwtSettings).isEqualTo(newJwtSettings);
|
||||
|
||||
resetJwtSettingsToDefault();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user