diff --git a/events/api/src/main/java/org/keycloak/events/Details.java b/events/api/src/main/java/org/keycloak/events/Details.java index 50921dd892..1ca58ecce4 100755 --- a/events/api/src/main/java/org/keycloak/events/Details.java +++ b/events/api/src/main/java/org/keycloak/events/Details.java @@ -19,5 +19,5 @@ public interface Details { String REFRESH_TOKEN_ID = "refresh_token_id"; String VALIDATE_ACCESS_TOKEN = "validate_access_token"; String UPDATED_REFRESH_TOKEN_ID = "updated_refresh_token_id"; - + String NODE_HOST = "node_host"; } diff --git a/examples/demo-template/customer-app/src/main/webapp/customers/session.jsp b/examples/demo-template/customer-app/src/main/webapp/customers/session.jsp index ba8583dff9..2bd9d1664a 100755 --- a/examples/demo-template/customer-app/src/main/webapp/customers/session.jsp +++ b/examples/demo-template/customer-app/src/main/webapp/customers/session.jsp @@ -3,13 +3,13 @@ <%@ page import="org.keycloak.ServiceUrlConstants" %> <%@ page import="org.keycloak.example.CustomerDatabaseClient" %> <%@ page import="org.keycloak.representations.IDToken" %> -<%@ page import="org.keycloak.util.UriUtils" %> +<%@ page import="org.keycloak.util.HostUtils" %> Customer Session Page -

Your hostname: <%= UriUtils.getHostName() %>

+

Your hostname: <%= HostUtils.getHostName() %>

Your session ID: <%= request.getSession().getId() %>

You visited this page <%= CustomerDatabaseClient.increaseAndGetCounter(request) %> times.



diff --git a/examples/demo-template/testrealm.json b/examples/demo-template/testrealm.json index a2a3a96bfe..da92138a4e 100755 --- a/examples/demo-template/testrealm.json +++ b/examples/demo-template/testrealm.json @@ -147,8 +147,7 @@ "enabled": true, "adminUrl": "/database", "baseUrl": "/database", - "bearerOnly": true, - "secret": "password" + "bearerOnly": true } ], "oauthClients": [ diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java index 1095b47ce7..c2d60d10f1 100755 --- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java +++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java @@ -85,12 +85,16 @@ public class KeycloakDeployment { return authServerBaseUrl; } - public void setAuthServerBaseUrl(String authServerBaseUrl, AdapterConfig config) { - this.authServerBaseUrl = authServerBaseUrl; - if (authServerBaseUrl == null) return; + public void setAuthServerBaseUrl(AdapterConfig config) { + this.authServerBaseUrl = config.getAuthServerUrl(); + if (authServerBaseUrl == null && config.getAuthServerUrlForBackendRequests() == null) return; - URI uri = URI.create(authServerBaseUrl); - if (uri.getHost() == null) { + URI authServerUri = null; + if (authServerBaseUrl != null) { + authServerUri = URI.create(authServerBaseUrl); + } + + if (authServerUri == null || authServerUri.getHost() == null) { String authServerURLForBackendReqs = config.getAuthServerUrlForBackendRequests(); if (authServerURLForBackendReqs != null) { relativeUrls = RelativeUrlsUsed.BROWSER_ONLY; diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java index cbb5fef00e..8913dd4e30 100755 --- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java +++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java @@ -73,7 +73,7 @@ public class KeycloakDeploymentBuilder { if (adapterConfig.getAuthServerUrl() == null && (!deployment.isBearerOnly() || realmKeyPem == null)) { throw new RuntimeException("You must specify auth-url"); } - deployment.setAuthServerBaseUrl(adapterConfig.getAuthServerUrl(), adapterConfig); + deployment.setAuthServerBaseUrl(adapterConfig); log.debug("Use authServerUrl: " + deployment.getAuthServerBaseUrl() + ", codeUrl: " + deployment.getCodeUrl() + ", relativeUrls: " + deployment.getRelativeUrls()); return deployment; diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationLifecycle.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationLifecycle.java deleted file mode 100644 index b344702812..0000000000 --- a/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationLifecycle.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.keycloak.adapters; - -import java.io.IOException; -import java.util.Timer; -import java.util.TimerTask; - -import org.jboss.logging.Logger; -import org.keycloak.enums.RelativeUrlsUsed; -import org.keycloak.util.HostUtils; - -/** - * @author Marek Posolda - */ -public class NodesRegistrationLifecycle { - - private static final Logger log = Logger.getLogger(NodesRegistrationLifecycle.class); - - private final KeycloakDeployment deployment; - private final Timer timer; - - // True if at least one event was successfully sent - private volatile boolean registered = false; - - public NodesRegistrationLifecycle(KeycloakDeployment deployment) { - this.deployment = deployment; - this.timer = new Timer(); - } - - public void start() { - if (!deployment.isRegisterNodeAtStartup() && deployment.getRegisterNodePeriod() <= 0) { - log.info("Skip registration of cluster nodes at startup"); - return; - } - - if (deployment.getRelativeUrls() == RelativeUrlsUsed.ALL_REQUESTS) { - log.warn("Skip registration of cluster nodes at startup as Keycloak node can't be contacted. Make sure to not use relative URI in adapters configuration!"); - return; - } - - if (deployment.isRegisterNodeAtStartup()) { - boolean success = sendRegistrationEvent(); - if (!success) { - throw new IllegalStateException("Failed to register node to keycloak at startup"); - } - } - - if (deployment.getRegisterNodePeriod() > 0) { - addPeriodicListener(); - } - } - - public void stop() { - removePeriodicListener(); - if (registered) { - sendUnregistrationEvent(); - } - } - - protected void addPeriodicListener() { - TimerTask task = new TimerTask() { - - @Override - public void run() { - sendRegistrationEvent(); - } - }; - - long interval = deployment.getRegisterNodePeriod() * 1000; - log.info("Setup of periodic re-registration event sending each " + interval + " ms"); - timer.schedule(task, interval, interval); - } - - protected void removePeriodicListener() { - timer.cancel(); - } - - protected boolean sendRegistrationEvent() { - log.info("Sending registration event right now"); - - String host = HostUtils.getIpAddress(); - try { - ServerRequest.invokeRegisterNode(deployment, host); - log.infof("Node '%s' successfully registered in Keycloak", host); - registered = true; - return true; - } catch (ServerRequest.HttpFailure failure) { - log.error("failed to register node to keycloak"); - log.error("status from server: " + failure.getStatus()); - if (failure.getError() != null) { - log.error(" " + failure.getError()); - } - return false; - } catch (IOException e) { - log.error("failed to register node to keycloak", e); - return false; - } - } - - protected boolean sendUnregistrationEvent() { - log.info("Sending UNregistration event right now"); - - String host = HostUtils.getIpAddress(); - try { - ServerRequest.invokeUnregisterNode(deployment, host); - log.infof("Node '%s' successfully unregistered from Keycloak", host); - return true; - } catch (ServerRequest.HttpFailure failure) { - log.error("failed to unregister node from keycloak"); - log.error("status from server: " + failure.getStatus()); - if (failure.getError() != null) { - log.error(" " + failure.getError()); - } - return false; - } catch (IOException e) { - log.error("failed to unregister node from keycloak", e); - return false; - } - } - -} diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java new file mode 100644 index 0000000000..5365620d8b --- /dev/null +++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java @@ -0,0 +1,117 @@ +package org.keycloak.adapters; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import org.jboss.logging.Logger; +import org.keycloak.util.HostUtils; +import org.keycloak.util.Time; + +/** + * @author Marek Posolda + */ +public class NodesRegistrationManagement { + + private static final Logger log = Logger.getLogger(NodesRegistrationManagement.class); + + private final Map nodeRegistrations = new ConcurrentHashMap(); + private final Executor executor = Executors.newSingleThreadExecutor(); + + // Sending registration event during first request to application or if re-registration is needed + public void tryRegister(final KeycloakDeployment resolvedDeployment) { + if (resolvedDeployment.isRegisterNodeAtStartup()) { + final String registrationUri = resolvedDeployment.getRegisterNodeUrl(); + if (needRefreshRegistration(registrationUri, resolvedDeployment)) { + Runnable runnable = new Runnable() { + + @Override + public void run() { + // Need to check it again in case that executor triggered by other thread already finished computation in the meantime + if (needRefreshRegistration(registrationUri, resolvedDeployment)) { + sendRegistrationEvent(resolvedDeployment); + } + } + }; + executor.execute(runnable); + } + } + } + + private boolean needRefreshRegistration(String registrationUri, KeycloakDeployment resolvedDeployment) { + NodeRegistrationContext currentRegistration = nodeRegistrations.get(registrationUri); + /// We don't yet have any registration for this node + if (currentRegistration == null) { + return true; + } + + return currentRegistration.lastRegistrationTime + resolvedDeployment.getRegisterNodePeriod() < Time.currentTime(); + } + + /** + * Called during undeployment or server stop. De-register from all previously registered deployments + */ + public void stop() { + Collection allRegistrations = nodeRegistrations.values(); + for (NodeRegistrationContext registration : allRegistrations) { + sendUnregistrationEvent(registration.resolvedDeployment); + } + } + + protected void sendRegistrationEvent(KeycloakDeployment deployment) { + log.info("Sending registration event right now"); + + String host = HostUtils.getIpAddress(); + try { + ServerRequest.invokeRegisterNode(deployment, host); + NodeRegistrationContext regContext = new NodeRegistrationContext(Time.currentTime(), deployment); + nodeRegistrations.put(deployment.getRegisterNodeUrl(), regContext); + log.infof("Node '%s' successfully registered in Keycloak", host); + } catch (ServerRequest.HttpFailure failure) { + log.error("failed to register node to keycloak"); + log.error("status from server: " + failure.getStatus()); + if (failure.getError() != null) { + log.error(" " + failure.getError()); + } + } catch (IOException e) { + log.error("failed to register node to keycloak", e); + } + } + + protected boolean sendUnregistrationEvent(KeycloakDeployment deployment) { + log.info("Sending Unregistration event right now"); + + String host = HostUtils.getIpAddress(); + try { + ServerRequest.invokeUnregisterNode(deployment, host); + log.infof("Node '%s' successfully unregistered from Keycloak", host); + return true; + } catch (ServerRequest.HttpFailure failure) { + log.error("failed to unregister node from keycloak"); + log.error("status from server: " + failure.getStatus()); + if (failure.getError() != null) { + log.error(" " + failure.getError()); + } + return false; + } catch (IOException e) { + log.error("failed to unregister node from keycloak", e); + return false; + } + } + + public static class NodeRegistrationContext { + + private final Integer lastRegistrationTime; + // deployment instance used for registration request + private final KeycloakDeployment resolvedDeployment; + + public NodeRegistrationContext(Integer lastRegTime, KeycloakDeployment deployment) { + this.lastRegistrationTime = lastRegTime; + this.resolvedDeployment = deployment; + } + } + +} diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java index a55fb97251..83cad53a19 100755 --- a/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java +++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java @@ -58,6 +58,7 @@ public class PreAuthActionsHandler { handleVersion(); return true; } else if (requestUri.endsWith(AdapterConstants.K_TEST_AVAILABLE)) { + if (!resolveDeployment()) return true; handleTestAvailable(); return true; } diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java index 438ad63cfe..f4a3142854 100755 --- a/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java +++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java @@ -231,6 +231,10 @@ public class ServerRequest { } public static void invokeClientManagementRequest(HttpClient client, String host, String endpointUrl, String clientId, Map credentials) throws HttpFailure, IOException { + if (endpointUrl == null) { + throw new IOException("You need to configure URI for register/unregister node for application " + clientId); + } + List formparams = new ArrayList(); formparams.add(new BasicNameValuePair(AdapterConstants.APPLICATION_CLUSTER_HOST, host)); @@ -240,6 +244,8 @@ public class ServerRequest { if (clientSecret != null) { String authorization = BasicAuthHelper.createHeader(clientId, clientSecret); post.setHeader("Authorization", authorization); + } else { + throw new IOException("You need to configure clientSecret for register/unregister node for application " + clientId); } UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8"); diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java index b21653eb40..8b40abb567 100755 --- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java +++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java @@ -21,7 +21,7 @@ import org.keycloak.adapters.AuthOutcome; import org.keycloak.adapters.HttpFacade; import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeploymentBuilder; -import org.keycloak.adapters.NodesRegistrationLifecycle; +import org.keycloak.adapters.NodesRegistrationManagement; import org.keycloak.adapters.PreAuthActionsHandler; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; @@ -47,7 +47,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif private static final Logger log = Logger.getLogger(KeycloakAuthenticatorValve.class); protected CatalinaUserSessionManagement userSessionManagement = new CatalinaUserSessionManagement(); protected AdapterDeploymentContext deploymentContext; - protected NodesRegistrationLifecycle nodesRegistrationLifecycle; + protected NodesRegistrationManagement nodesRegistrationManagement; @Override @@ -127,12 +127,11 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer(), getController()); setNext(actions); - nodesRegistrationLifecycle = new NodesRegistrationLifecycle(kd); - nodesRegistrationLifecycle.start(); + nodesRegistrationManagement = new NodesRegistrationManagement(); } protected void beforeStop() { - nodesRegistrationLifecycle.stop(); + nodesRegistrationManagement.stop(); } @Override @@ -166,6 +165,8 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif return false; } + nodesRegistrationManagement.tryRegister(deployment); + CatalinaRequestAuthenticator authenticator = new CatalinaRequestAuthenticator(deployment, this, userSessionManagement, facade, request); AuthOutcome outcome = authenticator.authenticate(); if (outcome == AuthOutcome.AUTHENTICATED) { diff --git a/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java index 0d45009f24..94447a1a59 100755 --- a/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java +++ b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java @@ -20,7 +20,7 @@ import org.keycloak.adapters.AuthOutcome; import org.keycloak.adapters.HttpFacade; import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeploymentBuilder; -import org.keycloak.adapters.NodesRegistrationLifecycle; +import org.keycloak.adapters.NodesRegistrationManagement; import org.keycloak.adapters.PreAuthActionsHandler; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.ServerRequest; @@ -48,7 +48,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif private final static Logger log = Logger.getLogger(""+KeycloakAuthenticatorValve.class); protected CatalinaUserSessionManagement userSessionManagement = new CatalinaUserSessionManagement(); protected AdapterDeploymentContext deploymentContext; - protected NodesRegistrationLifecycle nodesRegistrationLifecycle; + protected NodesRegistrationManagement nodesRegistrationManagement; @Override public void lifecycleEvent(LifecycleEvent event) { @@ -105,12 +105,11 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer(), getObjectName()); setNext(actions); - nodesRegistrationLifecycle = new NodesRegistrationLifecycle(kd); - nodesRegistrationLifecycle.start(); + nodesRegistrationManagement = new NodesRegistrationManagement(); } protected void beforeStop() { - nodesRegistrationLifecycle.stop(); + nodesRegistrationManagement.stop(); } private static InputStream getJSONFromServletContext(ServletContext servletContext) { @@ -166,6 +165,8 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif return false; } + nodesRegistrationManagement.tryRegister(deployment); + CatalinaRequestAuthenticator authenticator = new CatalinaRequestAuthenticator(deployment, this, userSessionManagement, facade, request); AuthOutcome outcome = authenticator.authenticate(); if (outcome == AuthOutcome.AUTHENTICATED) { diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java index 9919dfa834..5c7a16b4bd 100755 --- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java +++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java @@ -36,7 +36,7 @@ import org.keycloak.adapters.AdapterConstants; import org.keycloak.adapters.AdapterDeploymentContext; import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeploymentBuilder; -import org.keycloak.adapters.NodesRegistrationLifecycle; +import org.keycloak.adapters.NodesRegistrationManagement; import javax.servlet.ServletContext; import java.io.ByteArrayInputStream; @@ -112,7 +112,8 @@ public class KeycloakServletExtension implements ServletExtension { AdapterDeploymentContext deploymentContext = new AdapterDeploymentContext(deployment); servletContext.setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext); UndertowUserSessionManagement userSessionManagement = new UndertowUserSessionManagement(); - final ServletKeycloakAuthMech mech = createAuthenticationMechanism(deploymentInfo, deploymentContext, userSessionManagement); + final NodesRegistrationManagement nodesRegistrationManagement = new NodesRegistrationManagement(); + final ServletKeycloakAuthMech mech = createAuthenticationMechanism(deploymentInfo, deploymentContext, userSessionManagement, nodesRegistrationManagement); UndertowAuthenticatedActionsHandler.Wrapper actions = new UndertowAuthenticatedActionsHandler.Wrapper(deploymentContext); @@ -149,20 +150,20 @@ public class KeycloakServletExtension implements ServletExtension { cookieConfig.setPath(deploymentInfo.getContextPath()); deploymentInfo.setServletSessionConfig(cookieConfig); - deploymentInfo.addListener(new ListenerInfo(UndertowNodesRegistrationLifecycleWrapper.class, new InstanceFactory() { + deploymentInfo.addListener(new ListenerInfo(UndertowNodesRegistrationManagementWrapper.class, new InstanceFactory() { @Override - public InstanceHandle createInstance() throws InstantiationException { - NodesRegistrationLifecycle nodesRegistration = new NodesRegistrationLifecycle(deployment); - UndertowNodesRegistrationLifecycleWrapper listener = new UndertowNodesRegistrationLifecycleWrapper(nodesRegistration); - return new ImmediateInstanceHandle(listener); + public InstanceHandle createInstance() throws InstantiationException { + UndertowNodesRegistrationManagementWrapper listener = new UndertowNodesRegistrationManagementWrapper(nodesRegistrationManagement); + return new ImmediateInstanceHandle(listener); } })); } - protected ServletKeycloakAuthMech createAuthenticationMechanism(DeploymentInfo deploymentInfo, AdapterDeploymentContext deploymentContext, UndertowUserSessionManagement userSessionManagement) { + protected ServletKeycloakAuthMech createAuthenticationMechanism(DeploymentInfo deploymentInfo, AdapterDeploymentContext deploymentContext, UndertowUserSessionManagement userSessionManagement, + NodesRegistrationManagement nodesRegistrationManagement) { log.debug("creating ServletKeycloakAuthMech"); - return new ServletKeycloakAuthMech(deploymentContext, userSessionManagement, deploymentInfo.getConfidentialPortManager()); + return new ServletKeycloakAuthMech(deploymentContext, userSessionManagement, nodesRegistrationManagement, deploymentInfo.getConfidentialPortManager()); } } diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthMech.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthMech.java index 7e1ee378e5..7303bda5bb 100755 --- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthMech.java +++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthMech.java @@ -26,6 +26,7 @@ import org.jboss.logging.Logger; import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.AdapterDeploymentContext; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.NodesRegistrationManagement; import org.keycloak.adapters.RequestAuthenticator; import javax.servlet.http.HttpServletRequest; @@ -40,11 +41,13 @@ public class ServletKeycloakAuthMech extends UndertowKeycloakAuthMech { private static final Logger log = Logger.getLogger(ServletKeycloakAuthMech.class); protected UndertowUserSessionManagement userSessionManagement; + protected NodesRegistrationManagement nodesRegistrationManagement; protected ConfidentialPortManager portManager; - public ServletKeycloakAuthMech(AdapterDeploymentContext deploymentContext, UndertowUserSessionManagement userSessionManagement, ConfidentialPortManager portManager) { + public ServletKeycloakAuthMech(AdapterDeploymentContext deploymentContext, UndertowUserSessionManagement userSessionManagement, NodesRegistrationManagement nodesRegistrationManagement, ConfidentialPortManager portManager) { super(deploymentContext); this.userSessionManagement = userSessionManagement; + this.nodesRegistrationManagement = nodesRegistrationManagement; this.portManager = portManager; } @@ -56,6 +59,8 @@ public class ServletKeycloakAuthMech extends UndertowKeycloakAuthMech { return AuthenticationMechanismOutcome.NOT_ATTEMPTED; } + nodesRegistrationManagement.tryRegister(deployment); + RequestAuthenticator authenticator = createRequestAuthenticator(deployment, exchange, securityContext, facade); return keycloakAuthenticate(exchange, securityContext, authenticator); diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowNodesRegistrationLifecycleWrapper.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowNodesRegistrationManagementWrapper.java similarity index 57% rename from integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowNodesRegistrationLifecycleWrapper.java rename to integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowNodesRegistrationManagementWrapper.java index 5c97f6b7ae..d6ca115880 100644 --- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowNodesRegistrationLifecycleWrapper.java +++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowNodesRegistrationManagementWrapper.java @@ -3,22 +3,21 @@ package org.keycloak.adapters.undertow; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; -import org.keycloak.adapters.NodesRegistrationLifecycle; +import org.keycloak.adapters.NodesRegistrationManagement; /** * @author Marek Posolda */ -public class UndertowNodesRegistrationLifecycleWrapper implements ServletContextListener { +public class UndertowNodesRegistrationManagementWrapper implements ServletContextListener { - private final NodesRegistrationLifecycle delegate; + private final NodesRegistrationManagement delegate; - public UndertowNodesRegistrationLifecycleWrapper(NodesRegistrationLifecycle delegate) { + public UndertowNodesRegistrationManagementWrapper(NodesRegistrationManagement delegate) { this.delegate = delegate; } @Override public void contextInitialized(ServletContextEvent sce) { - delegate.start(); } @Override diff --git a/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyAuthenticationMechanism.java b/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyAuthenticationMechanism.java index 4963c0a532..cdb5315b97 100755 --- a/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyAuthenticationMechanism.java +++ b/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyAuthenticationMechanism.java @@ -5,6 +5,7 @@ import io.undertow.server.HttpServerExchange; import io.undertow.servlet.api.ConfidentialPortManager; import org.keycloak.adapters.AdapterDeploymentContext; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.NodesRegistrationManagement; import org.keycloak.adapters.undertow.ServletKeycloakAuthMech; import org.keycloak.adapters.undertow.ServletRequestAuthenticator; import org.keycloak.adapters.undertow.UndertowHttpFacade; @@ -18,8 +19,9 @@ public class WildflyAuthenticationMechanism extends ServletKeycloakAuthMech { public WildflyAuthenticationMechanism(AdapterDeploymentContext deploymentContext, UndertowUserSessionManagement userSessionManagement, + NodesRegistrationManagement nodesRegistrationManagement, ConfidentialPortManager portManager) { - super(deploymentContext, userSessionManagement, portManager); + super(deploymentContext, userSessionManagement, nodesRegistrationManagement, portManager); } @Override diff --git a/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyKeycloakServletExtension.java b/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyKeycloakServletExtension.java index 60b28b926e..6130d9b136 100755 --- a/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyKeycloakServletExtension.java +++ b/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyKeycloakServletExtension.java @@ -3,6 +3,7 @@ package org.keycloak.adapters.wildfly; import io.undertow.servlet.api.DeploymentInfo; import org.jboss.logging.Logger; import org.keycloak.adapters.AdapterDeploymentContext; +import org.keycloak.adapters.NodesRegistrationManagement; import org.keycloak.adapters.undertow.KeycloakServletExtension; import org.keycloak.adapters.undertow.ServletKeycloakAuthMech; import org.keycloak.adapters.undertow.UndertowUserSessionManagement; @@ -16,9 +17,9 @@ public class WildflyKeycloakServletExtension extends KeycloakServletExtension { @Override protected ServletKeycloakAuthMech createAuthenticationMechanism(DeploymentInfo deploymentInfo, AdapterDeploymentContext deploymentContext, - UndertowUserSessionManagement userSessionManagement) { + UndertowUserSessionManagement userSessionManagement, NodesRegistrationManagement nodesRegistrationManagement) { log.info("creating WildflyAuthenticationMechanism"); - return new WildflyAuthenticationMechanism(deploymentContext, userSessionManagement, deploymentInfo.getConfidentialPortManager()); + return new WildflyAuthenticationMechanism(deploymentContext, userSessionManagement, nodesRegistrationManagement, deploymentInfo.getConfidentialPortManager()); } } diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java index efbefca0c2..8fed69e6ee 100755 --- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java +++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java @@ -59,7 +59,7 @@ public class InfinispanCacheUserProviderFactory implements CacheUserProviderFact } @Listener - private class CacheListener { + public class CacheListener { @CacheEntryCreated public void userCreated(CacheEntryCreatedEvent event) { diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java index ef190d980e..0ac16b9b12 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java @@ -436,6 +436,9 @@ public class OpenIDConnectService { .build(); } + + event.success(); + return Response.ok(token, MediaType.APPLICATION_JSON_TYPE).build(); } diff --git a/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java b/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java index 689d892d95..80cdb25f35 100644 --- a/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java +++ b/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java @@ -1,5 +1,6 @@ package org.keycloak.services.resources; +import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -22,6 +23,7 @@ import org.jboss.resteasy.spi.UnauthorizedException; import org.keycloak.ClientConnection; import org.keycloak.OAuth2Constants; import org.keycloak.adapters.AdapterConstants; +import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; import org.keycloak.events.EventType; @@ -106,10 +108,13 @@ public class ClientsManagementService { ApplicationModel application = authorizeApplication(authorizationHeader, formData); String nodeHost = getApplicationClusterHost(formData); + event.client(application).detail(Details.NODE_HOST, nodeHost); logger.infof("Registering cluster host '%s' for client '%s'", nodeHost, application.getName()); application.registerNode(nodeHost, Time.currentTime()); + event.success(); + return Response.noContent().build(); } @@ -139,10 +144,13 @@ public class ClientsManagementService { ApplicationModel application = authorizeApplication(authorizationHeader, formData); String nodeHost = getApplicationClusterHost(formData); + event.client(application).detail(Details.NODE_HOST, nodeHost); logger.infof("Unregistering cluster host '%s' for client '%s'", nodeHost, application.getName()); application.unregisterNode(nodeHost); + event.success(); + return Response.noContent().build(); } diff --git a/testsuite/docker-cluster/shared-files/deploy-examples.sh b/testsuite/docker-cluster/shared-files/deploy-examples.sh index d2e3287965..2ddee7dbad 100644 --- a/testsuite/docker-cluster/shared-files/deploy-examples.sh +++ b/testsuite/docker-cluster/shared-files/deploy-examples.sh @@ -29,15 +29,19 @@ sed -i -e 's/false/true/' admin-access.war/WEB-INF/web.xml # Configure other examples for I in *.war/WEB-INF/keycloak.json; do - sed -i -e 's/\"auth-server-url\".*: \"\/auth\",/&\n \"auth-server-url-for-backend-requests\": \"http:\/\/\$\{jboss.host.name\}:8080\/auth\",\ - \n \"register-node-at-startup\": false,\n \"register-node-period\": 30,/' $I; + sed -i -e 's/\"resource\".*: \".*\",/&\n \"auth-server-url-for-backend-requests\": \"http:\/\/\$\{jboss.host.name\}:8080\/auth\",\n \"register-node-at-startup\": true,\n \"register-node-period\": 150,/' $I; + sed -i -e 's/\"bearer-only\" : true,/&\n \"credentials\" : \{ \"secret\": \"password\" \},/' $I; done; # Enable distributable for customer-portal sed -i -e 's/<\/module-name>/&\n /' customer-portal.war/WEB-INF/web.xml -# Configure testrealm.json - Enable adminUrl to access adapters on local machine -sed -i -e 's/\"adminUrl\": \"\/customer-portal/\"adminUrl\": \"http:\/\/\$\{jboss.host.name\}:8080\/customer-portal/' /keycloak-docker-cluster/examples/testrealm.json -sed -i -e 's/\"adminUrl\": \"\/product-portal/\"adminUrl\": \"http:\/\/\$\{application.session.host\}:8080\/product-portal/' /keycloak-docker-cluster/examples/testrealm.json +# Configure testrealm.json - Enable adminUrl to access adapters on local machine, add jboss-logging listener and add secret for database-service application +TEST_REALM=/keycloak-docker-cluster/examples/testrealm.json +sed -i -e 's/\"adminUrl\": \"\/customer-portal/\"adminUrl\": \"http:\/\/\$\{jboss.host.name\}:8080\/customer-portal/' $TEST_REALM +sed -i -e 's/\"adminUrl\": \"\/product-portal/\"adminUrl\": \"http:\/\/\$\{application.session.host\}:8080\/product-portal/' $TEST_REALM +sed -i -e 's/\"adminUrl\": \"\/database/\"adminUrl\": \"http:\/\/\$\{jboss.host.name\}:8080\/database/' $TEST_REALM +sed -i -e 's/\"bearerOnly\": true/&,\n \"secret\": \"password\"/' $TEST_REALM +sed -i -e 's/\"sslRequired\": \"external\",/&\n \"eventsListeners\": \[ \"jboss-logging\" \],/' $TEST_REALM