#78 put a secureRandom value as default value for the JWT token

This commit is contained in:
Fabio Formosa
2022-11-19 18:28:39 +01:00
parent 3bb30accfd
commit bccd50ac4a
7 changed files with 109 additions and 37 deletions

View File

@@ -3,17 +3,28 @@ package it.fabioformosa.quartzmanager.api.security.properties;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.security.SecureRandom;
import java.util.Base64;
@Configuration
@ConfigurationProperties(prefix = "quartz-manager.security.jwt")
@Getter
@Setter
public class JwtSecurityProperties {
private String secret = RandomStringUtils.randomAlphabetic(10);
private String secret;
{
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[20];
random.nextBytes(bytes);
Base64.Encoder encoder = Base64.getUrlEncoder().withoutPadding();
secret = encoder.encodeToString(bytes);
}
private long expirationInSec = 28800;
private CookieStrategy cookieStrategy = new CookieStrategy();

View File

@@ -2,6 +2,8 @@ package it.fabioformosa.quartzmanager.api.security;
import it.fabioformosa.quartzmanager.api.common.config.QuartzManagerPaths;
import it.fabioformosa.quartzmanager.api.security.controllers.TestController;
import it.fabioformosa.quartzmanager.api.security.properties.JwtSecurityProperties;
import org.assertj.core.api.Assertions;
import org.hamcrest.core.IsNot;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -19,9 +21,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest
@AutoConfigureMockMvc
@TestPropertySource(properties = {
"quartz-manager.security.jwt.enabled=true",
"quartz-manager.security.jwt.secret=bibidibobidiboo",
"quartz-manager.security.jwt.expiration-in-sec=28800",
"quartz-manager.security.jwt.expiration-in-sec=36000",
"quartz-manager.security.jwt.header-strategy.enabled=false",
"quartz-manager.security.jwt.header-strategy.header=Authorization",
"quartz-manager.security.jwt.cookie-strategy.enabled=true",
@@ -36,6 +37,9 @@ class SecurityControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private JwtSecurityProperties jwtSecurityProperties;
@Test
void givenAnAnonymousUser_whenCalledADMZController_thenShouldRaiseForbidden() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/dmz"))
@@ -72,4 +76,10 @@ class SecurityControllerTest {
.andExpect(status().isOk());
}
@Test
void givenSecurityProps_whenTheBootstrapHasCompleted_thenJWTPropertiesShouldBeSetAccordingly() throws Exception {
Assertions.assertThat(jwtSecurityProperties.getExpirationInSec()).isEqualTo(36000);
Assertions.assertThat(jwtSecurityProperties.getSecret()).isEqualTo("bibidibobidiboo");
}
}

View File

@@ -13,7 +13,6 @@ import org.springframework.test.context.TestPropertySource;
@TestPropertySource(properties = {
"quartz-manager.security.login-model.form-login-enabled = false",
"quartz-manager.security.login-model.userpwd-filter-enabled = true",
"quartz-manager.security.jwt.enabled=true",
"quartz-manager.security.jwt.secret=bibidibobidiboo",
"quartz-manager.security.jwt.expiration-in-sec=28800",
"quartz-manager.security.jwt.header-strategy.enabled=true",

View File

@@ -12,7 +12,6 @@ import org.springframework.test.context.TestPropertySource;
@TestPropertySource(properties = {
"quartz-manager.security.login-model.form-login-enabled = true",
"quartz-manager.security.login-model.userpwd-filter-enabled = false",
"quartz-manager.security.jwt.enabled=true",
"quartz-manager.security.jwt.secret=bibidibobidiboo",
"quartz-manager.security.jwt.expiration-in-sec=28800",
"quartz-manager.security.jwt.header-strategy.enabled=true",

View File

@@ -0,0 +1,39 @@
package it.fabioformosa.quartzmanager.api.security.properties;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import javax.validation.Validation;
import javax.validation.Validator;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
public class AbstractPropertyValidatorTest {
protected static Validator propertyValidator;
@BeforeAll
public static void setup() {
propertyValidator = Validation.buildDefaultValidatorFactory().getValidator();
}
protected static <T> T inflateConfigurationPropertyFromAMap(Map<String, String> properties, String configurationPropName, Class<T> propClass) {
ConfigurationPropertySource source = new MapConfigurationPropertySource(properties);
Binder binder = new Binder(source);
BindResult<T> result = binder.bind(configurationPropName, propClass);
if (properties != null && !properties.isEmpty()) {
Assertions.assertThat(result.isBound()).isTrue();
T configPropObject = result.get();
return configPropObject;
} else {
try {
return propClass.getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@@ -1,25 +1,16 @@
package it.fabioformosa.quartzmanager.api.security.properties;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
public class InMemoryUsersValidationControllerTest {
private static Validator propertyValidator;
public class InMemoryUsersValidationControllerTest extends AbstractPropertyValidatorTest {
static Stream<Arguments> notValidInMemoryProps = Stream.of(
Arguments.of(
@@ -34,26 +25,15 @@ public class InMemoryUsersValidationControllerTest {
);
@BeforeAll
public static void setup() {
propertyValidator = Validation.buildDefaultValidatorFactory().getValidator();
}
static Stream<Arguments> getNotValidInMemoryProps(){
static Stream<Arguments> getNotValidInMemoryProps() {
return notValidInMemoryProps;
}
@ParameterizedTest
@MethodSource("it.fabioformosa.quartzmanager.api.security.properties.InMemoryUsersValidationControllerTest#getNotValidInMemoryProps")
void givenAMissingUsername_whenThePropertyValidationIsApplied_thenShouldRaiseValidationError(Map<String, String> properties) {
ConfigurationPropertySource source = new MapConfigurationPropertySource(properties);
Binder binder = new Binder(source);
BindResult<InMemoryAccountProperties> result = binder.bind("quartz-manager.security.accounts.in-memory", InMemoryAccountProperties.class);
Assertions.assertThat(result.isBound()).isTrue();
InMemoryAccountProperties inMemoryAccountProperties = result.get();
InMemoryAccountProperties inMemoryAccountProperties = inflateConfigurationPropertyFromAMap(properties,
"quartz-manager.security.accounts.in-memory", InMemoryAccountProperties.class);
Assertions.assertThat(propertyValidator.validate(inMemoryAccountProperties)).isNotEmpty();
}
@@ -65,14 +45,9 @@ public class InMemoryUsersValidationControllerTest {
properties.put("quartz-manager.security.accounts.in-memory.users[0].password", "bar");
properties.put("quartz-manager.security.accounts.in-memory.users[0].roles[0]", "admin");
ConfigurationPropertySource source = new MapConfigurationPropertySource(properties);
InMemoryAccountProperties inMemoryAccountProperties = inflateConfigurationPropertyFromAMap(properties,
"quartz-manager.security.accounts.in-memory", InMemoryAccountProperties.class);
Binder binder = new Binder(source);
BindResult<InMemoryAccountProperties> result = binder.bind("quartz-manager.security.accounts.in-memory", InMemoryAccountProperties.class);
Assertions.assertThat(result.isBound()).isTrue();
InMemoryAccountProperties inMemoryAccountProperties = result.get();
Assertions.assertThat(propertyValidator.validate(inMemoryAccountProperties)).isEmpty();
}

View File

@@ -0,0 +1,39 @@
package it.fabioformosa.quartzmanager.api.security.properties;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
class JwtSecurityPropertiesTest extends AbstractPropertyValidatorTest {
@Test
void givenAllJWTSecurityPropSet_whenThePropertyValidationIsApplied_thenShouldBeValid() {
Map<String, String> properties = new HashMap<>();
String secret = "helloworld";
properties.put("quartz-manager.security.jwt.secret", secret);
String expirationInSec = "36000";
properties.put("quartz-manager.security.jwt.expirationInSec", expirationInSec);
JwtSecurityProperties jwtSecurityProperties = inflateConfigurationPropertyFromAMap(properties,
"quartz-manager.security.jwt", JwtSecurityProperties.class);
Assertions.assertThat(propertyValidator.validate(jwtSecurityProperties)).isEmpty();
Assertions.assertThat(jwtSecurityProperties.getExpirationInSec()).isEqualTo(Long.valueOf(expirationInSec));
Assertions.assertThat(jwtSecurityProperties.getSecret()).isEqualTo(secret);
}
@Test
void givenTheMandatoryJWTSecurityPropUnset_whenThePropertyValidationIsApplied_thenShouldBeSetWithDefault() {
Map<String, String> properties = new HashMap<>();
JwtSecurityProperties jwtSecurityProperties = inflateConfigurationPropertyFromAMap(properties,
"quartz-manager.security.jwt", JwtSecurityProperties.class);
Assertions.assertThat(jwtSecurityProperties.getExpirationInSec()).isEqualTo(28800L);
Assertions.assertThat(jwtSecurityProperties.getSecret()).isNotBlank();
}
}