|
|
@ -1,12 +1,16 @@ |
|
|
|
/* © SRSoftware 2024 */ |
|
|
|
/* © SRSoftware 2024 */ |
|
|
|
package de.srsoftware.oidc.backend; |
|
|
|
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 de.srsoftware.utils.Strings.uuid; |
|
|
|
import static org.jose4j.jws.AlgorithmIdentifiers.RSA_USING_SHA256; |
|
|
|
import static org.jose4j.jws.AlgorithmIdentifiers.RSA_USING_SHA256; |
|
|
|
|
|
|
|
|
|
|
|
import de.srsoftware.oidc.api.KeyManager; |
|
|
|
import de.srsoftware.oidc.api.KeyManager; |
|
|
|
import de.srsoftware.oidc.api.KeyStorage; |
|
|
|
import de.srsoftware.oidc.api.KeyStorage; |
|
|
|
import java.io.IOException; |
|
|
|
import java.io.IOException; |
|
|
|
|
|
|
|
import java.time.Instant; |
|
|
|
|
|
|
|
import java.time.temporal.ChronoUnit; |
|
|
|
import org.jose4j.jwk.PublicJsonWebKey; |
|
|
|
import org.jose4j.jwk.PublicJsonWebKey; |
|
|
|
import org.jose4j.jwk.RsaJwkGenerator; |
|
|
|
import org.jose4j.jwk.RsaJwkGenerator; |
|
|
|
import org.jose4j.lang.JoseException; |
|
|
|
import org.jose4j.lang.JoseException; |
|
|
@ -21,8 +25,19 @@ public class RotatingKeyManager implements KeyManager { |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public PublicJsonWebKey getKey() throws KeyCreationException, IOException { |
|
|
|
public PublicJsonWebKey getKey() throws KeyCreationException, IOException { |
|
|
|
var list = store.listKeys(); |
|
|
|
for (var keyId : store.listKeys()) { |
|
|
|
return list.isEmpty() ? createNewKey() : store.load(list.get(0)); |
|
|
|
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 { |
|
|
|
private PublicJsonWebKey createNewKey() throws KeyCreationException, IOException { |
|
|
@ -30,7 +45,9 @@ public class RotatingKeyManager implements KeyManager { |
|
|
|
var key = RsaJwkGenerator.generateJwk(2048); |
|
|
|
var key = RsaJwkGenerator.generateJwk(2048); |
|
|
|
key.setAlgorithm(RSA_USING_SHA256); |
|
|
|
key.setAlgorithm(RSA_USING_SHA256); |
|
|
|
key.setKeyId(uuid()); |
|
|
|
key.setKeyId(uuid()); |
|
|
|
|
|
|
|
key.setOtherParameter(EXPIRATION, Instant.now().plus(1, ChronoUnit.DAYS).getEpochSecond()); |
|
|
|
store.store(key); |
|
|
|
store.store(key); |
|
|
|
|
|
|
|
LOG.log(System.Logger.Level.INFO, "Created new JsonWebKey (Id: {0})", key.getKeyId()); |
|
|
|
return key; |
|
|
|
return key; |
|
|
|
} catch (JoseException e) { |
|
|
|
} catch (JoseException e) { |
|
|
|
throw new KeyCreationException(e); |
|
|
|
throw new KeyCreationException(e); |
|
|
|