Merge pull request #791 from mposolda/dynamic-adapter-registration

Send node registration at 1st request instead of deployment startup. Bug...
This commit is contained in:
Marek Posolda 2014-10-21 23:22:51 +02:00
commit 8ec2b2398c
19 changed files with 103 additions and 65 deletions

View file

@ -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";
}

View file

@ -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" %>
<html>
<head>
<title>Customer Session Page</title>
</head>
<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>You visited this page <b><%= CustomerDatabaseClient.increaseAndGetCounter(request) %></b> times.</p>
<br><br>

View file

@ -147,8 +147,7 @@
"enabled": true,
"adminUrl": "/database",
"baseUrl": "/database",
"bearerOnly": true,
"secret": "password"
"bearerOnly": true
}
],
"oauthClients": [

View file

@ -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;

View file

@ -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;

View file

@ -11,9 +11,9 @@ import org.keycloak.util.HostUtils;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class NodesRegistrationLifecycle {
public class NodesRegistrationManagement {
private static final Logger log = Logger.getLogger(NodesRegistrationLifecycle.class);
private static final Logger log = Logger.getLogger(NodesRegistrationManagement.class);
private final KeycloakDeployment deployment;
private final Timer timer;
@ -21,32 +21,35 @@ public class NodesRegistrationLifecycle {
// True if at least one event was successfully sent
private volatile boolean registered = false;
public NodesRegistrationLifecycle(KeycloakDeployment deployment) {
public NodesRegistrationManagement(KeycloakDeployment deployment) {
this.deployment = deployment;
this.timer = new Timer();
}
// Register listener for periodic sending of re-registration event
public void start() {
if (!deployment.isRegisterNodeAtStartup() && deployment.getRegisterNodePeriod() <= 0) {
log.info("Skip registration of cluster nodes at startup");
if (deployment.getRegisterNodePeriod() <= 0) {
log.infof("Skip periodic registration of cluster nodes at startup for application %s", deployment.getResourceName());
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!");
if (deployment.getRelativeUrls() == null || deployment.getRelativeUrls() == RelativeUrlsUsed.ALL_REQUESTS) {
log.errorf("Skip periodic registration of cluster nodes at startup for application %s as Keycloak node can't be contacted. Make sure to provide some non-relative URI in adapters configuration.", deployment.getResourceName());
return;
}
if (deployment.isRegisterNodeAtStartup()) {
boolean success = sendRegistrationEvent();
if (!success) {
throw new IllegalStateException("Failed to register node to keycloak at startup");
addPeriodicListener();
}
// Sending registration event during first request to application
public void tryRegister(KeycloakDeployment resolvedDeployment) {
if (resolvedDeployment.isRegisterNodeAtStartup() && !registered) {
synchronized (this) {
if (!registered) {
sendRegistrationEvent(resolvedDeployment);
}
}
}
if (deployment.getRegisterNodePeriod() > 0) {
addPeriodicListener();
}
}
public void stop() {
@ -61,7 +64,7 @@ public class NodesRegistrationLifecycle {
@Override
public void run() {
sendRegistrationEvent();
sendRegistrationEvent(deployment);
}
};
@ -74,7 +77,7 @@ public class NodesRegistrationLifecycle {
timer.cancel();
}
protected boolean sendRegistrationEvent() {
protected void sendRegistrationEvent(KeycloakDeployment deployment) {
log.info("Sending registration event right now");
String host = HostUtils.getIpAddress();
@ -82,22 +85,19 @@ public class NodesRegistrationLifecycle {
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");
log.info("Sending Unregistration event right now");
String host = HostUtils.getIpAddress();
try {

View file

@ -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;
}

View file

@ -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 {
if (endpointUrl == null) {
throw new IOException("You need to configure URI for register/unregister node for application " + clientId);
}
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
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");

View file

@ -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,12 @@ 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(kd);
nodesRegistrationManagement.start();
}
protected void beforeStop() {
nodesRegistrationLifecycle.stop();
nodesRegistrationManagement.stop();
}
@Override
@ -166,6 +166,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) {

View file

@ -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,12 @@ 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(kd);
nodesRegistrationManagement.start();
}
protected void beforeStop() {
nodesRegistrationLifecycle.stop();
nodesRegistrationManagement.stop();
}
private static InputStream getJSONFromServletContext(ServletContext servletContext) {
@ -166,6 +166,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) {

View file

@ -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(deployment);
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<UndertowNodesRegistrationLifecycleWrapper>() {
deploymentInfo.addListener(new ListenerInfo(UndertowNodesRegistrationManagementWrapper.class, new InstanceFactory<UndertowNodesRegistrationManagementWrapper>() {
@Override
public InstanceHandle<UndertowNodesRegistrationLifecycleWrapper> createInstance() throws InstantiationException {
NodesRegistrationLifecycle nodesRegistration = new NodesRegistrationLifecycle(deployment);
UndertowNodesRegistrationLifecycleWrapper listener = new UndertowNodesRegistrationLifecycleWrapper(nodesRegistration);
return new ImmediateInstanceHandle<UndertowNodesRegistrationLifecycleWrapper>(listener);
public InstanceHandle<UndertowNodesRegistrationManagementWrapper> createInstance() throws InstantiationException {
UndertowNodesRegistrationManagementWrapper listener = new UndertowNodesRegistrationManagementWrapper(nodesRegistrationManagement);
return new ImmediateInstanceHandle<UndertowNodesRegistrationManagementWrapper>(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());
}
}

View file

@ -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);

View file

@ -3,16 +3,16 @@ package org.keycloak.adapters.undertow;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.keycloak.adapters.NodesRegistrationLifecycle;
import org.keycloak.adapters.NodesRegistrationManagement;
/**
* @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;
}

View file

@ -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

View file

@ -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());
}
}

View file

@ -59,7 +59,7 @@ public class InfinispanCacheUserProviderFactory implements CacheUserProviderFact
}
@Listener
private class CacheListener {
public class CacheListener {
@CacheEntryCreated
public void userCreated(CacheEntryCreatedEvent<String, CachedUser> event) {

View file

@ -436,6 +436,9 @@ public class OpenIDConnectService {
.build();
}
event.success();
return Response.ok(token, MediaType.APPLICATION_JSON_TYPE).build();
}

View file

@ -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();
}

View file

@ -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 <distributable \/>/' 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