Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
b3fe650e27
20 changed files with 197 additions and 165 deletions
|
@ -19,5 +19,5 @@ public interface Details {
|
||||||
String REFRESH_TOKEN_ID = "refresh_token_id";
|
String REFRESH_TOKEN_ID = "refresh_token_id";
|
||||||
String VALIDATE_ACCESS_TOKEN = "validate_access_token";
|
String VALIDATE_ACCESS_TOKEN = "validate_access_token";
|
||||||
String UPDATED_REFRESH_TOKEN_ID = "updated_refresh_token_id";
|
String UPDATED_REFRESH_TOKEN_ID = "updated_refresh_token_id";
|
||||||
|
String NODE_HOST = "node_host";
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
<%@ page import="org.keycloak.ServiceUrlConstants" %>
|
<%@ page import="org.keycloak.ServiceUrlConstants" %>
|
||||||
<%@ page import="org.keycloak.example.CustomerDatabaseClient" %>
|
<%@ page import="org.keycloak.example.CustomerDatabaseClient" %>
|
||||||
<%@ page import="org.keycloak.representations.IDToken" %>
|
<%@ page import="org.keycloak.representations.IDToken" %>
|
||||||
<%@ page import="org.keycloak.util.UriUtils" %>
|
<%@ page import="org.keycloak.util.HostUtils" %>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Customer Session Page</title>
|
<title>Customer Session Page</title>
|
||||||
</head>
|
</head>
|
||||||
<body bgcolor="#E3F6CE">
|
<body bgcolor="#E3F6CE">
|
||||||
<p>Your hostname: <b><%= UriUtils.getHostName() %></b></p>
|
<p>Your hostname: <b><%= HostUtils.getHostName() %></b></p>
|
||||||
<p>Your session ID: <b><%= request.getSession().getId() %></b></p>
|
<p>Your session ID: <b><%= request.getSession().getId() %></b></p>
|
||||||
<p>You visited this page <b><%= CustomerDatabaseClient.increaseAndGetCounter(request) %></b> times.</p>
|
<p>You visited this page <b><%= CustomerDatabaseClient.increaseAndGetCounter(request) %></b> times.</p>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
|
@ -147,8 +147,7 @@
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"adminUrl": "/database",
|
"adminUrl": "/database",
|
||||||
"baseUrl": "/database",
|
"baseUrl": "/database",
|
||||||
"bearerOnly": true,
|
"bearerOnly": true
|
||||||
"secret": "password"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"oauthClients": [
|
"oauthClients": [
|
||||||
|
|
|
@ -85,12 +85,16 @@ public class KeycloakDeployment {
|
||||||
return authServerBaseUrl;
|
return authServerBaseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAuthServerBaseUrl(String authServerBaseUrl, AdapterConfig config) {
|
public void setAuthServerBaseUrl(AdapterConfig config) {
|
||||||
this.authServerBaseUrl = authServerBaseUrl;
|
this.authServerBaseUrl = config.getAuthServerUrl();
|
||||||
if (authServerBaseUrl == null) return;
|
if (authServerBaseUrl == null && config.getAuthServerUrlForBackendRequests() == null) return;
|
||||||
|
|
||||||
URI uri = URI.create(authServerBaseUrl);
|
URI authServerUri = null;
|
||||||
if (uri.getHost() == null) {
|
if (authServerBaseUrl != null) {
|
||||||
|
authServerUri = URI.create(authServerBaseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authServerUri == null || authServerUri.getHost() == null) {
|
||||||
String authServerURLForBackendReqs = config.getAuthServerUrlForBackendRequests();
|
String authServerURLForBackendReqs = config.getAuthServerUrlForBackendRequests();
|
||||||
if (authServerURLForBackendReqs != null) {
|
if (authServerURLForBackendReqs != null) {
|
||||||
relativeUrls = RelativeUrlsUsed.BROWSER_ONLY;
|
relativeUrls = RelativeUrlsUsed.BROWSER_ONLY;
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class KeycloakDeploymentBuilder {
|
||||||
if (adapterConfig.getAuthServerUrl() == null && (!deployment.isBearerOnly() || realmKeyPem == null)) {
|
if (adapterConfig.getAuthServerUrl() == null && (!deployment.isBearerOnly() || realmKeyPem == null)) {
|
||||||
throw new RuntimeException("You must specify auth-url");
|
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());
|
log.debug("Use authServerUrl: " + deployment.getAuthServerBaseUrl() + ", codeUrl: " + deployment.getCodeUrl() + ", relativeUrls: " + deployment.getRelativeUrls());
|
||||||
return deployment;
|
return deployment;
|
||||||
|
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class NodesRegistrationManagement {
|
||||||
|
|
||||||
|
private static final Logger log = Logger.getLogger(NodesRegistrationManagement.class);
|
||||||
|
|
||||||
|
private final Map<String, NodeRegistrationContext> nodeRegistrations = new ConcurrentHashMap<String, NodeRegistrationContext>();
|
||||||
|
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<NodeRegistrationContext> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -58,6 +58,7 @@ public class PreAuthActionsHandler {
|
||||||
handleVersion();
|
handleVersion();
|
||||||
return true;
|
return true;
|
||||||
} else if (requestUri.endsWith(AdapterConstants.K_TEST_AVAILABLE)) {
|
} else if (requestUri.endsWith(AdapterConstants.K_TEST_AVAILABLE)) {
|
||||||
|
if (!resolveDeployment()) return true;
|
||||||
handleTestAvailable();
|
handleTestAvailable();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,6 +231,10 @@ public class ServerRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void invokeClientManagementRequest(HttpClient client, String host, String endpointUrl, String clientId, Map<String, String> credentials) throws HttpFailure, IOException {
|
public static void invokeClientManagementRequest(HttpClient client, String host, String endpointUrl, String clientId, Map<String, String> credentials) throws HttpFailure, IOException {
|
||||||
|
if (endpointUrl == null) {
|
||||||
|
throw new IOException("You need to configure URI for register/unregister node for application " + clientId);
|
||||||
|
}
|
||||||
|
|
||||||
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
|
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
|
||||||
formparams.add(new BasicNameValuePair(AdapterConstants.APPLICATION_CLUSTER_HOST, host));
|
formparams.add(new BasicNameValuePair(AdapterConstants.APPLICATION_CLUSTER_HOST, host));
|
||||||
|
|
||||||
|
@ -240,6 +244,8 @@ public class ServerRequest {
|
||||||
if (clientSecret != null) {
|
if (clientSecret != null) {
|
||||||
String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
|
String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
|
||||||
post.setHeader("Authorization", authorization);
|
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");
|
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
|
||||||
|
|
|
@ -21,7 +21,7 @@ import org.keycloak.adapters.AuthOutcome;
|
||||||
import org.keycloak.adapters.HttpFacade;
|
import org.keycloak.adapters.HttpFacade;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||||
import org.keycloak.adapters.NodesRegistrationLifecycle;
|
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||||
import org.keycloak.adapters.PreAuthActionsHandler;
|
import org.keycloak.adapters.PreAuthActionsHandler;
|
||||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
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);
|
private static final Logger log = Logger.getLogger(KeycloakAuthenticatorValve.class);
|
||||||
protected CatalinaUserSessionManagement userSessionManagement = new CatalinaUserSessionManagement();
|
protected CatalinaUserSessionManagement userSessionManagement = new CatalinaUserSessionManagement();
|
||||||
protected AdapterDeploymentContext deploymentContext;
|
protected AdapterDeploymentContext deploymentContext;
|
||||||
protected NodesRegistrationLifecycle nodesRegistrationLifecycle;
|
protected NodesRegistrationManagement nodesRegistrationManagement;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -127,12 +127,11 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
|
||||||
AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer(), getController());
|
AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer(), getController());
|
||||||
setNext(actions);
|
setNext(actions);
|
||||||
|
|
||||||
nodesRegistrationLifecycle = new NodesRegistrationLifecycle(kd);
|
nodesRegistrationManagement = new NodesRegistrationManagement();
|
||||||
nodesRegistrationLifecycle.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void beforeStop() {
|
protected void beforeStop() {
|
||||||
nodesRegistrationLifecycle.stop();
|
nodesRegistrationManagement.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -166,6 +165,8 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nodesRegistrationManagement.tryRegister(deployment);
|
||||||
|
|
||||||
CatalinaRequestAuthenticator authenticator = new CatalinaRequestAuthenticator(deployment, this, userSessionManagement, facade, request);
|
CatalinaRequestAuthenticator authenticator = new CatalinaRequestAuthenticator(deployment, this, userSessionManagement, facade, request);
|
||||||
AuthOutcome outcome = authenticator.authenticate();
|
AuthOutcome outcome = authenticator.authenticate();
|
||||||
if (outcome == AuthOutcome.AUTHENTICATED) {
|
if (outcome == AuthOutcome.AUTHENTICATED) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ import org.keycloak.adapters.AuthOutcome;
|
||||||
import org.keycloak.adapters.HttpFacade;
|
import org.keycloak.adapters.HttpFacade;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||||
import org.keycloak.adapters.NodesRegistrationLifecycle;
|
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||||
import org.keycloak.adapters.PreAuthActionsHandler;
|
import org.keycloak.adapters.PreAuthActionsHandler;
|
||||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.ServerRequest;
|
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);
|
private final static Logger log = Logger.getLogger(""+KeycloakAuthenticatorValve.class);
|
||||||
protected CatalinaUserSessionManagement userSessionManagement = new CatalinaUserSessionManagement();
|
protected CatalinaUserSessionManagement userSessionManagement = new CatalinaUserSessionManagement();
|
||||||
protected AdapterDeploymentContext deploymentContext;
|
protected AdapterDeploymentContext deploymentContext;
|
||||||
protected NodesRegistrationLifecycle nodesRegistrationLifecycle;
|
protected NodesRegistrationManagement nodesRegistrationManagement;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void lifecycleEvent(LifecycleEvent event) {
|
public void lifecycleEvent(LifecycleEvent event) {
|
||||||
|
@ -105,12 +105,11 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
|
||||||
AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer(), getObjectName());
|
AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer(), getObjectName());
|
||||||
setNext(actions);
|
setNext(actions);
|
||||||
|
|
||||||
nodesRegistrationLifecycle = new NodesRegistrationLifecycle(kd);
|
nodesRegistrationManagement = new NodesRegistrationManagement();
|
||||||
nodesRegistrationLifecycle.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void beforeStop() {
|
protected void beforeStop() {
|
||||||
nodesRegistrationLifecycle.stop();
|
nodesRegistrationManagement.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputStream getJSONFromServletContext(ServletContext servletContext) {
|
private static InputStream getJSONFromServletContext(ServletContext servletContext) {
|
||||||
|
@ -166,6 +165,8 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nodesRegistrationManagement.tryRegister(deployment);
|
||||||
|
|
||||||
CatalinaRequestAuthenticator authenticator = new CatalinaRequestAuthenticator(deployment, this, userSessionManagement, facade, request);
|
CatalinaRequestAuthenticator authenticator = new CatalinaRequestAuthenticator(deployment, this, userSessionManagement, facade, request);
|
||||||
AuthOutcome outcome = authenticator.authenticate();
|
AuthOutcome outcome = authenticator.authenticate();
|
||||||
if (outcome == AuthOutcome.AUTHENTICATED) {
|
if (outcome == AuthOutcome.AUTHENTICATED) {
|
||||||
|
|
|
@ -36,7 +36,7 @@ import org.keycloak.adapters.AdapterConstants;
|
||||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||||
import org.keycloak.adapters.NodesRegistrationLifecycle;
|
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
@ -112,7 +112,8 @@ public class KeycloakServletExtension implements ServletExtension {
|
||||||
AdapterDeploymentContext deploymentContext = new AdapterDeploymentContext(deployment);
|
AdapterDeploymentContext deploymentContext = new AdapterDeploymentContext(deployment);
|
||||||
servletContext.setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
|
servletContext.setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
|
||||||
UndertowUserSessionManagement userSessionManagement = new UndertowUserSessionManagement();
|
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);
|
UndertowAuthenticatedActionsHandler.Wrapper actions = new UndertowAuthenticatedActionsHandler.Wrapper(deploymentContext);
|
||||||
|
|
||||||
|
@ -149,20 +150,20 @@ public class KeycloakServletExtension implements ServletExtension {
|
||||||
cookieConfig.setPath(deploymentInfo.getContextPath());
|
cookieConfig.setPath(deploymentInfo.getContextPath());
|
||||||
deploymentInfo.setServletSessionConfig(cookieConfig);
|
deploymentInfo.setServletSessionConfig(cookieConfig);
|
||||||
|
|
||||||
deploymentInfo.addListener(new ListenerInfo(UndertowNodesRegistrationLifecycleWrapper.class, new InstanceFactory<UndertowNodesRegistrationLifecycleWrapper>() {
|
deploymentInfo.addListener(new ListenerInfo(UndertowNodesRegistrationManagementWrapper.class, new InstanceFactory<UndertowNodesRegistrationManagementWrapper>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InstanceHandle<UndertowNodesRegistrationLifecycleWrapper> createInstance() throws InstantiationException {
|
public InstanceHandle<UndertowNodesRegistrationManagementWrapper> createInstance() throws InstantiationException {
|
||||||
NodesRegistrationLifecycle nodesRegistration = new NodesRegistrationLifecycle(deployment);
|
UndertowNodesRegistrationManagementWrapper listener = new UndertowNodesRegistrationManagementWrapper(nodesRegistrationManagement);
|
||||||
UndertowNodesRegistrationLifecycleWrapper listener = new UndertowNodesRegistrationLifecycleWrapper(nodesRegistration);
|
return new ImmediateInstanceHandle<UndertowNodesRegistrationManagementWrapper>(listener);
|
||||||
return new ImmediateInstanceHandle<UndertowNodesRegistrationLifecycleWrapper>(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");
|
log.debug("creating ServletKeycloakAuthMech");
|
||||||
return new ServletKeycloakAuthMech(deploymentContext, userSessionManagement, deploymentInfo.getConfidentialPortManager());
|
return new ServletKeycloakAuthMech(deploymentContext, userSessionManagement, nodesRegistrationManagement, deploymentInfo.getConfidentialPortManager());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.jboss.logging.Logger;
|
||||||
import org.keycloak.KeycloakSecurityContext;
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
|
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||||
import org.keycloak.adapters.RequestAuthenticator;
|
import org.keycloak.adapters.RequestAuthenticator;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -40,11 +41,13 @@ public class ServletKeycloakAuthMech extends UndertowKeycloakAuthMech {
|
||||||
private static final Logger log = Logger.getLogger(ServletKeycloakAuthMech.class);
|
private static final Logger log = Logger.getLogger(ServletKeycloakAuthMech.class);
|
||||||
|
|
||||||
protected UndertowUserSessionManagement userSessionManagement;
|
protected UndertowUserSessionManagement userSessionManagement;
|
||||||
|
protected NodesRegistrationManagement nodesRegistrationManagement;
|
||||||
protected ConfidentialPortManager portManager;
|
protected ConfidentialPortManager portManager;
|
||||||
|
|
||||||
public ServletKeycloakAuthMech(AdapterDeploymentContext deploymentContext, UndertowUserSessionManagement userSessionManagement, ConfidentialPortManager portManager) {
|
public ServletKeycloakAuthMech(AdapterDeploymentContext deploymentContext, UndertowUserSessionManagement userSessionManagement, NodesRegistrationManagement nodesRegistrationManagement, ConfidentialPortManager portManager) {
|
||||||
super(deploymentContext);
|
super(deploymentContext);
|
||||||
this.userSessionManagement = userSessionManagement;
|
this.userSessionManagement = userSessionManagement;
|
||||||
|
this.nodesRegistrationManagement = nodesRegistrationManagement;
|
||||||
this.portManager = portManager;
|
this.portManager = portManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +59,8 @@ public class ServletKeycloakAuthMech extends UndertowKeycloakAuthMech {
|
||||||
return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
|
return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nodesRegistrationManagement.tryRegister(deployment);
|
||||||
|
|
||||||
RequestAuthenticator authenticator = createRequestAuthenticator(deployment, exchange, securityContext, facade);
|
RequestAuthenticator authenticator = createRequestAuthenticator(deployment, exchange, securityContext, facade);
|
||||||
|
|
||||||
return keycloakAuthenticate(exchange, securityContext, authenticator);
|
return keycloakAuthenticate(exchange, securityContext, authenticator);
|
||||||
|
|
|
@ -3,22 +3,21 @@ package org.keycloak.adapters.undertow;
|
||||||
import javax.servlet.ServletContextEvent;
|
import javax.servlet.ServletContextEvent;
|
||||||
import javax.servlet.ServletContextListener;
|
import javax.servlet.ServletContextListener;
|
||||||
|
|
||||||
import org.keycloak.adapters.NodesRegistrationLifecycle;
|
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
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;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contextInitialized(ServletContextEvent sce) {
|
public void contextInitialized(ServletContextEvent sce) {
|
||||||
delegate.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
|
@ -5,6 +5,7 @@ import io.undertow.server.HttpServerExchange;
|
||||||
import io.undertow.servlet.api.ConfidentialPortManager;
|
import io.undertow.servlet.api.ConfidentialPortManager;
|
||||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
|
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||||
import org.keycloak.adapters.undertow.ServletKeycloakAuthMech;
|
import org.keycloak.adapters.undertow.ServletKeycloakAuthMech;
|
||||||
import org.keycloak.adapters.undertow.ServletRequestAuthenticator;
|
import org.keycloak.adapters.undertow.ServletRequestAuthenticator;
|
||||||
import org.keycloak.adapters.undertow.UndertowHttpFacade;
|
import org.keycloak.adapters.undertow.UndertowHttpFacade;
|
||||||
|
@ -18,8 +19,9 @@ public class WildflyAuthenticationMechanism extends ServletKeycloakAuthMech {
|
||||||
|
|
||||||
public WildflyAuthenticationMechanism(AdapterDeploymentContext deploymentContext,
|
public WildflyAuthenticationMechanism(AdapterDeploymentContext deploymentContext,
|
||||||
UndertowUserSessionManagement userSessionManagement,
|
UndertowUserSessionManagement userSessionManagement,
|
||||||
|
NodesRegistrationManagement nodesRegistrationManagement,
|
||||||
ConfidentialPortManager portManager) {
|
ConfidentialPortManager portManager) {
|
||||||
super(deploymentContext, userSessionManagement, portManager);
|
super(deploymentContext, userSessionManagement, nodesRegistrationManagement, portManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.adapters.wildfly;
|
||||||
import io.undertow.servlet.api.DeploymentInfo;
|
import io.undertow.servlet.api.DeploymentInfo;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||||
|
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||||
import org.keycloak.adapters.undertow.KeycloakServletExtension;
|
import org.keycloak.adapters.undertow.KeycloakServletExtension;
|
||||||
import org.keycloak.adapters.undertow.ServletKeycloakAuthMech;
|
import org.keycloak.adapters.undertow.ServletKeycloakAuthMech;
|
||||||
import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
|
import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
|
||||||
|
@ -16,9 +17,9 @@ public class WildflyKeycloakServletExtension extends KeycloakServletExtension {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ServletKeycloakAuthMech createAuthenticationMechanism(DeploymentInfo deploymentInfo, AdapterDeploymentContext deploymentContext,
|
protected ServletKeycloakAuthMech createAuthenticationMechanism(DeploymentInfo deploymentInfo, AdapterDeploymentContext deploymentContext,
|
||||||
UndertowUserSessionManagement userSessionManagement) {
|
UndertowUserSessionManagement userSessionManagement, NodesRegistrationManagement nodesRegistrationManagement) {
|
||||||
log.info("creating WildflyAuthenticationMechanism");
|
log.info("creating WildflyAuthenticationMechanism");
|
||||||
return new WildflyAuthenticationMechanism(deploymentContext, userSessionManagement, deploymentInfo.getConfidentialPortManager());
|
return new WildflyAuthenticationMechanism(deploymentContext, userSessionManagement, nodesRegistrationManagement, deploymentInfo.getConfidentialPortManager());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ public class InfinispanCacheUserProviderFactory implements CacheUserProviderFact
|
||||||
}
|
}
|
||||||
|
|
||||||
@Listener
|
@Listener
|
||||||
private class CacheListener {
|
public class CacheListener {
|
||||||
|
|
||||||
@CacheEntryCreated
|
@CacheEntryCreated
|
||||||
public void userCreated(CacheEntryCreatedEvent<String, CachedUser> event) {
|
public void userCreated(CacheEntryCreatedEvent<String, CachedUser> event) {
|
||||||
|
|
|
@ -436,6 +436,9 @@ public class OpenIDConnectService {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event.success();
|
||||||
|
|
||||||
return Response.ok(token, MediaType.APPLICATION_JSON_TYPE).build();
|
return Response.ok(token, MediaType.APPLICATION_JSON_TYPE).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.keycloak.services.resources;
|
package org.keycloak.services.resources;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ import org.jboss.resteasy.spi.UnauthorizedException;
|
||||||
import org.keycloak.ClientConnection;
|
import org.keycloak.ClientConnection;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.adapters.AdapterConstants;
|
import org.keycloak.adapters.AdapterConstants;
|
||||||
|
import org.keycloak.events.Details;
|
||||||
import org.keycloak.events.Errors;
|
import org.keycloak.events.Errors;
|
||||||
import org.keycloak.events.EventBuilder;
|
import org.keycloak.events.EventBuilder;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.events.EventType;
|
||||||
|
@ -106,10 +108,13 @@ public class ClientsManagementService {
|
||||||
ApplicationModel application = authorizeApplication(authorizationHeader, formData);
|
ApplicationModel application = authorizeApplication(authorizationHeader, formData);
|
||||||
String nodeHost = getApplicationClusterHost(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());
|
logger.infof("Registering cluster host '%s' for client '%s'", nodeHost, application.getName());
|
||||||
|
|
||||||
application.registerNode(nodeHost, Time.currentTime());
|
application.registerNode(nodeHost, Time.currentTime());
|
||||||
|
|
||||||
|
event.success();
|
||||||
|
|
||||||
return Response.noContent().build();
|
return Response.noContent().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,10 +144,13 @@ public class ClientsManagementService {
|
||||||
ApplicationModel application = authorizeApplication(authorizationHeader, formData);
|
ApplicationModel application = authorizeApplication(authorizationHeader, formData);
|
||||||
String nodeHost = getApplicationClusterHost(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());
|
logger.infof("Unregistering cluster host '%s' for client '%s'", nodeHost, application.getName());
|
||||||
|
|
||||||
application.unregisterNode(nodeHost);
|
application.unregisterNode(nodeHost);
|
||||||
|
|
||||||
|
event.success();
|
||||||
|
|
||||||
return Response.noContent().build();
|
return Response.noContent().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,15 +29,19 @@ sed -i -e 's/false/true/' admin-access.war/WEB-INF/web.xml
|
||||||
|
|
||||||
# Configure other examples
|
# Configure other examples
|
||||||
for I in *.war/WEB-INF/keycloak.json; do
|
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\",\
|
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;
|
||||||
\n \"register-node-at-startup\": false,\n \"register-node-period\": 30,/' $I;
|
sed -i -e 's/\"bearer-only\" : true,/&\n \"credentials\" : \{ \"secret\": \"password\" \},/' $I;
|
||||||
done;
|
done;
|
||||||
|
|
||||||
# Enable distributable for customer-portal
|
# Enable distributable for customer-portal
|
||||||
sed -i -e 's/<\/module-name>/&\n <distributable \/>/' customer-portal.war/WEB-INF/web.xml
|
sed -i -e 's/<\/module-name>/&\n <distributable \/>/' customer-portal.war/WEB-INF/web.xml
|
||||||
|
|
||||||
# Configure testrealm.json - Enable adminUrl to access adapters on local machine
|
# Configure testrealm.json - Enable adminUrl to access adapters on local machine, add jboss-logging listener and add secret for database-service application
|
||||||
sed -i -e 's/\"adminUrl\": \"\/customer-portal/\"adminUrl\": \"http:\/\/\$\{jboss.host.name\}:8080\/customer-portal/' /keycloak-docker-cluster/examples/testrealm.json
|
TEST_REALM=/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
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue