diff options
Diffstat (limited to 'qpid/java/broker-core/src/main/java/org/apache')
34 files changed, 549 insertions, 59 deletions
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/BrokerOptions.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/BrokerOptions.java index fc3ec82041..a6fae97aaa 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/BrokerOptions.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/BrokerOptions.java @@ -25,6 +25,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.apache.qpid.server.configuration.BrokerProperties; import org.apache.qpid.server.model.ConfiguredObject; @@ -54,6 +55,7 @@ public class BrokerOptions public static final String DEFAULT_LOG_CONFIG_FILE = "etc/log4j.xml"; public static final String DEFAULT_INITIAL_CONFIG_LOCATION = BrokerOptions.class.getClassLoader().getResource(DEFAULT_INITIAL_CONFIG_NAME).toExternalForm(); + public static final String MANAGEMENT_MODE_USER_NAME = "mm_admin"; private static final int MANAGEMENT_MODE_PASSWORD_LENGTH = 10; @@ -76,6 +78,7 @@ public class BrokerOptions private boolean _skipLoggingConfiguration; private boolean _overwriteConfigurationStore; private Map<String, String> _configProperties = new HashMap<String,String>(); + private String _initialSystemProperties; public Map<String, Object> convertToSystemAttributes() { @@ -304,7 +307,7 @@ public class BrokerOptions */ public Map<String,String> getConfigProperties() { - ConcurrentHashMap<String, String> properties = new ConcurrentHashMap<String,String>(); + ConcurrentMap<String, String> properties = new ConcurrentHashMap<String,String>(); properties.putAll(_configProperties); properties.putIfAbsent(QPID_WORK_DIR, getWorkDir()); @@ -369,4 +372,5 @@ public class BrokerOptions return _configProperties.get(QPID_HOME_DIR); } + } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandler.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandler.java index 2a39cfa642..44b76cd5c8 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandler.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandler.java @@ -34,6 +34,9 @@ import org.apache.qpid.server.BrokerOptions; import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.ConfiguredObjectAttribute; +import org.apache.qpid.server.model.ConfiguredObjectTypeRegistry; +import org.apache.qpid.server.model.Model; import org.apache.qpid.server.model.Port; import org.apache.qpid.server.model.Protocol; import org.apache.qpid.server.model.State; @@ -44,7 +47,6 @@ import org.apache.qpid.server.store.ConfiguredObjectRecordImpl; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.store.StoreException; import org.apache.qpid.server.store.handler.ConfiguredObjectRecordHandler; -import org.apache.qpid.server.util.MapValueConverter; public class ManagementModeStoreHandler implements DurableConfigurationStore { @@ -455,7 +457,13 @@ public class ManagementModeStoreHandler implements DurableConfigurationStore { return null; } - return MapValueConverter.getEnumSetAttribute(Port.PROTOCOLS, attributes, Protocol.class); + Model model = _parent.getModel(); + ConfiguredObjectTypeRegistry typeRegistry = model.getTypeRegistry(); + Map<String, ConfiguredObjectAttribute<?, ?>> attributeTypes = + typeRegistry.getAttributeTypes(Port.class); + ConfiguredObjectAttribute protocolsAttribute = attributeTypes.get(Port.PROTOCOLS); + return (Set<Protocol>) protocolsAttribute.convert(object,_parent); + } private ConfiguredObjectRecord createEntryWithState(ConfiguredObjectRecord entry, Object state) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index e41bb948dc..4472669f4a 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -30,6 +30,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -102,7 +103,7 @@ public abstract class AbstractExchange<T extends AbstractExchange<T>> private final CopyOnWriteArrayList<ExchangeImpl.BindingListener> _listeners = new CopyOnWriteArrayList<ExchangeImpl.BindingListener>(); - private final ConcurrentHashMap<BindingIdentifier, BindingImpl> _bindingsMap = new ConcurrentHashMap<BindingIdentifier, BindingImpl>(); + private final ConcurrentMap<BindingIdentifier, BindingImpl> _bindingsMap = new ConcurrentHashMap<BindingIdentifier, BindingImpl>(); private StateChangeListener<BindingImpl, State> _bindingListener; private State _state = State.UNINITIALIZED; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index 4997095315..66de22ece8 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArraySet; import org.apache.log4j.Logger; @@ -133,7 +134,7 @@ public class DirectExchange extends AbstractExchange<DirectExchange> } } - private final ConcurrentHashMap<String, BindingSet> _bindingsByKey = + private final ConcurrentMap<String, BindingSet> _bindingsByKey = new ConcurrentHashMap<String, BindingSet>(); @ManagedObjectFactoryConstructor diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 83c6b9fd00..67bbc26f74 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -25,6 +25,7 @@ import java.util.LinkedHashSet; import java.util.ListIterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; @@ -74,7 +75,7 @@ public class HeadersExchange extends AbstractExchange<HeadersExchange> private static final Logger _logger = Logger.getLogger(HeadersExchange.class); - private final ConcurrentHashMap<String, CopyOnWriteArraySet<BindingImpl>> _bindingsByKey = + private final ConcurrentMap<String, CopyOnWriteArraySet<BindingImpl>> _bindingsByKey = new ConcurrentHashMap<String, CopyOnWriteArraySet<BindingImpl>>(); private final CopyOnWriteArrayList<HeadersBinding> _bindingHeaderMatchers = diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java index d3a6bd9260..0db3e9b378 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java @@ -20,11 +20,6 @@ */ package org.apache.qpid.server.exchange.topic; -import org.apache.qpid.server.binding.BindingImpl; -import org.apache.qpid.server.filter.Filterable; -import org.apache.qpid.server.filter.MessageFilter; -import org.apache.qpid.server.queue.AMQQueue; - import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -32,13 +27,19 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; +import org.apache.qpid.server.binding.BindingImpl; +import org.apache.qpid.server.filter.Filterable; +import org.apache.qpid.server.filter.MessageFilter; +import org.apache.qpid.server.queue.AMQQueue; + public final class TopicExchangeResult implements TopicMatcherResult { private final List<BindingImpl> _bindings = new CopyOnWriteArrayList<BindingImpl>(); private final Map<AMQQueue, Integer> _unfilteredQueues = new ConcurrentHashMap<AMQQueue, Integer>(); - private final ConcurrentHashMap<AMQQueue, Map<MessageFilter,Integer>> _filteredQueues = new ConcurrentHashMap<AMQQueue, Map<MessageFilter, Integer>>(); + private final ConcurrentMap<AMQQueue, Map<MessageFilter,Integer>> _filteredQueues = new ConcurrentHashMap<AMQQueue, Map<MessageFilter, Integer>>(); private volatile ArrayList<AMQQueue> _unfilteredQueueList = new ArrayList<AMQQueue>(0); public void addUnfilteredQueue(AMQQueue queue) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java index 24c41ee7da..181f1d32b7 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java @@ -21,10 +21,11 @@ package org.apache.qpid.server.exchange.topic; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; public class TopicWordDictionary { - private final ConcurrentHashMap<String,TopicWord> _dictionary = + private final ConcurrentMap<String,TopicWord> _dictionary = new ConcurrentHashMap<String,TopicWord>(); public TopicWordDictionary() diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/logging/messages/HighAvailabilityMessages.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/logging/messages/HighAvailabilityMessages.java index b864a8c095..2234ce6b74 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/logging/messages/HighAvailabilityMessages.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/logging/messages/HighAvailabilityMessages.java @@ -144,7 +144,7 @@ public class HighAvailabilityMessages /** * Log a HighAvailability message of the Format: - * <pre>HA-1011 : Minimum group : {0}</pre> + * <pre>HA-1011 : Minimum group size : {0}</pre> * Optional values are contained in [square brackets] and are numbered * sequentially in the method call. * @@ -326,7 +326,7 @@ public class HighAvailabilityMessages /** * Log a HighAvailability message of the Format: - * <pre>HA-1012 : Priority : {0}</pre> + * <pre>HA-1012 : Priority : {0}</pre> * Optional values are contained in [square brackets] and are numbered * sequentially in the method call. * diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/logging/messages/HighAvailability_logmessages.properties b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/logging/messages/HighAvailability_logmessages.properties index 3c5b0d260f..1a6bff5353 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/logging/messages/HighAvailability_logmessages.properties +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/logging/messages/HighAvailability_logmessages.properties @@ -53,10 +53,10 @@ QUORUM_LOST = HA-1009 : Insufficient replicas contactable ROLE_CHANGED = HA-1010 : Role change reported: Node : ''{0}'' ({1}) : from ''{2}'' to ''{3}'' # 0 - new value -QUORUM_OVERRIDE_CHANGED = HA-1011 : Minimum group : {0} +QUORUM_OVERRIDE_CHANGED = HA-1011 : Minimum group size : {0} # 0 - new value -PRIORITY_CHANGED = HA-1012 : Priority : {0} +PRIORITY_CHANGED = HA-1012 : Priority : {0} # 0 - new value DESIGNATED_PRIMARY_CHANGED = HA-1013 : Designated primary : {0} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java index b191db8523..18930d8817 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java @@ -64,6 +64,7 @@ import org.apache.qpid.server.configuration.updater.VoidTask; import org.apache.qpid.server.configuration.updater.VoidTaskWithException; import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.auth.AuthenticatedPrincipal; +import org.apache.qpid.server.security.encryption.ConfigurationSecretEncrypter; import org.apache.qpid.server.store.ConfiguredObjectRecord; import org.apache.qpid.server.util.Action; import org.apache.qpid.server.util.ServerScopedRuntimeException; @@ -89,6 +90,8 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im SECURE_VALUES = Collections.unmodifiableMap(secureValues); } + private ConfigurationSecretEncrypter _encrypter; + private enum DynamicState { UNINIT, OPENED, CLOSED }; private final AtomicReference<DynamicState> _dynamicState = new AtomicReference<>(DynamicState.UNINIT); @@ -201,6 +204,16 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im _automatedFields = model.getTypeRegistry().getAutomatedFields(getClass()); _stateChangeMethods = model.getTypeRegistry().getStateChangeMethods(getClass()); + + for(ConfiguredObject<?> parent : parents.values()) + { + if(parent instanceof AbstractConfiguredObject && ((AbstractConfiguredObject)parent)._encrypter != null) + { + _encrypter = ((AbstractConfiguredObject)parent)._encrypter; + break; + } + } + Object idObj = attributes.get(ID); UUID uuid; @@ -541,6 +554,7 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im if(skipCheck || _dynamicState.get() != DynamicState.OPENED) { onResolve(); + postResolve(); applyToChildren(new Action<ConfiguredObject<?>>() { @Override @@ -555,6 +569,10 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im } } + protected void postResolve() + { + } + protected final void doCreation(final boolean skipCheck) { if(skipCheck || _dynamicState.get() != DynamicState.OPENED) @@ -593,6 +611,11 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { } + protected void setEncrypter(final ConfigurationSecretEncrypter encrypter) + { + _encrypter = encrypter; + } + protected void onResolve() { Set<ConfiguredObjectAttribute<?,?>> unresolved = new HashSet<>(); @@ -1094,6 +1117,26 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { value = ((ConfiguredObject)value).getId(); } + if(attr.isSecure() && _encrypter != null && value != null) + { + if(value instanceof Collection || value instanceof Map) + { + ObjectMapper mapper = new ObjectMapper(); + try(StringWriter stringWriter = new StringWriter()) + { + mapper.writeValue(stringWriter, value); + value = _encrypter.encrypt(stringWriter.toString()); + } + catch (IOException e) + { + throw new IllegalConfigurationException("Failure when encrypting a secret value", e); + } + } + else + { + value = _encrypter.encrypt(value.toString()); + } + } attributes.put(attr.getName(), value); } } @@ -1427,6 +1470,27 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im return false; } + @Override + public void decryptSecrets() + { + if(_encrypter != null) + { + for (Map.Entry<String, Object> entry : _attributes.entrySet()) + { + ConfiguredObjectAttribute<X, ?> attr = + (ConfiguredObjectAttribute<X, ?>) _attributeTypes.get(entry.getKey()); + if (attr != null + && attr.isSecure() + && entry.getValue() instanceof String) + { + String decrypt = _encrypter.decrypt((String) entry.getValue()); + entry.setValue(decrypt); + } + + } + } + } + //========================================================================================= static String interpolate(ConfiguredObject<?> object, String value) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java index 1a9390f210..011aaeee23 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java @@ -51,6 +51,7 @@ public interface Broker<X extends Broker<X>> extends ConfiguredObject<X>, EventL String STORE_VERSION = "storeVersion"; String STORE_PATH = "storePath"; String MODEL_VERSION = "modelVersion"; + String CONFIDENTIAL_CONFIGURATION_ENCRYPTION_PROVIDER = "confidentialConfigurationEncryptionProvider"; String CONNECTION_SESSION_COUNT_LIMIT = "connection.sessionCountLimit"; String CONNECTION_HEART_BEAT_DELAY = "connection.heartBeatDelay"; @@ -139,6 +140,8 @@ public interface Broker<X extends Broker<X>> extends ConfiguredObject<X>, EventL @ManagedContextDefault(name = MESSAGE_COMPRESSION_THRESHOLD_SIZE) int DEFAULT_MESSAGE_COMPRESSION_THRESHOLD_SIZE = 102400; + @ManagedAttribute + String getConfidentialConfigurationEncryptionProvider(); @DerivedAttribute( persist = true ) String getModelVersion(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/BrokerModel.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/BrokerModel.java index 2cffea5d73..02c9ccf8e1 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/BrokerModel.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/BrokerModel.java @@ -105,7 +105,7 @@ public final class BrokerModel extends Model addRelationship(Session.class, Publisher.class); _objectFactory = new ConfiguredObjectFactoryImpl(this); - _typeRegistry = new ConfiguredObjectTypeRegistry((new QpidServiceLoader<ConfiguredObjectRegistration>()).instancesOf(ConfiguredObjectRegistration.class), getSupportedCategories()); + _typeRegistry = new ConfiguredObjectTypeRegistry((new QpidServiceLoader()).instancesOf(ConfiguredObjectRegistration.class), getSupportedCategories()); } public final ConfiguredObjectTypeRegistry getTypeRegistry() diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java index ac5c75f80f..deda7768f3 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java @@ -253,4 +253,6 @@ public interface ConfiguredObject<X extends ConfiguredObject<X>> Model getModel(); void delete(); + + void decryptSecrets(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFactoryImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFactoryImpl.java index 440a790fc8..350e4fcd44 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFactoryImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFactoryImpl.java @@ -44,8 +44,8 @@ public class ConfiguredObjectFactoryImpl implements ConfiguredObjectFactory public ConfiguredObjectFactoryImpl(Model model) { _model = model; - QpidServiceLoader<ConfiguredObjectTypeFactory> serviceLoader = - new QpidServiceLoader<ConfiguredObjectTypeFactory>(); + QpidServiceLoader serviceLoader = + new QpidServiceLoader(); Iterable<ConfiguredObjectTypeFactory> allFactories = serviceLoader.instancesOf(ConfiguredObjectTypeFactory.class); for (ConfiguredObjectTypeFactory factory : allFactories) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java index af46bae1c4..afa68e23b1 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java @@ -47,6 +47,8 @@ import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.logging.messages.VirtualHostMessages; import org.apache.qpid.server.model.*; import org.apache.qpid.server.model.port.AbstractPortWithAuthProvider; +import org.apache.qpid.server.plugin.ConfigurationSecretEncrypterFactory; +import org.apache.qpid.server.plugin.PluggableFactoryLoader; import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.SubjectCreator; import org.apache.qpid.server.security.access.Operation; @@ -94,6 +96,8 @@ public class BrokerAdapter extends AbstractConfiguredObject<BrokerAdapter> imple private boolean _statisticsReportingResetEnabled; @ManagedAttributeField private boolean _messageCompressionEnabled; + @ManagedAttributeField + private String _confidentialConfigurationEncryptionProvider; private State _state = State.UNINITIALIZED; @@ -122,6 +126,25 @@ public class BrokerAdapter extends AbstractConfiguredObject<BrokerAdapter> imple _dataReceived = new StatisticsCounter("bytes-received"); } + @Override + protected void postResolve() + { + super.postResolve(); + if(_confidentialConfigurationEncryptionProvider != null) + { + + PluggableFactoryLoader<ConfigurationSecretEncrypterFactory> factoryLoader = + new PluggableFactoryLoader<>(ConfigurationSecretEncrypterFactory.class); + ConfigurationSecretEncrypterFactory factory = factoryLoader.get(_confidentialConfigurationEncryptionProvider); + if(factory == null) + { + throw new IllegalConfigurationException("Unknown Configuration Secret Encryption method " + _confidentialConfigurationEncryptionProvider); + } + setEncrypter(factory.createEncrypter(this)); + } + + } + public void onValidate() { super.onValidate(); @@ -368,6 +391,12 @@ public class BrokerAdapter extends AbstractConfiguredObject<BrokerAdapter> imple } @Override + public String getConfidentialConfigurationEncryptionProvider() + { + return _confidentialConfigurationEncryptionProvider; + } + + @Override public String getModelVersion() { return BrokerModel.MODEL_VERSION; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java index 6f6d04c335..1fbc0c8bc1 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java @@ -151,8 +151,7 @@ public class AmqpPortImpl extends AbstractPortWithAuthProvider<AmqpPortImpl> imp TransportProvider transportProvider = null; final HashSet<Transport> transportSet = new HashSet<Transport>(transports); - for (TransportProviderFactory tpf : (new QpidServiceLoader<TransportProviderFactory>()).instancesOf( - TransportProviderFactory.class)) + for (TransportProviderFactory tpf : (new QpidServiceLoader()).instancesOf(TransportProviderFactory.class)) { if (tpf.getSupportedTransports().contains(transports)) { @@ -284,7 +283,7 @@ public class AmqpPortImpl extends AbstractPortWithAuthProvider<AmqpPortImpl> imp public static Set<Protocol> getInstalledProtocols() { Set<Protocol> protocols = new HashSet<>(); - for(ProtocolEngineCreator installedEngine : (new QpidServiceLoader<ProtocolEngineCreator>()).instancesOf(ProtocolEngineCreator.class)) + for(ProtocolEngineCreator installedEngine : (new QpidServiceLoader()).instancesOf(ProtocolEngineCreator.class)) { protocols.add(installedEngine.getVersion()); } @@ -343,7 +342,7 @@ public class AmqpPortImpl extends AbstractPortWithAuthProvider<AmqpPortImpl> imp { Set<Set<Transport>> combinations = new HashSet<>(); - for(TransportProviderFactory providerFactory : (new QpidServiceLoader<TransportProviderFactory>()).instancesOf(TransportProviderFactory.class)) + for(TransportProviderFactory providerFactory : (new QpidServiceLoader()).instancesOf(TransportProviderFactory.class)) { combinations.addAll(providerFactory.getSupportedTransports()); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/PortFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/PortFactory.java index 99ec4b79cb..870621f292 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/PortFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/PortFactory.java @@ -24,8 +24,12 @@ import java.util.Map; import java.util.Set; import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.ConfiguredObjectAttribute; import org.apache.qpid.server.model.ConfiguredObjectFactory; +import org.apache.qpid.server.model.ConfiguredObjectTypeRegistry; +import org.apache.qpid.server.model.Model; import org.apache.qpid.server.model.Port; import org.apache.qpid.server.model.Protocol; import org.apache.qpid.server.model.Protocol.ProtocolType; @@ -34,7 +38,6 @@ import org.apache.qpid.server.plugin.ConfiguredObjectTypeFactory; import org.apache.qpid.server.plugin.PluggableService; import org.apache.qpid.server.store.ConfiguredObjectRecord; import org.apache.qpid.server.store.UnresolvedConfiguredObject; -import org.apache.qpid.server.util.MapValueConverter; @PluggableService public class PortFactory<X extends Port<X>> implements ConfiguredObjectTypeFactory<X> @@ -52,11 +55,14 @@ public class PortFactory<X extends Port<X>> implements ConfiguredObjectTypeFacto { } - private ProtocolType getProtocolType(Map<String, Object> portAttributes) + private ProtocolType getProtocolType(Map<String, Object> portAttributes, Broker<?> broker) { - - Set<Protocol> protocols = MapValueConverter.getEnumSetAttribute(Port.PROTOCOLS, portAttributes, Protocol.class); - + Model model = broker.getModel(); + ConfiguredObjectTypeRegistry typeRegistry = model.getTypeRegistry(); + Map<String, ConfiguredObjectAttribute<?, ?>> attributeTypes = + typeRegistry.getAttributeTypes(Port.class); + ConfiguredObjectAttribute protocolsAttribute = attributeTypes.get(Port.PROTOCOLS); + Set<Protocol> protocols = (Set<Protocol>) protocolsAttribute.convert(portAttributes.get(Port.PROTOCOLS),broker); ProtocolType protocolType = null; if(protocols == null || protocols.isEmpty()) @@ -98,7 +104,7 @@ public class PortFactory<X extends Port<X>> implements ConfiguredObjectTypeFacto final Map<String, Object> attributes, final ConfiguredObject<?>... parents) { - return getPortFactory(factory, attributes).create(factory, attributes,parents); + return getPortFactory(factory, attributes, (Broker<?>)parents[0]).create(factory, attributes,parents); } @Override @@ -106,11 +112,12 @@ public class PortFactory<X extends Port<X>> implements ConfiguredObjectTypeFacto final ConfiguredObjectRecord record, final ConfiguredObject<?>... parents) { - return getPortFactory(factory, record.getAttributes()).recover(factory, record, parents); + return getPortFactory(factory, record.getAttributes(), (Broker<?>)parents[0]).recover(factory, record, parents); } public ConfiguredObjectTypeFactory<X> getPortFactory(final ConfiguredObjectFactory factory, - Map<String, Object> attributes) + Map<String, Object> attributes, + Broker<?> broker) { String type; @@ -120,7 +127,7 @@ public class PortFactory<X extends Port<X>> implements ConfiguredObjectTypeFacto } else { - type = getProtocolType(attributes).name(); + type = getProtocolType(attributes, broker).name(); } return factory.getConfiguredObjectTypeFactory(Port.class.getSimpleName(), type); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/ConfigurationSecretEncrypterFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/ConfigurationSecretEncrypterFactory.java new file mode 100644 index 0000000000..0548e6418a --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/ConfigurationSecretEncrypterFactory.java @@ -0,0 +1,29 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.qpid.server.plugin; + +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.security.encryption.ConfigurationSecretEncrypter; + +public interface ConfigurationSecretEncrypterFactory extends Pluggable +{ + public ConfigurationSecretEncrypter createEncrypter(ConfiguredObject<?> object); +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/JDBCConnectionProviderFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/JDBCConnectionProviderFactory.java index 14acd59928..6375a03cdf 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/JDBCConnectionProviderFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/JDBCConnectionProviderFactory.java @@ -21,14 +21,9 @@ package org.apache.qpid.server.plugin; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.store.jdbc.ConnectionProvider; public interface JDBCConnectionProviderFactory extends Pluggable @@ -48,7 +43,7 @@ public interface JDBCConnectionProviderFactory extends Pluggable public static JDBCConnectionProviderFactory get(String type) { - QpidServiceLoader<JDBCConnectionProviderFactory> qpidServiceLoader = new QpidServiceLoader<JDBCConnectionProviderFactory>(); + QpidServiceLoader qpidServiceLoader = new QpidServiceLoader(); Iterable<JDBCConnectionProviderFactory> factories = qpidServiceLoader.atLeastOneInstanceOf(JDBCConnectionProviderFactory.class); for(JDBCConnectionProviderFactory factory : factories) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/PluggableFactoryLoader.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/PluggableFactoryLoader.java index 40db520ff1..462f32e636 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/PluggableFactoryLoader.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/PluggableFactoryLoader.java @@ -33,7 +33,7 @@ public class PluggableFactoryLoader<T extends Pluggable> public PluggableFactoryLoader(Class<T> factoryClass) { Map<String, T> fm = new HashMap<String, T>(); - QpidServiceLoader<T> qpidServiceLoader = new QpidServiceLoader<T>(); + QpidServiceLoader qpidServiceLoader = new QpidServiceLoader(); Iterable<T> factories = qpidServiceLoader.atLeastOneInstanceOf(factoryClass); for (T factory : factories) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/QpidServiceLoader.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/QpidServiceLoader.java index 6920d5a879..9f94e7d09d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/QpidServiceLoader.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/QpidServiceLoader.java @@ -24,16 +24,17 @@ import java.util.List; import java.util.ServiceLoader; import org.apache.log4j.Logger; + import org.apache.qpid.server.util.ServerScopedRuntimeException; /** * Simple facade over a {@link ServiceLoader} to instantiate all configured implementations of an interface. */ -public class QpidServiceLoader<C extends Pluggable> +public class QpidServiceLoader { private static final Logger _logger = Logger.getLogger(QpidServiceLoader.class); - public Iterable<C> instancesOf(Class<C> clazz) + public <C extends Pluggable> Iterable<C> instancesOf(Class<C> clazz) { return instancesOf(clazz, false); } @@ -41,12 +42,12 @@ public class QpidServiceLoader<C extends Pluggable> /** * @throws RuntimeException if at least one implementation is not found. */ - public Iterable<C> atLeastOneInstanceOf(Class<C> clazz) + public <C extends Pluggable> Iterable<C> atLeastOneInstanceOf(Class<C> clazz) { return instancesOf(clazz, true); } - private Iterable<C> instancesOf(Class<C> clazz, boolean atLeastOne) + private <C extends Pluggable> Iterable<C> instancesOf(Class<C> clazz, boolean atLeastOne) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Iterator<C> serviceLoaderIterator = ServiceLoader.load(clazz, classLoader).iterator(); @@ -55,7 +56,11 @@ public class QpidServiceLoader<C extends Pluggable> List<C> serviceImplementations = new ArrayList<C>(); while(serviceLoaderIterator.hasNext()) { - serviceImplementations.add(serviceLoaderIterator.next()); + C next = serviceLoaderIterator.next(); + if(!isDisabled(clazz, next)) + { + serviceImplementations.add(next); + } } if(atLeastOne && serviceImplementations.isEmpty()) @@ -70,4 +75,16 @@ public class QpidServiceLoader<C extends Pluggable> return serviceImplementations; } + + private <C extends Pluggable> boolean isDisabled(Class<C> clazz, final C next) + { + return Boolean.getBoolean("qpid.plugin.disabled:"+clazz.getSimpleName().toLowerCase()+"."+next.getType()) + || (next instanceof ConfiguredObjectTypeFactory && isDisabledConfiguredType((ConfiguredObjectTypeFactory<?>) next)); + } + + private boolean isDisabledConfiguredType(final ConfiguredObjectTypeFactory<?> typeFactory) + { + return Boolean.getBoolean("qpid.type.disabled:" + typeFactory.getCategoryClass().getSimpleName().toLowerCase() + + "." + typeFactory.getType()); + } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/protocol/MessageConverterRegistry.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/protocol/MessageConverterRegistry.java index 81e5af179d..7959c7f6b4 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/protocol/MessageConverterRegistry.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/protocol/MessageConverterRegistry.java @@ -35,7 +35,7 @@ public class MessageConverterRegistry static { - for(MessageConverter<? extends ServerMessage, ? extends ServerMessage> converter : (new QpidServiceLoader<MessageConverter>()).instancesOf(MessageConverter.class)) + for(MessageConverter<? extends ServerMessage, ? extends ServerMessage> converter : (new QpidServiceLoader()).instancesOf(MessageConverter.class)) { Map<Class<? extends ServerMessage>, MessageConverter> map = _converters.get(converter.getInputClass()); if(map == null) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactory.java index b1c49c6fe5..ac8bdc3fa4 100755 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactory.java @@ -72,7 +72,7 @@ public class MultiVersionProtocolEngineFactory implements ProtocolEngineFactory _supported = supportedVersions; _defaultSupportedReply = defaultSupportedReply; final List<ProtocolEngineCreator> creators = new ArrayList<ProtocolEngineCreator>(); - for(ProtocolEngineCreator c : new QpidServiceLoader<ProtocolEngineCreator>().instancesOf(ProtocolEngineCreator.class)) + for(ProtocolEngineCreator c : new QpidServiceLoader().instancesOf(ProtocolEngineCreator.class)) { creators.add(c); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AssignedConsumerMessageGroupManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AssignedConsumerMessageGroupManager.java index 8220993e03..e1b25e5abb 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AssignedConsumerMessageGroupManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AssignedConsumerMessageGroupManager.java @@ -20,11 +20,12 @@ */ package org.apache.qpid.server.queue; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class AssignedConsumerMessageGroupManager implements MessageGroupManager @@ -33,7 +34,7 @@ public class AssignedConsumerMessageGroupManager implements MessageGroupManager private final String _groupId; - private final ConcurrentHashMap<Integer, QueueConsumer<?>> _groupMap = new ConcurrentHashMap<Integer, QueueConsumer<?>>(); + private final ConcurrentMap<Integer, QueueConsumer<?>> _groupMap = new ConcurrentHashMap<Integer, QueueConsumer<?>>(); private final int _groupMask; public AssignedConsumerMessageGroupManager(final String groupId, final int maxGroups) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/LastValueQueueList.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/LastValueQueueList.java index 6f1edf12e5..1e250ac2c9 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/LastValueQueueList.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/LastValueQueueList.java @@ -24,6 +24,7 @@ package org.apache.qpid.server.queue; import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicReference; import org.slf4j.Logger; @@ -48,7 +49,7 @@ public class LastValueQueueList extends OrderedQueueEntryList }; private final String _conflationKey; - private final ConcurrentHashMap<Object, AtomicReference<ConflationQueueEntry>> _latestValuesMap = + private final ConcurrentMap<Object, AtomicReference<ConflationQueueEntry>> _latestValuesMap = new ConcurrentHashMap<Object, AtomicReference<ConflationQueueEntry>>(); private final ConflationQueueEntry _deleteInProgress = new ConflationQueueEntry(this); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SecurityManager.java index 2f7acba91d..96bd9ee0d6 100755 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SecurityManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SecurityManager.java @@ -35,6 +35,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import javax.security.auth.Subject; @@ -63,11 +64,11 @@ public class SecurityManager implements ConfigurationChangeListener Collections.emptySet(), Collections.emptySet()); - private final ConcurrentHashMap<String, AccessControl> _plugins = new ConcurrentHashMap<String, AccessControl>(); + private final ConcurrentMap<String, AccessControl> _plugins = new ConcurrentHashMap<String, AccessControl>(); private final boolean _managementMode; private final Broker<?> _broker; - private final ConcurrentHashMap<PublishAccessCheckCacheEntry, PublishAccessCheck> _publishAccessCheckCache = new ConcurrentHashMap<SecurityManager.PublishAccessCheckCacheEntry, SecurityManager.PublishAccessCheck>(); + private final ConcurrentMap<PublishAccessCheckCacheEntry, PublishAccessCheck> _publishAccessCheckCache = new ConcurrentHashMap<SecurityManager.PublishAccessCheckCacheEntry, SecurityManager.PublishAccessCheck>(); public SecurityManager(Broker<?> broker, boolean managementMode) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypter.java new file mode 100644 index 0000000000..c0c92f0389 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypter.java @@ -0,0 +1,130 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.qpid.server.security.encryption; + + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.xml.bind.DatatypeConverter; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; + +class AESKeyFileEncrypter implements ConfigurationSecretEncrypter +{ + private static final String CIPHER_NAME = "AES/CBC/PKCS5Padding"; + private static final int AES_INITIALIZATION_VECTOR_LENGTH = 16; + private final SecretKey _secretKey; + private final SecureRandom _random = new SecureRandom(); + + AESKeyFileEncrypter(SecretKey secretKey) + { + _secretKey = secretKey; + } + + @Override + public String encrypt(final String unencrypted) + { + byte[] unencryptedBytes = unencrypted.getBytes(StandardCharsets.UTF_8); + try + { + byte[] ivbytes = new byte[AES_INITIALIZATION_VECTOR_LENGTH]; + _random.nextBytes(ivbytes); + Cipher cipher = Cipher.getInstance(CIPHER_NAME); + cipher.init(Cipher.ENCRYPT_MODE, _secretKey, new IvParameterSpec(ivbytes)); + byte[] encryptedBytes = readFromCipherStream(unencryptedBytes, cipher); + byte[] output = new byte[AES_INITIALIZATION_VECTOR_LENGTH + encryptedBytes.length]; + System.arraycopy(ivbytes, 0, output, 0, AES_INITIALIZATION_VECTOR_LENGTH); + System.arraycopy(encryptedBytes, 0, output, AES_INITIALIZATION_VECTOR_LENGTH, encryptedBytes.length); + return DatatypeConverter.printBase64Binary(output); + } + catch (IOException | InvalidAlgorithmParameterException | InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException e) + { + throw new IllegalConfigurationException("Unable to encrypt secret", e); + } + } + + @Override + public String decrypt(final String encrypted) + { + byte[] encryptedBytes = DatatypeConverter.parseBase64Binary(encrypted); + try + { + Cipher cipher = Cipher.getInstance(CIPHER_NAME); + cipher.init(Cipher.DECRYPT_MODE, _secretKey, new IvParameterSpec(encryptedBytes, 0, + AES_INITIALIZATION_VECTOR_LENGTH)); + return new String(readFromCipherStream(encryptedBytes, + AES_INITIALIZATION_VECTOR_LENGTH, + encryptedBytes.length - AES_INITIALIZATION_VECTOR_LENGTH, + cipher), StandardCharsets.UTF_8); + } + catch (IOException | InvalidAlgorithmParameterException | InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException e) + { + throw new IllegalConfigurationException("Unable to encrypt secret", e); + } + } + + + private byte[] readFromCipherStream(final byte[] unencryptedBytes, final Cipher cipher) throws IOException + { + return readFromCipherStream(unencryptedBytes, 0, unencryptedBytes.length, cipher); + } + + private byte[] readFromCipherStream(final byte[] unencryptedBytes, int offset, int length, final Cipher cipher) + throws IOException + { + final byte[] encryptedBytes; + try (CipherInputStream cipherInputStream = new CipherInputStream(new ByteArrayInputStream(unencryptedBytes, + offset, + length), cipher)) + { + byte[] buf = new byte[1024]; + int pos = 0; + int read; + while ((read = cipherInputStream.read(buf, pos, buf.length - pos)) != -1) + { + pos += read; + if (pos == buf.length - 1) + { + byte[] tmp = buf; + buf = new byte[buf.length + 1024]; + System.arraycopy(tmp, 0, buf, 0, tmp.length); + } + } + encryptedBytes = new byte[pos]; + System.arraycopy(buf, 0, encryptedBytes, 0, pos); + } + return encryptedBytes; + } + + + +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java new file mode 100644 index 0000000000..447f19b7ce --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java @@ -0,0 +1,164 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.qpid.server.security.encryption; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.security.NoSuchAlgorithmException; +import java.util.EnumSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.qpid.server.BrokerOptions; +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.plugin.ConfigurationSecretEncrypterFactory; +import org.apache.qpid.server.plugin.PluggableService; + +@PluggableService +public class AESKeyFileEncrypterFactory implements ConfigurationSecretEncrypterFactory +{ + private static final String ENCRYPTER_KEY_FILE = "encrypter.key.file"; + + private static final int AES_KEY_SIZE_BITS = 256; + private static final int AES_KEY_SIZE_BYTES = AES_KEY_SIZE_BITS / 8; + private static final String AES_ALGORITHM = "AES"; + + public static String TYPE = "AESKeyFile"; + + @Override + public ConfigurationSecretEncrypter createEncrypter(final ConfiguredObject<?> object) + { + String fileLocation; + if(object.getContextKeys(false).contains(ENCRYPTER_KEY_FILE)) + { + fileLocation = object.getContextValue(String.class, ENCRYPTER_KEY_FILE); + } + else + { + + fileLocation = object.getContextValue(String.class, BrokerOptions.QPID_WORK_DIR) + + File.separator + ".keys" + File.separator + + object.getCategoryClass().getSimpleName() + "_" + + object.getName() + ".key"; + + Map<String, String> context = object.getContext(); + Map<String, String> modifiedContext = new LinkedHashMap<>(context); + modifiedContext.put(ENCRYPTER_KEY_FILE, fileLocation); + + object.setAttribute(ConfiguredObject.CONTEXT, context, modifiedContext); + } + File file = new File(fileLocation); + if(!file.exists()) + { + createAndPopulateKeyFile(file); + } + if(!file.isFile()) + { + throw new IllegalArgumentException("File '"+fileLocation+"' is not a regular file."); + } + try + { + Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(file.toPath()); + + if (permissions.contains(PosixFilePermission.GROUP_READ) + || permissions.contains(PosixFilePermission.OTHERS_READ) + || permissions.contains(PosixFilePermission.GROUP_WRITE) + || permissions.contains(PosixFilePermission.OTHERS_WRITE)) + { + throw new IllegalStateException("Key file '" + + fileLocation + + "' has incorrect permissions. Only the owner " + + "should be able to read or write this file."); + } + if(Files.size(file.toPath()) != AES_KEY_SIZE_BYTES) + { + throw new IllegalConfigurationException("Key file '" + fileLocation + "' contains an incorrect about of data"); + } + + try(FileInputStream inputStream = new FileInputStream(file)) + { + byte[] key = new byte[AES_KEY_SIZE_BYTES]; + int pos = 0; + int read; + while(pos < key.length && -1 != ( read = inputStream.read(key, pos, key.length - pos))) + { + pos += read; + } + if(pos != key.length) + { + throw new IllegalConfigurationException("Key file '" + fileLocation + "' contained an incorrect about of data"); + } + SecretKeySpec keySpec = new SecretKeySpec(key, AES_ALGORITHM); + return new AESKeyFileEncrypter(keySpec); + } + } + catch (IOException e) + { + throw new IllegalConfigurationException("Unable to get file permissions: " + e.getMessage(), e); + } + } + + private void createAndPopulateKeyFile(final File file) + { + try + { + Set<PosixFilePermission> ownerOnly = EnumSet.of(PosixFilePermission.OWNER_READ, + PosixFilePermission.OWNER_WRITE, + PosixFilePermission.OWNER_EXECUTE); + Files.createDirectories(file.getParentFile().toPath(), PosixFilePermissions.asFileAttribute(ownerOnly)); + + Files.createFile(file.toPath(), PosixFilePermissions.asFileAttribute( + EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); + + KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_ALGORITHM); + keyGenerator.init(AES_KEY_SIZE_BITS); + SecretKey key = keyGenerator.generateKey(); + try(FileOutputStream os = new FileOutputStream(file)) + { + os.write(key.getEncoded()); + } + + Files.setPosixFilePermissions(file.toPath(), EnumSet.of(PosixFilePermission.OWNER_READ)); + } + catch (NoSuchAlgorithmException | IOException e) + { + throw new IllegalConfigurationException("Cannot create key file: " + e.getMessage(), e); + } + + } + + @Override + public String getType() + { + return TYPE; + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/ConfigurationSecretEncrypter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/ConfigurationSecretEncrypter.java new file mode 100644 index 0000000000..d8c64c789c --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/ConfigurationSecretEncrypter.java @@ -0,0 +1,28 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.qpid.server.security.encryption; + +public interface ConfigurationSecretEncrypter +{ + String encrypt(String unencrypted); + + String decrypt(String encrypted); +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/AbstractMemoryStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/AbstractMemoryStore.java index 4d5cb84d04..a9af138a02 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/AbstractMemoryStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/AbstractMemoryStore.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.store.handler.ConfiguredObjectRecordHandler; @@ -34,7 +35,7 @@ public abstract class AbstractMemoryStore implements DurableConfigurationStore, private final Class<? extends ConfiguredObject> _rootClass; - private final ConcurrentHashMap<UUID, ConfiguredObjectRecord> _configuredObjectRecords = new ConcurrentHashMap<UUID, ConfiguredObjectRecord>(); + private final ConcurrentMap<UUID, ConfiguredObjectRecord> _configuredObjectRecords = new ConcurrentHashMap<UUID, ConfiguredObjectRecord>(); protected AbstractMemoryStore(final Class<? extends ConfiguredObject> rootClass) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/GenericRecoverer.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/GenericRecoverer.java index 58fa852849..9edc5fd30a 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/GenericRecoverer.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/GenericRecoverer.java @@ -170,6 +170,7 @@ public class GenericRecoverer { updatesMade = true; ConfiguredObject<?> resolved = recovered.resolve(); + resolved.decryptSecrets(); resolvedObjects.put(resolved.getId(), resolved); } else diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index f3b2cac52e..9c0a5118ff 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; import org.apache.qpid.server.message.EnqueueableMessage; @@ -41,7 +42,7 @@ public class MemoryMessageStore implements MessageStore private final AtomicLong _messageId = new AtomicLong(1); - private final ConcurrentHashMap<Long, StoredMemoryMessage> _messages = new ConcurrentHashMap<Long, StoredMemoryMessage>(); + private final ConcurrentMap<Long, StoredMemoryMessage> _messages = new ConcurrentHashMap<Long, StoredMemoryMessage>(); private final Object _transactionLock = new Object(); private final Map<UUID, Set<Long>> _messageInstances = new HashMap<UUID, Set<Long>>(); private final Map<Xid, DistributedTransactionRecords> _distributedTransactions = new HashMap<Xid, DistributedTransactionRecords>(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/MessageMetaDataTypeRegistry.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/MessageMetaDataTypeRegistry.java index 64f3ab15ee..940abf42f4 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/MessageMetaDataTypeRegistry.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/MessageMetaDataTypeRegistry.java @@ -32,7 +32,7 @@ public class MessageMetaDataTypeRegistry int maxOrdinal = -1; Iterable<MessageMetaDataType> messageMetaDataTypes = - new QpidServiceLoader<MessageMetaDataType>().atLeastOneInstanceOf(MessageMetaDataType.class); + new QpidServiceLoader().atLeastOneInstanceOf(MessageMetaDataType.class); for(MessageMetaDataType type : messageMetaDataTypes) { @@ -42,7 +42,7 @@ public class MessageMetaDataTypeRegistry } } values = new MessageMetaDataType[maxOrdinal+1]; - for(MessageMetaDataType type : new QpidServiceLoader<MessageMetaDataType>().instancesOf(MessageMetaDataType.class)) + for(MessageMetaDataType type : new QpidServiceLoader().instancesOf(MessageMetaDataType.class)) { if(values[type.ordinal()] != null) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java index b72d44debf..450fc30bf2 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java @@ -272,7 +272,7 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte private void registerSystemNodes() { - QpidServiceLoader<SystemNodeCreator> qpidServiceLoader = new QpidServiceLoader<SystemNodeCreator>(); + QpidServiceLoader qpidServiceLoader = new QpidServiceLoader(); Iterable<SystemNodeCreator> factories = qpidServiceLoader.instancesOf(SystemNodeCreator.class); for(SystemNodeCreator creator : factories) { |