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

com.hazelcast.config.replacer.EncryptionReplacer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2008-2024, Hazelcast, Inc. All Rights Reserved.
 *
 * 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 com.hazelcast.config.replacer;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathException;
import javax.xml.xpath.XPathFactory;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Properties;

import static com.hazelcast.internal.config.DomConfigHelper.childElements;
import static com.hazelcast.internal.config.DomConfigHelper.cleanNodeName;
import static com.hazelcast.internal.nio.IOUtil.closeResource;
import static com.hazelcast.internal.util.ExceptionUtil.rethrow;
import static com.hazelcast.internal.util.Preconditions.checkFalse;
import static com.hazelcast.internal.util.Preconditions.checkPositive;
import static com.hazelcast.internal.util.StringUtil.trim;
import static com.hazelcast.internal.util.XmlUtil.getNsAwareDocumentBuilderFactory;
import static java.lang.String.format;

/**
 * This class is an example {@link com.hazelcast.config.replacer.spi.ConfigReplacer} implementation which decrypts
 * encrypted values.
 * 

* The {@link #main(String...)} method is provided to generate the encrypted variables. *

* This class extends {@link AbstractPbeReplacer} where the main encryption logic is located. This class implements * {@link #getPassword()} method and depending on configuration allows to use a password file and/or user properties (name and * HOME) and/or network interface properties (MAC address). */ public class EncryptionReplacer extends AbstractPbeReplacer { /** * Replacer property name to configure {@code true}/{@code false} flag controlling if users properties should be used as part * of the encryption password. */ public static final String PROPERTY_PASSWORD_USER_PROPERTIES = "passwordUserProperties"; /** * Replacer property name to configure network interface name used to retrieve MAC address used as part of the encryption * password. */ public static final String PROPERTY_PASSWORD_NETWORK_INTERFACE = "passwordNetworkInterface"; /** * Replacer property name to configure path to a password file which content should be used as part of the encryption * password. */ public static final String PROPERTY_PASSWORD_FILE = "passwordFile"; private static final String PREFIX = "ENC"; private static final int DEFAULT_ITERATIONS = 531; private boolean passwordUserProperties; private String passwordNetworkInterface; private String passwordFile; @Override public void init(Properties properties) { super.init(properties); passwordFile = properties.getProperty(PROPERTY_PASSWORD_FILE); passwordUserProperties = Boolean.parseBoolean(properties.getProperty(PROPERTY_PASSWORD_USER_PROPERTIES, "true")); passwordNetworkInterface = properties.getProperty(PROPERTY_PASSWORD_NETWORK_INTERFACE); checkFalse(passwordFile == null && passwordNetworkInterface == null && !passwordUserProperties, "At least one of the properties used to generate encryption password has to be configured"); } @Override public String getPrefix() { return PREFIX; } @Override protected char[] getPassword() { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (passwordFile != null) { try (FileInputStream fis = new FileInputStream(passwordFile)) { fis.transferTo(baos); } } if (passwordUserProperties) { baos.write(System.getProperty("user.home").getBytes(StandardCharsets.UTF_8)); baos.write(System.getProperty("user.name").getBytes(StandardCharsets.UTF_8)); } if (passwordNetworkInterface != null) { try { NetworkInterface iface = NetworkInterface.getByName(passwordNetworkInterface); baos.write(iface.getHardwareAddress()); } catch (SocketException e) { throw rethrow(e); } } return new String(Base64.getEncoder().encode(baos.toByteArray()), StandardCharsets.UTF_8).toCharArray(); } catch (Exception e) { throw rethrow(e); } } public static final void main(String... args) throws Exception { if (args == null || args.length < 1 || args.length > 2) { System.err.println("Usage:"); System.err.println("\tjava -D= " + EncryptionReplacer.class.getName() + " \"\" [iterations]"); System.err.println(); System.err.println("The replacer configuration can be loaded either from hazelcast/hazelcast-client XML file:"); System.err.println("\t-Dhazelcast.config=/path/to/hazelcast.xml"); System.err.println(); System.err.println("or provided directly via following property names:"); System.err.println("\t" + PROPERTY_CIPHER_ALGORITHM); System.err.println("\t" + PROPERTY_KEY_LENGTH_BITS); System.err.println("\t" + PROPERTY_SALT_LENGTH_BYTES); System.err.println("\t" + PROPERTY_SECRET_KEY_ALGORITHM); System.err.println("\t" + PROPERTY_SECRET_KEY_FACTORY_ALGORITHM); System.err.println("\t" + PROPERTY_SECURITY_PROVIDER); System.err.println("\t" + PROPERTY_PASSWORD_FILE); System.err.println("\t" + PROPERTY_PASSWORD_NETWORK_INTERFACE); System.err.println("\t" + PROPERTY_PASSWORD_USER_PROPERTIES); System.err.println(); System.err.println("Values available for property " + PROPERTY_PASSWORD_NETWORK_INTERFACE); Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); while (networkInterfaces.hasMoreElements()) { NetworkInterface networkInterface = networkInterfaces.nextElement(); byte[] hardwareAddress = networkInterface.getHardwareAddress(); if (hardwareAddress != null) { System.err.println("\t" + networkInterface.getName()); } } System.err.println(); System.exit(1); } System.out.println(encrypt(args)); } protected static String encrypt(String... args) throws Exception { int iterations = args.length == 2 ? Integer.parseInt(args[1]) : DEFAULT_ITERATIONS; EncryptionReplacer replacer = new EncryptionReplacer(); String xmlPath = System.getProperty("hazelcast.config"); Properties properties = xmlPath == null ? System.getProperties() : loadPropertiesFromConfig(new FileInputStream(xmlPath)); replacer.init(properties); String encrypted = replacer.encrypt(args[0], iterations); String variable = "$" + replacer.getPrefix() + "{" + encrypted + "}"; return variable; } private static Properties loadPropertiesFromConfig(FileInputStream fileInputStream) throws Exception { try { DocumentBuilder builder = getNsAwareDocumentBuilderFactory().newDocumentBuilder(); Document doc = builder.parse(fileInputStream); Element root = doc.getDocumentElement(); return loadProperties(findReplacerDefinition(root)); } finally { closeResource(fileInputStream); } } private static Node findReplacerDefinition(Element root) throws XPathException { XPath xpath = XPathFactory.newInstance().newXPath(); xpath.setNamespaceContext(new HzNsContext()); String xpathExp = "//%s:config-replacers/%1$s:replacer[@class-name='%s']"; NodeList replaceTags = (NodeList) xpath.evaluate(format(xpathExp, "hz", EncryptionReplacer.class.getName()), root, XPathConstants.NODESET); if (replaceTags.getLength() < 1) { replaceTags = (NodeList) xpath.evaluate(format(xpathExp, "hz-client", EncryptionReplacer.class.getName()), root, XPathConstants.NODESET); checkPositive(replaceTags.getLength(), "No EncryptionReplacer definition found within the provided XML document."); } return replaceTags.item(0); } private static Properties loadProperties(Node node) { Properties properties = new Properties(); for (Node n : childElements(node)) { String value = cleanNodeName(n); if ("properties".equals(value)) { fillProperties(n, properties); } } return properties; } private static void fillProperties(Node node, Properties properties) { if (properties == null) { return; } for (Node n : childElements(node)) { String name = cleanNodeName(n); if ("property".equals(name)) { String propertyName = getTextContent(n.getAttributes().getNamedItem("name")); String value = trim(getTextContent(n)); properties.setProperty(propertyName, value == null ? "" : value); } } } private static String getTextContent(Node node) { try { return node.getTextContent(); } catch (Exception e) { return getTextContentOld(node); } } private static String getTextContentOld(Node node) { Node child = node.getFirstChild(); if (child != null) { Node next = child.getNextSibling(); if (next == null) { return hasTextContent(child) ? child.getNodeValue() : null; } StringBuilder buf = new StringBuilder(); appendTextContents(node, buf); return buf.toString(); } return null; } private static void appendTextContents(Node node, StringBuilder buf) { Node child = node.getFirstChild(); while (child != null) { if (hasTextContent(child)) { buf.append(child.getNodeValue()); } child = child.getNextSibling(); } } private static boolean hasTextContent(Node node) { short nodeType = node.getNodeType(); return nodeType != Node.COMMENT_NODE && nodeType != Node.PROCESSING_INSTRUCTION_NODE; } private static class HzNsContext implements NamespaceContext { @Override public String getNamespaceURI(String prefix) { if ("hz".equals(prefix)) { return "http://www.hazelcast.com/schema/config"; } else if ("hz-client".equals(prefix)) { return "http://www.hazelcast.com/schema/client-config"; } return null; } @Override public String getPrefix(String namespaceURI) { return null; } @Override @SuppressWarnings("rawtypes") public Iterator getPrefixes(String namespaceURI) { return null; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy