org.wildfly.security.http.oidc.NodesRegistrationManagement Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including
all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and
Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
/*
* JBoss, Home of Professional Open Source.
* Copyright 2021 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wildfly.security.http.oidc;
import static org.wildfly.security.http.oidc.ElytronMessages.log;
import static org.wildfly.security.http.oidc.Oidc.getCurrentTimeInSeconds;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Used for clustering with Keycloak.
*
* @author Marek Posolda
* @author Farah Juma
*/
public class NodesRegistrationManagement {
private final Map nodeRegistrations = new ConcurrentHashMap();
private final ExecutorService executor = Executors.newSingleThreadExecutor();
// Sending registration event during first request to application or if re-registration is needed
public void tryRegister(final OidcClientConfiguration 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, OidcClientConfiguration 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() < getCurrentTimeInSeconds();
}
/**
* Called during undeployment or server stop. De-register from all previously registered deployments
*/
public void stop() {
executor.shutdownNow();
Collection allRegistrations = nodeRegistrations.values();
for (NodeRegistrationContext registration : allRegistrations) {
sendUnregistrationEvent(registration.resolvedDeployment);
}
}
protected void sendRegistrationEvent(OidcClientConfiguration deployment) {
// This method is invoked from single-thread executor, so no synchronization is needed
// However, it could happen that the same deployment was submitted more than once to that executor
// Hence we need to recheck that the registration is really needed
final String registrationUri = deployment.getRegisterNodeUrl();
if (! needRefreshRegistration(registrationUri, deployment)) {
return;
}
if (Thread.currentThread().isInterrupted()) {
return;
}
log.debug("Sending registration event right now");
String host = getHostName();
try {
ServerRequest.invokeRegisterNodeForKeycloak(deployment, host);
NodeRegistrationContext regContext = new NodeRegistrationContext(getCurrentTimeInSeconds(), deployment);
nodeRegistrations.put(deployment.getRegisterNodeUrl(), regContext);
log.debugf("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(OidcClientConfiguration deployment) {
log.debug("Sending Unregistration event right now");
String host = getHostName();
try {
ServerRequest.invokeUnregisterNodeForKeycloak(deployment, host);
log.debugf("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 OidcClientConfiguration resolvedDeployment;
public NodeRegistrationContext(Integer lastRegTime, OidcClientConfiguration deployment) {
this.lastRegistrationTime = lastRegTime;
this.resolvedDeployment = deployment;
}
}
private static String getHostName() {
return getHostNameImpl().trim().toLowerCase();
}
private static String getHostNameImpl() {
// Return bind address if available
String bindAddr = System.getProperty("jboss.bind.address");
if (bindAddr != null && !bindAddr.trim().equals("0.0.0.0")) {
return bindAddr;
}
// Fallback to qualified name
String qualifiedHostName = System.getProperty("jboss.qualified.host.name");
if (qualifiedHostName != null) {
return qualifiedHostName;
}
// If not on jboss env, let's try other possible fallbacks
// POSIX-like OSes including Mac should have this set
qualifiedHostName = System.getenv("HOSTNAME");
if (qualifiedHostName != null) {
return qualifiedHostName;
}
// Certain versions of Windows
qualifiedHostName = System.getenv("COMPUTERNAME");
if (qualifiedHostName != null) {
return qualifiedHostName;
}
try {
return NetworkUtils.canonize(getLocalHost().getHostName());
} catch (UnknownHostException uhe) {
uhe.printStackTrace();
return "unknown-host.unknown-domain";
}
}
/**
* Methods returns InetAddress for localhost
*
* @return InetAddress of the localhost
* @throws UnknownHostException if localhost could not be resolved
*/
private static InetAddress getLocalHost() throws UnknownHostException {
InetAddress addr;
try {
addr = InetAddress.getLocalHost();
} catch (ArrayIndexOutOfBoundsException e) {
addr = InetAddress.getByName(null);
}
return addr;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy