/*
* oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
*
* Copyright (c) 2014, Gluu
*/
package org.xdi.oxauth.service;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.gluu.site.ldap.persistence.LdapEntryManager;
import org.slf4j.Logger;
import org.xdi.oxauth.model.config.Conf;
import org.xdi.oxauth.model.config.ConfigurationFactory;
import org.xdi.oxauth.model.configuration.AppConfiguration;
import org.xdi.oxauth.model.crypto.AbstractCryptoProvider;
import org.xdi.oxauth.model.crypto.CryptoProviderFactory;
import org.xdi.oxauth.service.cdi.event.KeyGenerationEvent;
import org.xdi.service.cdi.event.Scheduled;
import org.xdi.service.timer.event.TimerEvent;
import org.xdi.service.timer.schedule.TimerSchedule;
import javax.ejb.Asynchronous;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Event;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.xdi.oxauth.model.jwk.JWKParameter.*;
/**
* @author Javier Rojas Blum
* @version June 15, 2016
*/
@ApplicationScoped
@Named
public class KeyGeneratorTimer {
private final static String EVENT_TYPE = "KeyGeneratorTimerEvent";
private final static int DEFAULT_INTERVAL = 48; // 48 hours
@Inject
private Logger log;
@Inject
private Event<TimerEvent> timerEvent;
@Inject
private ConfigurationFactory configurationFactory;
@Inject
private LdapEntryManager ldapEntryManager;
@Inject
private AppConfiguration appConfiguration;
private AtomicBoolean isActive;
public void initTimer() {
log.debug("Initializing Key Generator Timer");
this.isActive = new AtomicBoolean(false);
int interval = appConfiguration.getKeyRegenerationInterval();
if (interval <= 0) {
interval = DEFAULT_INTERVAL;
}
interval = interval * 3600;
timerEvent.fire(new TimerEvent(new TimerSchedule(interval, interval), new KeyGenerationEvent(),
Scheduled.Literal.INSTANCE));
}
@Asynchronous
public void process(@Observes @Scheduled KeyGenerationEvent keyGenerationEvent) {
if (!appConfiguration.getKeyRegenerationEnabled()) {
return;
}
if (this.isActive.get()) {
return;
}
if (!this.isActive.compareAndSet(false, true)) {
return;
}
try {
updateKeys();
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
this.isActive.set(false);
}
}
public String updateKeys() throws JSONException, Exception {
String dn = configurationFactory.getLdapConfiguration().getString("configurationEntryDN");
Conf conf = ldapEntryManager.find(Conf.class, dn);
JSONObject jwks = new JSONObject(conf.getWebKeys());
conf.setWebKeys(updateKeys(jwks).toString());
long nextRevision = conf.getRevision() + 1;
conf.setRevision(nextRevision);
ldapEntryManager.merge(conf);
return conf.getWebKeys();
}
private JSONObject updateKeys(JSONObject jwks) throws Exception {
JSONObject jsonObject = AbstractCryptoProvider.generateJwks(appConfiguration.getKeyRegenerationInterval(),
appConfiguration.getIdTokenLifetime(), appConfiguration);
JSONArray keys = jwks.getJSONArray(JSON_WEB_KEY_SET);
for (int i = 0; i < keys.length(); i++) {
JSONObject key = keys.getJSONObject(i);
if (key.has(EXPIRATION_TIME) && !key.isNull(EXPIRATION_TIME)) {
GregorianCalendar now = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
GregorianCalendar expirationDate = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
expirationDate.setTimeInMillis(key.getLong(EXPIRATION_TIME));
if (expirationDate.before(now)) {
// The expired key is not added to the array of keys
log.debug("Removing JWK: {}, Expiration date: {}", key.getString(KEY_ID),
key.getString(EXPIRATION_TIME));
AbstractCryptoProvider cryptoProvider = CryptoProviderFactory.getCryptoProvider(appConfiguration);
cryptoProvider.deleteKey(key.getString(KEY_ID));
} else {
jsonObject.getJSONArray(JSON_WEB_KEY_SET).put(key);
}
} else {
GregorianCalendar expirationTime = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
expirationTime.add(GregorianCalendar.HOUR, appConfiguration.getKeyRegenerationInterval());
expirationTime.add(GregorianCalendar.SECOND, appConfiguration.getIdTokenLifetime());
key.put(EXPIRATION_TIME, expirationTime.getTimeInMillis());
jsonObject.getJSONArray(JSON_WEB_KEY_SET).put(key);
}
}
return jsonObject;
}
}