All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pl.edu.icm.unity.engine.endpoint.EndpointsUpdater Maven / Gradle / Ivy

/*
 * Copyright (c) 2013 ICM Uniwersytet Warszawski All rights reserved.
 * See LICENCE.txt file for licensing information.
 */
package pl.edu.icm.unity.engine.endpoint;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import eu.unicore.util.configuration.ConfigurationException;
import pl.edu.icm.unity.base.utils.Log;
import pl.edu.icm.unity.engine.api.authn.AuthenticationFlow;
import pl.edu.icm.unity.engine.api.authn.AuthenticatorInstance;
import pl.edu.icm.unity.engine.api.endpoint.EndpointInstance;
import pl.edu.icm.unity.engine.utils.ScheduledUpdaterBase;
import pl.edu.icm.unity.exceptions.EngineException;
import pl.edu.icm.unity.store.api.generic.AuthenticationFlowDB;
import pl.edu.icm.unity.store.api.generic.AuthenticatorConfigurationDB;
import pl.edu.icm.unity.store.api.generic.EndpointDB;
import pl.edu.icm.unity.store.api.generic.RealmDB;
import pl.edu.icm.unity.store.api.tx.TransactionalRunner;
import pl.edu.icm.unity.store.types.AuthenticatorConfiguration;
import pl.edu.icm.unity.types.authn.AuthenticationFlowDefinition;
import pl.edu.icm.unity.types.authn.AuthenticationRealm;
import pl.edu.icm.unity.types.endpoint.Endpoint;
import pl.edu.icm.unity.types.endpoint.Endpoint.EndpointState;


