From 75b5ea1c45926d250c57a6a12fe83ace19f03e41 Mon Sep 17 00:00:00 2001 From: Prarthona Paul Date: Thu, 25 Jan 2024 10:55:12 -0500 Subject: [PATCH] [WFLY-14984] Add support for encrypted expressions in the wildfly-config.xml --- .../config/ConfigurationXMLStreamReader.java | 66 +++++++++++++++++++ .../client/config/ResolverProvider.java | 28 ++++++++ .../config/_private/ConfigMessages.java | 7 ++ 3 files changed, 101 insertions(+) create mode 100644 src/main/java/org/wildfly/client/config/ResolverProvider.java diff --git a/src/main/java/org/wildfly/client/config/ConfigurationXMLStreamReader.java b/src/main/java/org/wildfly/client/config/ConfigurationXMLStreamReader.java index 5831e13..e16f49b 100644 --- a/src/main/java/org/wildfly/client/config/ConfigurationXMLStreamReader.java +++ b/src/main/java/org/wildfly/client/config/ConfigurationXMLStreamReader.java @@ -26,6 +26,8 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; @@ -725,6 +727,40 @@ default Expression getExpressionAttributeValue(int index, Expression.Flag... fla final String attributeValue = getAttributeValue(index); if (attributeValue == null) { return null; + } else if (attributeValue.startsWith("env.")) { + String envVar = System.getenv().get(attributeValue.substring(4)); + + if (envVar.contains("ENC:")) { + return resolveEncryptedExpression(envVar, flags); + } else { + return Expression.compile(envVar, flags); + } + } else if (attributeValue.contains("env") || attributeValue.contains("ENV")) { + String envVar = replaceNonAlphanumericByUnderscoresAndMakeUpperCase(attributeValue); + + if (envVar.contains("ENC:")) { + return resolveEncryptedExpression(envVar, flags); + } else { + return Expression.compile(envVar, flags); + } + } else if (attributeValue.startsWith("prop.")) { + String propertyValue = System.getProperty(attributeValue.substring(5)); + + if (propertyValue.contains("ENC:")) { + return resolveEncryptedExpression(propertyValue, flags); + } else { + return Expression.compile(propertyValue, flags); + } + } else if (attributeValue.contains("prop") || attributeValue.contains("PROP")) { + String propertyValue = System.getProperty(replaceNonAlphanumericByUnderscoresAndMakeUpperCase(attributeValue)); + + if (propertyValue.contains("ENC:")) { + return resolveEncryptedExpression(propertyValue, flags); + } else { + return Expression.compile(propertyValue, flags); + } + } else if (attributeValue.contains("ENC:")) { + return resolveEncryptedExpression(attributeValue, flags); } else try { return Expression.compile(attributeValue, flags); } catch (IllegalArgumentException ex) { @@ -732,6 +768,20 @@ default Expression getExpressionAttributeValue(int index, Expression.Flag... fla } } + default Expression resolveEncryptedExpression(String attributeValue, Expression.Flag... flags) throws ConfigXMLParseException { + try { + Iterator resolverProviderIterator = ServiceLoader.load(ResolverProvider.class, ConfigurationXMLStreamReader.class.getClassLoader()).iterator(); + if (resolverProviderIterator.hasNext()) { + final ResolverProvider resolverProvider = resolverProviderIterator.next(); + return Expression.compile(resolverProvider.resolveExpression(attributeValue), flags); + } else { + throw msg.failedToLoadResolver(); + } + } catch (ServiceConfigurationError e) { + throw msg.failedToLoadUsingServiceLoader(ResolverProvider.class.getName()); + } + } + /** * Get an attribute value as a {@link InetAddress}. * @@ -811,4 +861,20 @@ default CidrAddress getCidrAddressAttributeValueResolved(int index) throws Confi return cidrAddress; } } + + default String replaceNonAlphanumericByUnderscoresAndMakeUpperCase(final String name) { + StringBuilder sb = new StringBuilder(); + int c; + for (int i = 0; i < name.length(); i += Character.charCount(c)) { + c = Character.toUpperCase(name.codePointAt(i)); + if ('A' <= c && c <= 'Z' || '0' <= c && c <= '9') { + sb.appendCodePoint(c); + } else if (c == '{' || c == '}' || c == '$') { + //ignore these characters + }else { + sb.append('_'); + } + } + return sb.toString(); + } } diff --git a/src/main/java/org/wildfly/client/config/ResolverProvider.java b/src/main/java/org/wildfly/client/config/ResolverProvider.java new file mode 100644 index 0000000..5411141 --- /dev/null +++ b/src/main/java/org/wildfly/client/config/ResolverProvider.java @@ -0,0 +1,28 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2024 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.client.config; + +/** + * An interface that allows WildFly-Client-Config to use Functions from + * Encrypted Expression Resolver without adding an Elytron dependency. + * @author Prarthona Paul + */ +public interface ResolverProvider { + String resolveExpression(String expression); +} diff --git a/src/main/java/org/wildfly/client/config/_private/ConfigMessages.java b/src/main/java/org/wildfly/client/config/_private/ConfigMessages.java index f19a863..fbf3711 100644 --- a/src/main/java/org/wildfly/client/config/_private/ConfigMessages.java +++ b/src/main/java/org/wildfly/client/config/_private/ConfigMessages.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URISyntaxException; +import java.util.ServiceConfigurationError; import javax.xml.namespace.QName; import javax.xml.stream.Location; @@ -115,4 +116,10 @@ public interface ConfigMessages { @Message(id = 24, value = "Failed to parse CIDR address value of attribute \"%s\": \"%s\" is not a valid CIDR address") ConfigXMLParseException cidrAddressParseException(QName attributeName, String address, @Param(Location.class) XMLLocation location); + + @Message(id = 25, value = "Failed to load a resolver for the encrypted expression.") + ConfigXMLParseException failedToLoadResolver(); + + @Message(id = 26, value = "Failed to load the \"%s\" class using a service loader.") + ServiceConfigurationError failedToLoadUsingServiceLoader(String className); }