All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgroups.auth.sasl.SimpleAuthorizingCallbackHandler Maven / Gradle / Ivy

There is a newer version: 5.3.13.Final
Show newest version
package org.jgroups.auth.sasl;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Timer;
import java.util.concurrent.TimeUnit;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.AuthorizeCallback;
import javax.security.sasl.RealmCallback;

import org.jgroups.logging.Log;
import org.jgroups.logging.LogFactory;
import org.jgroups.util.Util;

/**
 * SimpleAuthorizingCallbackHandler. This class implements a simple callback handler which can be
 * used to configure cluster authentication for the JGroups transport. It is configured via system
 * properties. The following properties are available:
 *
 * 
    *
  • sasl.credentials.properties - the path to a property file which contains principal/credential * mappings represented as principal=password
  • *
  • sasl.local.principal - the name of the principal that is used to identify the local node. It * must exist in the sasl.credentials.properties file
  • *
  • sasl.roles.properties - (optional) the path to a property file which contains principal/roles * mappings represented as principal=role1,role2,role3
  • *
  • sasl.role - (optional) if present, authorizes joining nodes only if their principal is *
  • sasl.realm - (optional) the name of the realm to use for the SASL mechanisms that require it *
  • *
* * @author Tristan Tarrant * @since 3.6 */ public class SimpleAuthorizingCallbackHandler implements CallbackHandler { private static final Log log = LogFactory.getLog(SimpleAuthorizingCallbackHandler.class); private final Properties credentials; private final Properties roles; private final Timer timer; private final String localPrincipal; private final String role; private final String realm; public SimpleAuthorizingCallbackHandler() { this(SecurityActions.getSystemProperties()); } public SimpleAuthorizingCallbackHandler(Properties properties) { this.credentials = new Properties(); this.roles = new Properties(); localPrincipal = requireProperty(properties, "sasl.local.principal"); String credentialsFile = requireProperty(properties, "sasl.credentials.properties"); timer = new Timer(); File fCredentials = new File(credentialsFile); timer.scheduleAtFixedRate( new FileWatchTask(fCredentials, new PropertiesReloadFileObserver(fCredentials, credentials)), 0, TimeUnit.SECONDS.toMillis(10)); role = properties.getProperty("sasl.role"); String rolesFile = properties.getProperty("sasl.roles.properties"); if (role != null) { if (rolesFile == null) { throw new IllegalStateException( "To enable role authorization, both sasl.role and sasl.roles.properties system properties must be set"); } else { File fRoles = new File(rolesFile); timer.scheduleAtFixedRate( new FileWatchTask(fRoles, new PropertiesReloadFileObserver(fRoles, roles)), 0, TimeUnit.SECONDS.toMillis(10)); } } realm = properties.getProperty("sasl.realm"); } private static String requireProperty(Properties properties, String propertyName) { String value = properties.getProperty(propertyName); if (value == null) { throw new IllegalStateException("The required system property " + propertyName + " has not been set"); } else { return value; } } @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { List responseCallbacks = new LinkedList<>(); String remotePrincipal = null; boolean remotePrincipalFound = false; for (Callback current : callbacks) { if (current instanceof AuthorizeCallback) { responseCallbacks.add(current); } else if (current instanceof NameCallback) { NameCallback nameCallback = (NameCallback) current; remotePrincipal = nameCallback.getDefaultName(); if (remotePrincipal != null) { // server remotePrincipalFound = credentials.containsKey(remotePrincipal); } else { // client, we need to respond responseCallbacks.add(current); } } else if (current instanceof PasswordCallback) { responseCallbacks.add(current); } else if (current instanceof RealmCallback) { String realmLocal = ((RealmCallback) current).getDefaultText(); if (realmLocal != null && !realmLocal.equals(this.realm)) { throw new IOException("Invalid realm " + realmLocal); } responseCallbacks.add(current); } else { if ("org.wildfly.security.auth.callback.AvailableRealmsCallback".equals(current.getClass().getName())) { try { current.getClass().getMethod("setRealmNames", String[].class).invoke(current, new Object[] {new String[] {realm}}); } catch (Exception e) { throw new UnsupportedCallbackException(current); } } else { throw new UnsupportedCallbackException(current); } } } for (Callback current : responseCallbacks) { if (current instanceof NameCallback) { ((NameCallback) current).setName(localPrincipal); } else if (current instanceof AuthorizeCallback) { AuthorizeCallback acb = (AuthorizeCallback) current; String authenticationId = acb.getAuthenticationID(); String authorizationId = acb.getAuthorizationID(); acb.setAuthorized(authenticationId.equals(authorizationId)); if (role != null) { String principalRoleNames = roles.getProperty(acb.getAuthorizationID()); List principalRoles = (List) (principalRoleNames != null ? Arrays.asList(principalRoleNames.split("\\s*,\\s*")) : Collections.emptyList()); if (!principalRoles.contains(role)) { throw new IOException("Unauthorized user " + authorizationId); } } } else if (current instanceof PasswordCallback) { String password; if (remotePrincipal == null) { // client, send our password password = credentials.getProperty(localPrincipal); } else if (remotePrincipalFound) { // server, validate incoming password password = credentials.getProperty(remotePrincipal); } else { throw new IOException("Unauthorized user " + remotePrincipal); } ((PasswordCallback) current).setPassword(password.toCharArray()); } else if (current instanceof RealmCallback) { ((RealmCallback)current).setText(realm); } } } public static class PropertiesReloadFileObserver implements FileObserver { private final Properties properties; PropertiesReloadFileObserver(File file, Properties properties) { this.properties = properties; loadProperties(file); } private void loadProperties(File file) { FileInputStream fis = null; try { fis = new FileInputStream(file); properties.load(fis); } catch (IOException e) { log.error(Util.getMessage("AnErrorOccurredWhileLoadingPropertiesFrom") + file, e); } finally { Util.close(fis); } } @Override public void fileChanged(File file) { loadProperties(file); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy