package org.gcube.keycloak.event; import java.net.MalformedURLException; import java.net.URL; import org.jboss.logging.Logger; import org.keycloak.Config.Scope; import org.keycloak.events.EventListenerProviderFactory; import org.keycloak.models.ClientModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.RealmModel; /** * @author Marco Lettere * @author Mauro Mugnaini */ public class OrchestratorEventPublisherProviderFactory implements EventListenerProviderFactory { private static final Logger logger = Logger.getLogger(OrchestratorEventPublisherProviderFactory.class); public static final String MASTER_REALM_NAME = "master"; public static final String ORCHESTRATOR_CLIENT_ID = "orchestrator"; public static final String KEYCLOAK_CLIENT_ID = "keycloak-client"; private static final int CHECK_DELAY = 60 * 1000; // One minute public static URL ORCHESTRATOR_ENDPOINT; public static URL KEYCLOAK_ENDPOINT; public static String KEYCLOAK_CLIENT_SECRET; protected Long lastEndpointCheck = new Long(0); protected OrchestratorEventPublisherProvider oepp; public OrchestratorEventPublisherProviderFactory() { logger.info("New OrchestratorEventPublisherProviderFactory has been created"); } @Override public void close() { } @Override public synchronized OrchestratorEventPublisherProvider create(KeycloakSession keycloakSession) { Long now = System.currentTimeMillis(); Long elapsed = now - lastEndpointCheck; if (oepp == null || elapsed > CHECK_DELAY) { lastEndpointCheck = now; ClientModel orchestratorClient = getClientInActualOrMasterRealm(keycloakSession, ORCHESTRATOR_CLIENT_ID); ClientModel keycloakClient = getClientInActualOrMasterRealm(keycloakSession, KEYCLOAK_CLIENT_ID); logger.debug("Getting configured orchestrator endpoint address from client's base URL"); String orchestratorAddress = orchestratorClient.getBaseUrl(); logger.debug("Getting configured keycloak endpoint address from client's base URL"); String keycloakAddress = keycloakClient.getBaseUrl(); logger.debug("Getting configured keycloak client client-secret from client"); String keycloakClientSecret = keycloakClient.getSecret(); URL newOrchestratorEndpoint; URL newKeycloakEndpoint; try { newOrchestratorEndpoint = new URL(orchestratorAddress); } catch (MalformedURLException e) { logger.errorf("Can't create new orchestrator endpoint address: %s", orchestratorAddress, e); oepp = null; return null; } try { newKeycloakEndpoint = new URL(keycloakAddress); } catch (MalformedURLException e) { logger.errorf("Can't create new keycloak token address: %s", keycloakAddress, e); oepp = null; return null; } if (oepp == null || !newOrchestratorEndpoint.equals(ORCHESTRATOR_ENDPOINT) || !newKeycloakEndpoint.equals(KEYCLOAK_ENDPOINT) || !keycloakClientSecret.equals(KEYCLOAK_CLIENT_SECRET)) { logger.infof("Creating new orchestrator event publisher provider for endpoint: %s", orchestratorAddress); // Address and other fileds will be then read from static fields in this class by // the createEventSender() called by the superclass' constructor, overridden in the impl. ORCHESTRATOR_ENDPOINT = newOrchestratorEndpoint; KEYCLOAK_ENDPOINT = newKeycloakEndpoint; KEYCLOAK_CLIENT_SECRET = keycloakClientSecret; oepp = new OrchestratorEventPublisherProvider(); } } else { logger.debugf("Next check is in %d millis", CHECK_DELAY - elapsed); } return oepp; } protected ClientModel getClientInActualOrMasterRealm(KeycloakSession keycloakSession, String clientId) { logger.debug("Getting actual realm from session's context"); RealmModel realm = keycloakSession.getContext().getRealm(); logger.debugf("Trying getting '%s' client in current realm '%s'", clientId, realm.getName()); ClientModel client = realm.getClientByClientId(clientId); if (client == null) { logger.debugf("Not found. Now trying getting '%s' in '%s' realm", clientId, MASTER_REALM_NAME); realm = keycloakSession.realms().getRealmByName(MASTER_REALM_NAME); client = realm.getClientByClientId(clientId); if (client == null) { logger.warnf("Cannot find '%s' client not even in '%s' realm", clientId, realm.getName(), MASTER_REALM_NAME); return null; } } return client; } @Override public String getId() { return "orchestrator-event-publisher"; } @Override public void init(Scope scope) { } @Override public void postInit(KeycloakSessionFactory keycloakSessionFactory) { } }