diff --git a/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/RotatingKeyManager.java b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/RotatingKeyManager.java index fffe5df..588fbec 100644 --- a/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/RotatingKeyManager.java +++ b/de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/RotatingKeyManager.java @@ -1,12 +1,16 @@ /* © SRSoftware 2024 */ package de.srsoftware.oidc.backend; +import static de.srsoftware.oidc.api.Constants.EXPIRATION; +import static de.srsoftware.utils.Optionals.nullable; import static de.srsoftware.utils.Strings.uuid; import static org.jose4j.jws.AlgorithmIdentifiers.RSA_USING_SHA256; import de.srsoftware.oidc.api.KeyManager; import de.srsoftware.oidc.api.KeyStorage; import java.io.IOException; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import org.jose4j.jwk.PublicJsonWebKey; import org.jose4j.jwk.RsaJwkGenerator; import org.jose4j.lang.JoseException; @@ -21,8 +25,19 @@ public class RotatingKeyManager implements KeyManager { @Override public PublicJsonWebKey getKey() throws KeyCreationException, IOException { - var list = store.listKeys(); - return list.isEmpty() ? createNewKey() : store.load(list.get(0)); + for (var keyId : store.listKeys()) { + try { + var key = store.load(keyId); + var expired = nullable(key.getOtherParameterValue(EXPIRATION, Long.class)).map(Instant::ofEpochSecond).map(expiration -> expiration.isBefore(Instant.now())).orElse(false); + if (expired) { + store.drop(keyId); + } else + return key; + } catch (Exception e) { + LOG.log(System.Logger.Level.WARNING, "Failed to load key with id {0}", keyId); + } + } + return createNewKey(); } private PublicJsonWebKey createNewKey() throws KeyCreationException, IOException { @@ -30,7 +45,9 @@ public class RotatingKeyManager implements KeyManager { var key = RsaJwkGenerator.generateJwk(2048); key.setAlgorithm(RSA_USING_SHA256); key.setKeyId(uuid()); + key.setOtherParameter(EXPIRATION, Instant.now().plus(1, ChronoUnit.DAYS).getEpochSecond()); store.store(key); + LOG.log(System.Logger.Level.INFO, "Created new JsonWebKey (Id: {0})", key.getKeyId()); return key; } catch (JoseException e) { throw new KeyCreationException(e); diff --git a/de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/PlaintextKeyStore.java b/de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/PlaintextKeyStore.java index e941cae..c2721df 100644 --- a/de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/PlaintextKeyStore.java +++ b/de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/PlaintextKeyStore.java @@ -1,6 +1,7 @@ /* © SRSoftware 2024 */ package de.srsoftware.oidc.datastore.file; +import static java.lang.System.Logger.Level.DEBUG; import static java.lang.System.Logger.Level.ERROR; import static org.jose4j.jwk.JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE; @@ -26,7 +27,8 @@ public class PlaintextKeyStore implements KeyStorage { } @Override public KeyStorage drop(String keyId) { - return null; + if (dir.resolve(keyId + ".key").toFile().delete()) LOG.log(DEBUG, "Removed key {0}", keyId); + return this; } @Override