diff --git a/pom.xml b/pom.xml index f268f98..80d3458 100644 --- a/pom.xml +++ b/pom.xml @@ -122,6 +122,9 @@ + + none + org.apache.maven.plugins diff --git a/src/main/java/io/github/tap30/hiss/HissFactory.java b/src/main/java/io/github/tap30/hiss/HissFactory.java index d6ca577..26b6108 100644 --- a/src/main/java/io/github/tap30/hiss/HissFactory.java +++ b/src/main/java/io/github/tap30/hiss/HissFactory.java @@ -11,6 +11,7 @@ import io.github.tap30.hiss.hasher.impl.TapsiHmacSha256Hasher; import io.github.tap30.hiss.key.KeyHashGenerator; import io.github.tap30.hiss.properties.HissProperties; +import io.github.tap30.hiss.properties.HissPropertiesProvider; import io.github.tap30.hiss.properties.HissPropertiesValidator; import org.jetbrains.annotations.NotNull; @@ -27,14 +28,13 @@ public class HissFactory { * Creates a Hiss instance with provided HissProperties and default encryptors and hashers. * * @param hissProperties the properties by which hiss will be instantiated; - * {@link io.github.tap30.hiss.properties.HissPropertiesFromEnv} - * or any custom implementation of - * {@link io.github.tap30.hiss.properties.HissProperties} - * can be used. + * use {@link HissProperties#fromEnv()} + * or {@link HissProperties#builder()} + * or {@link HissProperties#withProvider(HissPropertiesProvider)} * @return {@link Hiss} instance. * @throws IllegalArgumentException if the properties are not valid. */ - public static Hiss createHiss(HissProperties hissProperties) { + public static Hiss createHiss(@NotNull HissProperties hissProperties) { return createHiss(hissProperties, Set.of(), Set.of()); } @@ -44,18 +44,17 @@ public static Hiss createHiss(HissProperties hissProperties) { * Provided encryptors and hashers will be added alongside default ones. * * @param hissProperties the properties by which hiss will be instantiated; - * {@link io.github.tap30.hiss.properties.HissPropertiesFromEnv} - * or any custom implementation of - * {@link io.github.tap30.hiss.properties.HissProperties} - * can be used. - * @param encryptors custom {@link Encryptor} implementations. Can be empty but not null. - * @param hashers custom {@link Hasher} implementations. Can be empty but not null. + * use {@link HissProperties#fromEnv()} + * or {@link HissProperties#builder()} + * or {@link HissProperties#withProvider(HissPropertiesProvider)} + * @param encryptors custom {@link Encryptor} implementations. Can be empty but not null. + * @param hashers custom {@link Hasher} implementations. Can be empty but not null. * @return {@link Hiss} instance. * @throws IllegalArgumentException if the properties are not valid. */ - public static Hiss createHiss(HissProperties hissProperties, - Set encryptors, - Set hashers) { + public static Hiss createHiss(@NotNull HissProperties hissProperties, + @NotNull Set encryptors, + @NotNull Set hashers) { Objects.requireNonNull(hissProperties); Objects.requireNonNull(encryptors); Objects.requireNonNull(hashers); @@ -109,8 +108,8 @@ public static Hiss createHiss(HissProperties hissProperties, } private static void logInitializingHiss(HissProperties hissProperties, - Map encryptors, - Map hashers) { + Map encryptors, + Map hashers) { logger.log(Level.INFO, "Hiss initialized:\n" + " Loaded Keys: {0}\n" + " Default Encryption Key ID: {1}\n" + diff --git a/src/main/java/io/github/tap30/hiss/properties/HissProperties.java b/src/main/java/io/github/tap30/hiss/properties/HissProperties.java index f1678d9..1ee46ce 100644 --- a/src/main/java/io/github/tap30/hiss/properties/HissProperties.java +++ b/src/main/java/io/github/tap30/hiss/properties/HissProperties.java @@ -2,74 +2,73 @@ import io.github.tap30.hiss.key.Key; import io.github.tap30.hiss.utils.StringUtils; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Value; -import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.function.Function; -import java.util.function.Supplier; import java.util.stream.Collectors; -public abstract class HissProperties { - - private final Map properties = new HashMap<>(); - - public Map getKeys() { - return this.getProperty("Keys", this::loadKeys, HissProperties::keysAsMap); - } - - public String getDefaultEncryptionKeyId() { - return this.getProperty("DefaultEncryptionKeyId", - this::loadDefaultEncryptionKeyId, StringUtils::toLowerCase); - } - - public String getDefaultEncryptionAlgorithm() { - return this.getProperty("DefaultEncryptionAlgorithm", - this::loadDefaultEncryptionAlgorithm, StringUtils::toLowerCase); - } - - public String getDefaultHashingKeyId() { - return this.getProperty("DefaultHashingKeyId", - this::loadDefaultHashingKeyId, StringUtils::toLowerCase); - } - - public String getDefaultHashingAlgorithm() { - return this.getProperty("DefaultHashingAlgorithm", - this::loadDefaultHashingAlgorithm, StringUtils::toLowerCase); +@Builder +@Value +@AllArgsConstructor(access = AccessLevel.PACKAGE) +public class HissProperties { + + Map keys; + String defaultEncryptionKeyId; + String defaultEncryptionAlgorithm; + String defaultHashingKeyId; + String defaultHashingAlgorithm; + boolean keyHashGenerationEnabled; + + /** + * See {@link HissPropertiesFromEnvProvider}. + */ + public static HissProperties fromEnv() { + return withProvider(new HissPropertiesFromEnvProvider()); } - public boolean isKeyHashGenerationEnabled() { - return this.getProperty("KeyHashGenerationEnabled", this::loadKeyHashGenerationEnabled); + public static HissProperties withProvider(HissPropertiesProvider provider) { + return builder() + .keys(provider.getKeys()) + .defaultEncryptionKeyId(provider.getDefaultEncryptionKeyId()) + .defaultEncryptionAlgorithm(provider.getDefaultEncryptionAlgorithm()) + .defaultHashingKeyId(provider.getDefaultHashingKeyId()) + .defaultHashingAlgorithm(provider.getDefaultHashingAlgorithm()) + .keyHashGenerationEnabled(provider.isKeyHashGenerationEnabled()) + .build(); } - protected abstract Set loadKeys(); - - protected abstract String loadDefaultEncryptionKeyId(); - - protected abstract String loadDefaultEncryptionAlgorithm(); - - protected abstract String loadDefaultHashingKeyId(); + public static class HissPropertiesBuilder { + public HissPropertiesBuilder keys(Set keys) { + this.keys = keys.stream() + .collect(Collectors.toMap(k -> StringUtils.toLowerCase(k.getId()), Function.identity())); + return this; + } - protected abstract String loadDefaultHashingAlgorithm(); + public HissPropertiesBuilder defaultEncryptionKeyId(String defaultEncryptionKeyId) { + this.defaultEncryptionKeyId = StringUtils.toLowerCase(defaultEncryptionKeyId); + return this; + } - protected abstract boolean loadKeyHashGenerationEnabled(); + public HissPropertiesBuilder defaultEncryptionAlgorithm(String defaultEncryptionAlgorithm) { + this.defaultEncryptionAlgorithm = StringUtils.toLowerCase(defaultEncryptionAlgorithm); + return this; + } - private O getProperty(String key, Supplier valueSupplier) { - return getProperty(key, valueSupplier, v -> v); - } + public HissPropertiesBuilder defaultHashingKeyId(String defaultHashingKeyId) { + this.defaultHashingKeyId = StringUtils.toLowerCase(defaultHashingKeyId); + return this; + } - @SuppressWarnings("unchecked") - private O getProperty(String key, Supplier valueSupplier, Function mapper) { - if (this.properties.containsKey(key)) { - return (O) this.properties.get(key); + public HissPropertiesBuilder defaultHashingAlgorithm(String defaultHashingAlgorithm) { + this.defaultHashingAlgorithm = StringUtils.toLowerCase(defaultHashingAlgorithm); + return this; } - var value = mapper.apply(valueSupplier.get()); - this.properties.put(key, value); - return value; } - private static Map keysAsMap(Set keys) { - return keys.stream().collect(Collectors.toMap(k -> StringUtils.toLowerCase(k.getId()), k -> k)); - } } diff --git a/src/main/java/io/github/tap30/hiss/properties/HissPropertiesFromEnv.java b/src/main/java/io/github/tap30/hiss/properties/HissPropertiesFromEnvProvider.java similarity index 82% rename from src/main/java/io/github/tap30/hiss/properties/HissPropertiesFromEnv.java rename to src/main/java/io/github/tap30/hiss/properties/HissPropertiesFromEnvProvider.java index bc4706b..81c7407 100644 --- a/src/main/java/io/github/tap30/hiss/properties/HissPropertiesFromEnv.java +++ b/src/main/java/io/github/tap30/hiss/properties/HissPropertiesFromEnvProvider.java @@ -8,7 +8,7 @@ import java.util.Set; import java.util.function.Supplier; -// Todo: import doc +// Todo: improve doc /** * Sample Envs: *
@@ -26,7 +26,7 @@ * HISS_DEFAULT_HASHING_ALGORITHM: hmac-sha256 * */ -public class HissPropertiesFromEnv extends HissProperties { +public class HissPropertiesFromEnvProvider implements HissPropertiesProvider { private static final String KEY_ENV_PREFIX = "HISS_KEYS_"; private static final String KEY_HASH_ENV_POSTFIX = "___HASH"; @@ -34,7 +34,7 @@ public class HissPropertiesFromEnv extends HissProperties { private static final Supplier> ENV_PROVIDER = System::getenv; @Override - public Set loadKeys() { + public Set getKeys() { var keys = new HashSet(); ENV_PROVIDER.get().forEach((k, v) -> { if (k.startsWith(KEY_ENV_PREFIX) && !k.endsWith(KEY_HASH_ENV_POSTFIX)) { @@ -49,27 +49,28 @@ public Set loadKeys() { } @Override - public String loadDefaultEncryptionKeyId() { + public String getDefaultEncryptionKeyId() { return ENV_PROVIDER.get().get("HISS_DEFAULT_ENCRYPTION_KEY_ID"); } @Override - public String loadDefaultEncryptionAlgorithm() { + public String getDefaultEncryptionAlgorithm() { return ENV_PROVIDER.get().get("HISS_DEFAULT_ENCRYPTION_ALGORITHM"); } @Override - public String loadDefaultHashingKeyId() { + public String getDefaultHashingKeyId() { return ENV_PROVIDER.get().get("HISS_DEFAULT_HASHING_KEY_ID"); } @Override - public String loadDefaultHashingAlgorithm() { + public String getDefaultHashingAlgorithm() { return ENV_PROVIDER.get().get("HISS_DEFAULT_HASHING_ALGORITHM"); } @Override - protected boolean loadKeyHashGenerationEnabled() { + public boolean isKeyHashGenerationEnabled() { return Boolean.parseBoolean(ENV_PROVIDER.get().get("HISS_KEY_HASH_GENERATION_ENABLED")); } + } diff --git a/src/main/java/io/github/tap30/hiss/properties/HissPropertiesProvider.java b/src/main/java/io/github/tap30/hiss/properties/HissPropertiesProvider.java new file mode 100644 index 0000000..3f0232d --- /dev/null +++ b/src/main/java/io/github/tap30/hiss/properties/HissPropertiesProvider.java @@ -0,0 +1,14 @@ +package io.github.tap30.hiss.properties; + +import io.github.tap30.hiss.key.Key; + +import java.util.Set; + +public interface HissPropertiesProvider { + Set getKeys(); + String getDefaultEncryptionKeyId(); + String getDefaultEncryptionAlgorithm(); + String getDefaultHashingKeyId(); + String getDefaultHashingAlgorithm(); + boolean isKeyHashGenerationEnabled(); +} diff --git a/src/main/java/io/github/tap30/hiss/properties/HissPropertiesValidator.java b/src/main/java/io/github/tap30/hiss/properties/HissPropertiesValidator.java index bdd6ab5..8911458 100644 --- a/src/main/java/io/github/tap30/hiss/properties/HissPropertiesValidator.java +++ b/src/main/java/io/github/tap30/hiss/properties/HissPropertiesValidator.java @@ -53,7 +53,8 @@ private void validateDefaultEncryptionKeyAndAlgorithm(HissProperties hissPropert if (!StringUtils.hasText(hissProperties.getDefaultEncryptionKeyId())) { errors.add("Default encryption key ID is not defined"); } - if (!hissProperties.getKeys().containsKey(hissProperties.getDefaultEncryptionKeyId())) { + if (hissProperties.getKeys() != null + && !hissProperties.getKeys().containsKey(hissProperties.getDefaultEncryptionKeyId())) { errors.add("Default encryption key ID is not among provided keys: " + hissProperties.getKeys().keySet()); } if (!StringUtils.hasText(hissProperties.getDefaultEncryptionAlgorithm())) { @@ -67,7 +68,8 @@ private void validateDefaultHashingKeyAndAlgorithm(HissProperties hissProperties if (!StringUtils.hasText(hissProperties.getDefaultHashingKeyId())) { errors.add("Default hashing key ID is not defined"); } - if (!hissProperties.getKeys().containsKey(hissProperties.getDefaultHashingKeyId())) { + if (hissProperties.getKeys() != null + && !hissProperties.getKeys().containsKey(hissProperties.getDefaultHashingKeyId())) { errors.add("Default hashing key ID is not among provided keys: " + hissProperties.getKeys().keySet()); } if (!StringUtils.hasText(hissProperties.getDefaultHashingAlgorithm())) { diff --git a/src/test/java/io/github/tap30/hiss/BaseHissTest.java b/src/test/java/io/github/tap30/hiss/BaseHissTest.java index be5886a..dc53388 100644 --- a/src/test/java/io/github/tap30/hiss/BaseHissTest.java +++ b/src/test/java/io/github/tap30/hiss/BaseHissTest.java @@ -1,6 +1,6 @@ package io.github.tap30.hiss; -import io.github.tap30.hiss.properties.HissPropertiesFromEnv; +import io.github.tap30.hiss.properties.HissProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; @@ -24,8 +24,7 @@ public class BaseHissTest { @BeforeEach void setUpHiss() { - var hissPropertiesFromEnv = new HissPropertiesFromEnv(); - hiss = HissFactory.createHiss(hissPropertiesFromEnv); + hiss = HissFactory.createHiss(HissProperties.fromEnv()); } } diff --git a/src/test/java/io/github/tap30/hiss/HissFactoryTest.java b/src/test/java/io/github/tap30/hiss/HissFactoryTest.java index 7c09188..d5c703c 100644 --- a/src/test/java/io/github/tap30/hiss/HissFactoryTest.java +++ b/src/test/java/io/github/tap30/hiss/HissFactoryTest.java @@ -14,42 +14,18 @@ class HissFactoryTest { @Test void createHiss() { // Given - var properties = new HissProperties() { - - @Override - protected Set loadKeys() { - return Set.of(Key.builder() - .id("default_key") - .key(Base64.getDecoder().decode("AAAAAAAAAAAAAAAAAAAAAA==")) - .keyHash("$2a$12$3T0VMnGMgvesehYomommnO02dbFOJuM/3elsmgmsB2/qlGSF3BIbe") - .build()); - } - - @Override - protected String loadDefaultEncryptionKeyId() { - return "default_key"; - } - - @Override - protected String loadDefaultEncryptionAlgorithm() { - return "aes-128-gcm"; - } - - @Override - protected String loadDefaultHashingKeyId() { - return "default_key"; - } - - @Override - protected String loadDefaultHashingAlgorithm() { - return "hmac-sha256"; - } - - @Override - protected boolean loadKeyHashGenerationEnabled() { - return false; - } - }; + var properties = HissProperties.builder() + .keys(Set.of(Key.builder() + .id("default_key") + .key(Base64.getDecoder().decode("AAAAAAAAAAAAAAAAAAAAAA==")) + .keyHash("$2a$12$3T0VMnGMgvesehYomommnO02dbFOJuM/3elsmgmsB2/qlGSF3BIbe") + .build())) + .defaultEncryptionKeyId("default_key") + .defaultEncryptionAlgorithm("aes-128-gcm") + .defaultHashingKeyId("default_key") + .defaultHashingAlgorithm("hmac-sha256") + .keyHashGenerationEnabled(false) + .build(); // When var hiss = HissFactory.createHiss(properties); @@ -65,37 +41,7 @@ protected boolean loadKeyHashGenerationEnabled() { @Test void createHiss_shouldPropertiesBeingValidated() { assertThrows(IllegalArgumentException.class, () -> - HissFactory.createHiss(new HissProperties() { - @Override - protected Set loadKeys() { - return Set.of(); - } - - @Override - protected String loadDefaultEncryptionKeyId() { - return ""; - } - - @Override - protected String loadDefaultEncryptionAlgorithm() { - return ""; - } - - @Override - protected String loadDefaultHashingKeyId() { - return ""; - } - - @Override - protected String loadDefaultHashingAlgorithm() { - return ""; - } - - @Override - protected boolean loadKeyHashGenerationEnabled() { - return false; - } - })); + HissFactory.createHiss(HissProperties.builder().build())); } } \ No newline at end of file diff --git a/src/test/java/io/github/tap30/hiss/properties/HissPropertiesFromEnvTest.java b/src/test/java/io/github/tap30/hiss/properties/HissPropertiesFromEnvProviderTest.java similarity index 95% rename from src/test/java/io/github/tap30/hiss/properties/HissPropertiesFromEnvTest.java rename to src/test/java/io/github/tap30/hiss/properties/HissPropertiesFromEnvProviderTest.java index e373410..ca5aa23 100644 --- a/src/test/java/io/github/tap30/hiss/properties/HissPropertiesFromEnvTest.java +++ b/src/test/java/io/github/tap30/hiss/properties/HissPropertiesFromEnvProviderTest.java @@ -12,7 +12,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; @ExtendWith(SystemStubsExtension.class) -class HissPropertiesFromEnvTest { +class HissPropertiesFromEnvProviderTest { @SystemStub EnvironmentVariables environment = new EnvironmentVariables( @@ -30,7 +30,7 @@ class HissPropertiesFromEnvTest { @Test void test() { // Given & When - var hissProperties = new HissPropertiesFromEnv(); + var hissProperties = HissProperties.fromEnv(); // Then assertEquals(2, hissProperties.getKeys().size()); diff --git a/src/test/java/io/github/tap30/hiss/properties/HissPropertiesValidatorTest.java b/src/test/java/io/github/tap30/hiss/properties/HissPropertiesValidatorTest.java index cca48ac..caa85e6 100644 --- a/src/test/java/io/github/tap30/hiss/properties/HissPropertiesValidatorTest.java +++ b/src/test/java/io/github/tap30/hiss/properties/HissPropertiesValidatorTest.java @@ -172,41 +172,18 @@ void validate_whenDefaultHashingAlgorithmIsInvalid() { } HissProperties createValidProperties() { - return new HissProperties() { - @Override - protected Set loadKeys() { - return Set.of(Key.builder() + return HissProperties.builder() + .keys(Set.of(Key.builder() .id("default_key") .key(Base64.getDecoder().decode("AAAAAAAAAAAAAAAAAAAAAA==")) .keyHash("$2a$12$3T0VMnGMgvesehYomommnO02dbFOJuM/3elsmgmsB2/qlGSF3BIbe") - .build()); - } - - @Override - protected String loadDefaultEncryptionKeyId() { - return "default_key"; - } - - @Override - protected String loadDefaultEncryptionAlgorithm() { - return "aes-128-gcm"; - } - - @Override - protected String loadDefaultHashingKeyId() { - return "default_key"; - } - - @Override - protected String loadDefaultHashingAlgorithm() { - return "hmac-sha256"; - } - - @Override - protected boolean loadKeyHashGenerationEnabled() { - return true; - } - }; + .build())) + .defaultEncryptionKeyId("default_key") + .defaultEncryptionAlgorithm("aes-128-gcm") + .defaultHashingKeyId("default_key") + .defaultHashingAlgorithm("hmac-sha256") + .keyHashGenerationEnabled(false) + .build(); } } \ No newline at end of file