diff --git a/alpine-infra/pom.xml b/alpine-infra/pom.xml index c39f1c61..c3f02a85 100644 --- a/alpine-infra/pom.xml +++ b/alpine-infra/pom.xml @@ -71,10 +71,6 @@ io.jsonwebtoken jjwt - - org.mindrot - jbcrypt - org.junit.jupiter diff --git a/alpine-infra/src/main/java/alpine/persistence/AlpineQueryManager.java b/alpine-infra/src/main/java/alpine/persistence/AlpineQueryManager.java index e2d5c14a..93b0026b 100644 --- a/alpine-infra/src/main/java/alpine/persistence/AlpineQueryManager.java +++ b/alpine-infra/src/main/java/alpine/persistence/AlpineQueryManager.java @@ -18,7 +18,6 @@ */ package alpine.persistence; -import alpine.Config; import alpine.common.logging.Logger; import alpine.event.LdapSyncEvent; import alpine.event.framework.EventService; @@ -42,12 +41,12 @@ import javax.jdo.PersistenceManager; import javax.jdo.Query; -import org.mindrot.jbcrypt.BCrypt; - +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; import java.sql.Timestamp; import java.util.ArrayList; -import java.util.Base64; import java.util.Date; +import java.util.HexFormat; import java.util.LinkedHashSet; import java.util.List; @@ -61,7 +60,7 @@ public class AlpineQueryManager extends AbstractAlpineQueryManager { private static final Logger LOGGER = Logger.getLogger(AlpineQueryManager.class); - private static final int ROUNDS = Config.getInstance().getPropertyAsInt(Config.AlpineKey.BCRYPT_ROUNDS); + private static final String HASH_METHOD = "SHA3-256"; private static final int SUFFIX_LENGTH = 5; /** @@ -108,7 +107,9 @@ public ApiKey getApiKey(final String key) { final Query query = pm.newQuery(ApiKey.class, "suffix == :suffix"); query.setParameters(key.substring(key.length() - SUFFIX_LENGTH)); ApiKey apiKey = executeAndCloseUnique(query); - return BCrypt.checkpw(key.substring(0, key.length() - SUFFIX_LENGTH), apiKey.getKey()) ? apiKey : null; + MessageDigest digest = MessageDigest.getInstance(HASH_METHOD); + byte[] hashedKey = digest.digest(key.getBytes(StandardCharsets.UTF_8)); + return apiKey != null && MessageDigest.isEqual(hashedKey, apiKey.getKey().getBytes()) ? apiKey : null; }); } @@ -123,12 +124,12 @@ public ApiKey getApiKey(final String key) { public ApiKey regenerateApiKey(final ApiKey apiKey) { return callInTransaction(() -> { String clearKey = ApiKeyGenerator.generate(); - String hashedKey = BCrypt.hashpw(new String(Base64.getDecoder().decode(clearKey)), BCrypt.gensalt(ROUNDS)) - .toCharArray().toString(); + MessageDigest digest = MessageDigest.getInstance(HASH_METHOD); + String hashedKey = HexFormat.of().formatHex(digest.digest(clearKey.getBytes(StandardCharsets.UTF_8))); apiKey.setKey(hashedKey); - apiKey.setSuffix(ApiKeyGenerator.generate(SUFFIX_LENGTH)); + apiKey.setSuffix(clearKey.substring(clearKey.length() - SUFFIX_LENGTH)); pm.makeTransient(apiKey); - apiKey.setKey(clearKey + apiKey.getSuffix()); + apiKey.setKey(clearKey); return apiKey; }); } @@ -140,20 +141,21 @@ public ApiKey regenerateApiKey(final ApiKey apiKey) { * @return an ApiKey */ public ApiKey createApiKey(final Team team) { - return callInTransaction(() -> { - final var apiKey = new ApiKey(); - String clearKey = ApiKeyGenerator.generate(); - String hashedKey = BCrypt.hashpw(new String(Base64.getDecoder().decode(clearKey)), BCrypt.gensalt(ROUNDS)) - .toCharArray().toString(); - apiKey.setKey(hashedKey); - apiKey.setSuffix(ApiKeyGenerator.generate(SUFFIX_LENGTH)); - apiKey.setCreated(new Date()); - apiKey.setTeams(List.of(team)); - pm.makePersistent(apiKey); - pm.makeTransient(apiKey); - apiKey.setKey(clearKey + apiKey.getSuffix()); - return apiKey; + String clearKey = ApiKeyGenerator.generate(); + ApiKey apiKey = callInTransaction(() -> { + final var apiKeyPers = new ApiKey(); + MessageDigest digest = MessageDigest.getInstance(HASH_METHOD); + String hashedKey = HexFormat.of().formatHex(digest.digest(clearKey.getBytes(StandardCharsets.UTF_8))); + apiKeyPers.setKey(hashedKey); + apiKeyPers.setSuffix(clearKey.substring(clearKey.length() - SUFFIX_LENGTH)); + apiKeyPers.setCreated(new Date()); + apiKeyPers.setTeams(List.of(team)); + pm.makePersistent(apiKeyPers); + return apiKeyPers; }); + ApiKey copiedApiKey = pm.detachCopy(apiKey); + copiedApiKey.setKey(clearKey); + return copiedApiKey; } public ApiKey updateApiKey(final ApiKey transientApiKey) { diff --git a/alpine-model/src/main/java/alpine/model/ApiKey.java b/alpine-model/src/main/java/alpine/model/ApiKey.java index 8095ece4..43e379d0 100644 --- a/alpine-model/src/main/java/alpine/model/ApiKey.java +++ b/alpine-model/src/main/java/alpine/model/ApiKey.java @@ -90,6 +90,7 @@ public class ApiKey implements Serializable, Principal { @Persistent @Unique @Column(name = "SUFFIX") + @JsonIgnore private String suffix; public long getId() { diff --git a/alpine-model/src/test/java/alpine/model/ApiKeyTest.java b/alpine-model/src/test/java/alpine/model/ApiKeyTest.java index 079b032c..058391fd 100644 --- a/alpine-model/src/test/java/alpine/model/ApiKeyTest.java +++ b/alpine-model/src/test/java/alpine/model/ApiKeyTest.java @@ -40,14 +40,16 @@ public void keyTest() { { ApiKey key = new ApiKey(); key.setKey("12345678901234567890"); + key.setSuffix(key.getKey().substring(key.getKey().length() - 5)); Assertions.assertEquals("12345678901234567890", key.getKey()); - Assertions.assertEquals("****************7890", key.getName()); + Assertions.assertEquals("***************67890", key.getName()); } { ApiKey key = new ApiKey(); key.setKey(prefix + "12345678901234567890"); + key.setSuffix(key.getKey().substring(key.getKey().length() - 5)); Assertions.assertEquals(prefix + "12345678901234567890", key.getKey()); - Assertions.assertEquals(prefix + "****************7890", key.getName()); + Assertions.assertEquals(prefix + "***************67890", key.getName()); } } @@ -56,23 +58,27 @@ public void maskTest() { { ApiKey key = new ApiKey(); key.setKey("12345678901234567890"); - Assertions.assertEquals("****************7890", key.getMaskedKey()); + key.setSuffix(key.getKey().substring(key.getKey().length() - 5)); + Assertions.assertEquals("***************67890", key.getMaskedKey()); } { ApiKey key = new ApiKey(); key.setKey("1234ABCabc+_=!?-*"); - Assertions.assertEquals("*************!?-*", key.getMaskedKey()); + key.setSuffix(key.getKey().substring(key.getKey().length() - 5)); + Assertions.assertEquals("************=!?-*", key.getMaskedKey()); } { ApiKey key = new ApiKey(); - key.setKey("1234"); - Assertions.assertEquals("1234", key.getMaskedKey()); + key.setKey("12345"); + key.setSuffix(key.getKey().substring(key.getKey().length() - 5)); + Assertions.assertEquals("12345", key.getMaskedKey()); } { // test with prefix ApiKey key = new ApiKey(); key.setKey(prefix + "1234567890"); - Assertions.assertEquals(prefix + "******7890", key.getMaskedKey()); + key.setSuffix(key.getKey().substring(key.getKey().length() - 5)); + Assertions.assertEquals(prefix + "*****67890", key.getMaskedKey()); } }