/*
* 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.gluu.site.ldap.persistence.BatchOperation;
import org.gluu.site.ldap.persistence.LdapEntryManager;
import org.slf4j.Logger;
import org.xdi.model.ApplicationType;
import org.xdi.oxauth.model.common.AuthorizationGrant;
import org.xdi.oxauth.model.common.AuthorizationGrantList;
import org.xdi.oxauth.model.configuration.AppConfiguration;
import org.xdi.oxauth.model.fido.u2f.DeviceRegistration;
import org.xdi.oxauth.model.fido.u2f.RequestMessageLdap;
import org.xdi.oxauth.model.registration.Client;
import org.xdi.oxauth.service.cdi.event.CleanerEvent;
import org.xdi.oxauth.service.fido.u2f.DeviceRegistrationService;
import org.xdi.oxauth.service.fido.u2f.RequestService;
import org.xdi.oxauth.service.uma.ResourceSetPermissionManager;
import org.xdi.oxauth.service.uma.RptManager;
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.ejb.DependsOn;
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.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author Yuriy Zabrovarnyy
* @author Javier Rojas Blum
* @version December 15, 2015
*/
@ApplicationScoped
@DependsOn("appInitializer")
@Named
public class CleanerTimer {
public final static int BATCH_SIZE = 100;
private final static int DEFAULT_INTERVAL = 600; // 10 minutes
@Inject
private Logger log;
@Inject
private LdapEntryManager ldapEntryManager;
@Inject
private AuthorizationGrantList authorizationGrantList;
@Inject
private ClientService clientService;
@Inject
private GrantService grantService;
@Inject
private RptManager rptManager;
@Inject
private ResourceSetPermissionManager resourceSetPermissionManager;
@Inject
private SessionStateService sessionStateService;
@Inject @Named("u2fRequestService")
private RequestService u2fRequestService;
@Inject
private MetricService metricService;
@Inject
private DeviceRegistrationService deviceRegistrationService;
@Inject
private AppConfiguration appConfiguration;
@Inject
private Event<TimerEvent> cleanerEvent;
private AtomicBoolean isActive;
public void initTimer() {
log.debug("Initializing Cleaner Timer");
this.isActive = new AtomicBoolean(false);
int interval = appConfiguration.getCleanServiceInterval();
if (interval <= 0) {
interval = DEFAULT_INTERVAL;
}
cleanerEvent.fire(new TimerEvent(new TimerSchedule(30, 30), new CleanerEvent(), Scheduled.Literal.INSTANCE));
}
@Asynchronous
public void process(@Observes @Scheduled CleanerEvent cleanerEvent) {
if (this.isActive.get()) {
return;
}
if (!this.isActive.compareAndSet(false, true)) {
return;
}
try {
processAuthorizationGrantList();
processRegisteredClients();
Date now = new Date();
this.rptManager.cleanupRPTs(now);
this.resourceSetPermissionManager.cleanupResourceSetPermissions(now);
processU2fRequests();
processU2fDeviceRegistrations();
processMetricEntries();
} finally {
this.isActive.set(false);
}
}
private void processAuthorizationGrantList() {
log.debug("Start AuthorizationGrant clean up");
grantService.cleanUp();
log.debug("End AuthorizationGrant clean up");
}
private void processRegisteredClients() {
log.debug("Start Client clean up");
BatchOperation<Client> clientBatchService = new BatchOperation<Client>(ldapEntryManager) {
@Override
protected List<Client> getChunkOrNull(int chunkSize) {
return clientService.getClientsWithExpirationDate(this, chunkSize, chunkSize);
}
@Override
protected void performAction(List<Client> entries) {
for (Client client : entries) {
try {
GregorianCalendar now = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
GregorianCalendar expirationDate = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
expirationDate.setTime(client.getClientSecretExpiresAt());
if (expirationDate.before(now)) {
List<AuthorizationGrant> toRemove = authorizationGrantList.getAuthorizationGrant(client.getClientId());
authorizationGrantList.removeAuthorizationGrants(toRemove);
log.debug("Removing Client: {}, Expiration date: {}",
client.getClientId(),
client.getClientSecretExpiresAt());
clientService.remove(client);
}
} catch (Exception e) {
log.error("Failed to remove entry", e);
}
}
}
};
clientBatchService.iterateAllByChunks(BATCH_SIZE);
log.debug("End Client clean up");
}
private void processU2fRequests() {
log.debug("Start U2F request clean up");
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.add(Calendar.SECOND, -90);
final Date expirationDate = calendar.getTime();
BatchOperation<RequestMessageLdap> requestMessageLdapBatchService = new BatchOperation<RequestMessageLdap>(ldapEntryManager) {
@Override
protected List<RequestMessageLdap> getChunkOrNull(int chunkSize) {
return u2fRequestService.getExpiredRequestMessages(this, expirationDate);
}
@Override
protected void performAction(List<RequestMessageLdap> entries) {
for (RequestMessageLdap requestMessageLdap : entries) {
try {
log.debug("Removing RequestMessageLdap: {}, Creation date: {}",
requestMessageLdap.getRequestId(),
requestMessageLdap.getCreationDate());
u2fRequestService.removeRequestMessage(requestMessageLdap);
} catch (Exception e) {
log.error("Failed to remove entry", e);
}
}
}
};
requestMessageLdapBatchService.iterateAllByChunks(BATCH_SIZE);
log.debug("End U2F request clean up");
}
private void processU2fDeviceRegistrations() {
log.debug("Start U2F request clean up");
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.add(Calendar.SECOND, -90);
final Date expirationDate = calendar.getTime();
BatchOperation<DeviceRegistration> deviceRegistrationBatchService = new BatchOperation<DeviceRegistration>(ldapEntryManager) {
@Override
protected List<DeviceRegistration> getChunkOrNull(int chunkSize) {
return deviceRegistrationService.getExpiredDeviceRegistrations(this, expirationDate);
}
@Override
protected void performAction(List<DeviceRegistration> entries) {
for (DeviceRegistration deviceRegistration : entries) {
try {
log.debug("Removing DeviceRegistration: {}, Creation date: {}",
deviceRegistration.getId(),
deviceRegistration.getCreationDate());
deviceRegistrationService.removeUserDeviceRegistration(deviceRegistration);
}
catch (Exception e){
log.error("Failed to remove entry", e);
}
}
}
};
deviceRegistrationBatchService.iterateAllByChunks(BATCH_SIZE);
log.debug("End U2F request clean up");
}
private void processMetricEntries() {
log.debug("Start metric entries clean up");
int keepDataDays = appConfiguration.getMetricReporterKeepDataDays();
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.add(Calendar.DATE, -keepDataDays);
Date expirationDate = calendar.getTime();
metricService.removeExpiredMetricEntries(BATCH_SIZE, expirationDate, ApplicationType.OX_AUTH, metricService.applianceInum());
log.debug("End metric entries clean up");
}
}