/**
 * Allows for scanning the DB endpoints state. If it is detected during the scan that runtime configuration 
 * is outdated wrt DB contents, then the reconfiguration is done: existing endpoints are undeployed,
 * and redeployed from configuration.
 * 

* To ensure synchronization this class is used by two components: periodically (to refresh state changes * by another Unity instance) and manually by endpoints management (to refresh the state after local changes * without waiting for the periodic update). * * @author K. Benedyczak */ @Component public class EndpointsUpdater extends ScheduledUpdaterBase { private static final Logger log = Log.getLogger(Log.U_SERVER_CORE, EndpointsUpdater.class); private InternalEndpointManagement endpointMan; private EndpointDB endpointDB; private RealmDB realmDB; private AuthenticatorConfigurationDB authnDB; private AuthenticationFlowDB authnFlowDB; private EndpointInstanceLoader loader; private TransactionalRunner tx; @Autowired public EndpointsUpdater(TransactionalRunner tx, InternalEndpointManagement endpointMan, EndpointDB endpointDB, AuthenticatorConfigurationDB authnDB, AuthenticationFlowDB authnFlowDB, EndpointInstanceLoader loader, RealmDB realmDB) { super("endpoints"); this.tx = tx; this.endpointMan = endpointMan; this.endpointDB = endpointDB; this.authnDB = authnDB; this.loader = loader; this.authnFlowDB = authnFlowDB; this.realmDB = realmDB; } @Override protected void updateInternal() throws EngineException { List deployedEndpoints = endpointMan.getDeployedEndpoints(); Set endpointsInDb = new HashSet<>(); Map endpointsDeployed = new HashMap<>(); for (EndpointInstance endpoint: deployedEndpoints) endpointsDeployed.put(endpoint.getEndpointDescription().getName(), endpoint); log.debug("Running periodic endpoints update task. There are " + deployedEndpoints.size() + " deployed endpoints."); try { tx.runInTransactionThrowing(() -> { Map allRealmsAsMap = realmDB.getAllAsMap(); long roundedUpdateTime = roundToS(System.currentTimeMillis()); List endpointsInDBMap = endpointDB.getAll(); log.debug("There are " + endpointsInDBMap.size() + " endpoints in DB."); for (Endpoint endpointInDB : endpointsInDBMap) { if (endpointInDB.getState().equals(EndpointState.UNDEPLOYED)) continue; EndpointInstance instance = updateEndpoint(endpointInDB, endpointsDeployed, allRealmsAsMap); endpointsInDb.add(instance.getEndpointDescription().getName()); } setLastUpdate(roundedUpdateTime); undeployInactive(endpointsInDb, deployedEndpoints); }); } catch (EndpointConfigurationException e) { log.error("Can not update endpoint", e); undeployAndChangeStateToUndeployedWhenInvalidConfiguration(e.endpoint); throw e.exception; } } private EndpointInstance updateEndpoint(Endpoint endpointInDB, Map endpointsDeployed, Map allRealmsAsMap) throws EngineException { String name = endpointInDB.getName(); EndpointInstance runtimeEndpointInstance = endpointsDeployed.get(name); EndpointInstance updatedInstance = null; if (runtimeEndpointInstance == null) { updatedInstance = createEndpointInstance(endpointInDB); log.info("Endpoint " + name + " will be deployed"); endpointMan.deploy(updatedInstance); } else if (endpointInDB.getRevision() > runtimeEndpointInstance.getEndpointDescription() .getEndpoint() .getRevision() || hasChangedRealm(runtimeEndpointInstance, allRealmsAsMap)) { updatedInstance = createEndpointInstance(endpointInDB); log.info("Endpoint " + name + " will be re-deployed"); endpointMan.undeploy(name); endpointMan.deploy(updatedInstance); } else if (hasChangedAuthenticationFlow(runtimeEndpointInstance)) { updatedInstance = createEndpointInstance(endpointInDB); updateEndpointAuthenticators(name, updatedInstance, endpointsDeployed); } else if (hasChangedAuthenticator(runtimeEndpointInstance)) { updatedInstance = createEndpointInstance(endpointInDB); updateEndpointAuthenticators(name, updatedInstance, endpointsDeployed); } return updatedInstance == null ? runtimeEndpointInstance : updatedInstance; } private EndpointInstance createEndpointInstance(Endpoint endpointInDB) throws EndpointConfigurationException { try { return loader.createEndpointInstance(endpointInDB); } catch (ConfigurationException e) { throw new EndpointConfigurationException(endpointInDB, e); } } private void undeployAndChangeStateToUndeployedWhenInvalidConfiguration(Endpoint endpointInDB) throws EngineException { tx.runInTransactionThrowing(() -> { endpointMan.undeploy(endpointInDB.getName()); Endpoint updatedEndpoint = new Endpoint(endpointInDB.getName(), endpointInDB.getTypeId(), endpointInDB.getContextAddress(), endpointInDB.getConfiguration(), endpointInDB.getRevision() + 1, EndpointState.UNDEPLOYED); endpointDB.update(updatedEndpoint); }); } private void updateEndpointAuthenticators(String name, EndpointInstance instance, Map endpointsDeployed) throws EngineException { log.info("Endpoint " + name + " will have its authenticators updated"); EndpointInstance toUpdate = endpointsDeployed.get(name); try { toUpdate.updateAuthenticationFlows(instance.getAuthenticationFlows()); } catch (UnsupportedOperationException e) { log.info("Endpoint " + name + " doesn't support authenticators update so will be redeployed"); endpointMan.undeploy(instance.getEndpointDescription().getEndpoint().getName()); endpointMan.deploy(instance); } } private boolean hasChangedRealm(EndpointInstance endpointInstance, Map allRealmsAsMap) { AuthenticationRealm currentRealm = endpointInstance.getEndpointDescription() .getRealm(); if (currentRealm == null) return false; AuthenticationRealm dbRealm = allRealmsAsMap.get(currentRealm.getName()); return !dbRealm.equals(currentRealm); } /** * @param instance * @return true if one of authenticator from instance is changed */ private boolean hasChangedAuthenticator(EndpointInstance instance) { Map revisionMap = new HashMap<>(); for (AuthenticationFlow flow : instance.getAuthenticationFlows()) { for (AuthenticatorInstance authenticator : flow.getAllAuthenticators()) { revisionMap.put(authenticator.getRetrieval().getAuthenticatorId(), authenticator.getRevision()); } } Map allAuth = authnDB.getAllAsMap(); for (String authn : revisionMap.keySet()) { AuthenticatorConfiguration authInstance = allAuth.get(authn); if (authInstance != null) { if (authInstance.getRevision() > revisionMap.get(authn)) { return true; } } } return false; } /** * @param instance * @return true if one of authentication flow from instance is changed */ private boolean hasChangedAuthenticationFlow(EndpointInstance instance) { Map all = authnFlowDB.getAllAsMap(); for (AuthenticationFlow flow : instance.getAuthenticationFlows()) { AuthenticationFlowDefinition dbFlowDefinition = all.get(flow.getId()); if (dbFlowDefinition != null) { if (dbFlowDefinition.getRevision() > flow.getRevision()) return true; } } return false; } private void undeployInactive(Set endpointsInDb, Collection deployedEndpoints) throws EngineException { for (EndpointInstance endpoint: deployedEndpoints) { String name = endpoint.getEndpointDescription().getName(); if (!endpointsInDb.contains(name)) { log.info("Undeploying endpoint: " + name); endpointMan.undeploy(name); } } } private static class EndpointConfigurationException extends EngineException { final Endpoint endpoint; final ConfigurationException exception; EndpointConfigurationException(Endpoint endpoint, ConfigurationException exception) { this.endpoint = endpoint; this.exception = exception; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy