summaryrefslogtreecommitdiff
path: root/qpid/java/broker/src/main
diff options
context:
space:
mode:
authorRobert Gemmell <robbie@apache.org>2013-04-12 16:16:09 +0000
committerRobert Gemmell <robbie@apache.org>2013-04-12 16:16:09 +0000
commit249369d22526b77b3ffa4c456854b55c287cfd7b (patch)
treed3706c9c525d196e824d1fdd51873ec275295eae /qpid/java/broker/src/main
parent332410c66c62d5e075e9f9077d29fc4669e11db0 (diff)
downloadqpid-python-249369d22526b77b3ffa4c456854b55c287cfd7b.tar.gz
QPID-4739: complete support for defining multiple key/trust stores and assigning them on a port-specific basis
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1467334 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java/broker/src/main')
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java68
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java32
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/KeyStore.java22
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/Port.java10
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/TrustStore.java8
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java49
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractKeyStoreAdapter.java51
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AmqpPortAdapter.java14
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java291
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/KeyStoreAdapter.java175
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java85
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortFactory.java14
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/TrustStoreAdapter.java151
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/util/MapValueConverter.java6
14 files changed, 652 insertions, 324 deletions
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java
index 0d7be75a0b..4fc0a37c3e 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java
@@ -1,23 +1,28 @@
package org.apache.qpid.server.configuration.startup;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.apache.qpid.server.configuration.ConfigurationEntry;
import org.apache.qpid.server.configuration.ConfiguredObjectRecoverer;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.configuration.RecovererProvider;
+import org.apache.qpid.server.configuration.store.StoreConfigurationChangeListener;
+import org.apache.qpid.server.configuration.updater.TaskExecutor;
import org.apache.qpid.server.logging.LogRecorder;
import org.apache.qpid.server.logging.RootMessageLogger;
import org.apache.qpid.server.model.AuthenticationProvider;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.KeyStore;
import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.TrustStore;
import org.apache.qpid.server.model.adapter.AuthenticationProviderFactory;
import org.apache.qpid.server.model.adapter.BrokerAdapter;
import org.apache.qpid.server.model.adapter.PortFactory;
-import org.apache.qpid.server.configuration.store.StoreConfigurationChangeListener;
-import org.apache.qpid.server.configuration.updater.TaskExecutor;
import org.apache.qpid.server.stats.StatisticsGatherer;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
@@ -52,31 +57,62 @@ public class BrokerRecoverer implements ConfiguredObjectRecoverer<Broker>
_logRecorder, _rootMessageLogger, _authenticationProviderFactory, _portFactory, _taskExecutor, entry.getStore());
broker.addChangeListener(storeChangeListener);
- Map<String, Collection<ConfigurationEntry>> childEntries = entry.getChildren();
- for (String type : childEntries.keySet())
+
+ //Recover the SSL keystores / truststores first, then others that depend on them
+ Map<String, Collection<ConfigurationEntry>> childEntries = new HashMap<String, Collection<ConfigurationEntry>>(entry.getChildren());
+ Map<String, Collection<ConfigurationEntry>> sslChildEntries = new HashMap<String, Collection<ConfigurationEntry>>(childEntries);
+ List<String> types = new ArrayList<String>(childEntries.keySet());
+
+ for(String type : types)
{
- ConfiguredObjectRecoverer<?> recoverer = recovererProvider.getRecoverer(type);
- if (recoverer == null)
+ if(KeyStore.class.getSimpleName().equals(type) || TrustStore.class.getSimpleName().equals(type))
{
- throw new IllegalConfigurationException("Cannot recover entry for the type '" + type + "' from broker");
+ childEntries.remove(type);
}
- Collection<ConfigurationEntry> entries = childEntries.get(type);
- for (ConfigurationEntry childEntry : entries)
+ else
{
- ConfiguredObject object = recoverer.create(recovererProvider, childEntry, broker);
- if (object == null)
- {
- throw new IllegalConfigurationException("Cannot create configured object for the entry " + childEntry);
- }
- broker.recoverChild(object);
- object.addChangeListener(storeChangeListener);
+ sslChildEntries.remove(type);
}
}
+
+ for (String type : sslChildEntries.keySet())
+ {
+ recoverType(recovererProvider, storeChangeListener, broker, sslChildEntries, type);
+ }
+ for (String type : childEntries.keySet())
+ {
+ recoverType(recovererProvider, storeChangeListener, broker, childEntries, type);
+ }
+
wireUpConfiguredObjects(broker, entry.getAttributes());
return broker;
}
+ private void recoverType(RecovererProvider recovererProvider,
+ StoreConfigurationChangeListener storeChangeListener,
+ BrokerAdapter broker,
+ Map<String, Collection<ConfigurationEntry>> childEntries,
+ String type)
+ {
+ ConfiguredObjectRecoverer<?> recoverer = recovererProvider.getRecoverer(type);
+ if (recoverer == null)
+ {
+ throw new IllegalConfigurationException("Cannot recover entry for the type '" + type + "' from broker");
+ }
+ Collection<ConfigurationEntry> entries = childEntries.get(type);
+ for (ConfigurationEntry childEntry : entries)
+ {
+ ConfiguredObject object = recoverer.create(recovererProvider, childEntry, broker);
+ if (object == null)
+ {
+ throw new IllegalConfigurationException("Cannot create configured object for the entry " + childEntry);
+ }
+ broker.recoverChild(object);
+ object.addChangeListener(storeChangeListener);
+ }
+ }
+
private void wireUpConfiguredObjects(BrokerAdapter broker, Map<String, Object> brokerAttributes)
{
AuthenticationProvider defaultAuthenticationProvider = null;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java
index ad0e68cee6..0e230bd552 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java
@@ -88,18 +88,6 @@ public interface Broker extends ConfiguredObject
String ACL_FILE = "aclFile";
/*
- * A temporary attributes to set the broker default key/trust stores.
- * TODO: Remove them after adding a full support to configure KeyStore/TrustStore via management layers.
- */
- String KEY_STORE_PATH = "keyStorePath";
- String KEY_STORE_PASSWORD = "keyStorePassword";
- String KEY_STORE_CERT_ALIAS = "keyStoreCertAlias";
- String TRUST_STORE_PATH = "trustStorePath";
- String TRUST_STORE_PASSWORD = "trustStorePassword";
- String PEER_STORE_PATH = "peerStorePath";
- String PEER_STORE_PASSWORD = "peerStorePassword";
-
- /*
* A temporary attributes to set the broker group file.
* TODO: Remove them after adding a full support to configure authorization providers via management layers.
*/
@@ -148,16 +136,8 @@ public interface Broker extends ConfiguredObject
VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_WARN,
VIRTUALHOST_STORE_TRANSACTION_OPEN_TIMEOUT_CLOSE,
VIRTUALHOST_STORE_TRANSACTION_OPEN_TIMEOUT_WARN,
-
- ACL_FILE,
- KEY_STORE_PATH,
- KEY_STORE_PASSWORD,
- KEY_STORE_CERT_ALIAS,
- TRUST_STORE_PATH,
- TRUST_STORE_PASSWORD,
- PEER_STORE_PATH,
- PEER_STORE_PASSWORD,
- GROUP_FILE
+ GROUP_FILE,
+ ACL_FILE
));
//children
@@ -194,6 +174,10 @@ public interface Broker extends ConfiguredObject
VirtualHost findVirtualHostByName(String name);
+ KeyStore findKeyStoreByName(String name);
+
+ TrustStore findTrustStoreByName(String name);
+
/**
* Get the SubjectCreator for the given socket address.
* TODO: move the authentication related functionality into host aliases and AuthenticationProviders
@@ -211,10 +195,6 @@ public interface Broker extends ConfiguredObject
*/
VirtualHostRegistry getVirtualHostRegistry();
- KeyStore getDefaultKeyStore();
-
- TrustStore getDefaultTrustStore();
-
TaskExecutor getTaskExecutor();
boolean isManagementMode();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/KeyStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/KeyStore.java
index 959714656b..74a7469ffb 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/KeyStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/KeyStore.java
@@ -24,10 +24,23 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-public interface KeyStore extends TrustStore
+public interface KeyStore extends ConfiguredObject
{
+ String ID = "id";
+ String NAME = "name";
+ String DURABLE = "durable";
+ String LIFETIME_POLICY = "lifetimePolicy";
+ String STATE = "state";
+ String TIME_TO_LIVE = "timeToLive";
+ String CREATED = "created";
+ String UPDATED = "updated";
+ String DESCRIPTION = "description";
+ String PATH = "path";
+ String PASSWORD = "password";
+ String TYPE = "type";
String CERTIFICATE_ALIAS = "certificateAlias";
+ String KEY_MANAGER_FACTORY_ALGORITHM = "keyManagerFactoryAlgorithm";
public static final Collection<String> AVAILABLE_ATTRIBUTES =
Collections.unmodifiableList(
@@ -44,8 +57,11 @@ public interface KeyStore extends TrustStore
PATH,
PASSWORD,
TYPE,
- KEY_MANAGER_FACTORY_ALGORITHM,
- CERTIFICATE_ALIAS
+ CERTIFICATE_ALIAS,
+ KEY_MANAGER_FACTORY_ALGORITHM
));
+ public String getPassword();
+
+ public void setPassword(String password);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Port.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Port.java
index 33ba34767d..7ff5f04ee7 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Port.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Port.java
@@ -45,6 +45,8 @@ public interface Port extends ConfiguredObject
String NEED_CLIENT_AUTH = "needClientAuth";
String WANT_CLIENT_AUTH = "wantClientAuth";
String AUTHENTICATION_PROVIDER = "authenticationProvider";
+ String KEY_STORE = "keyStore";
+ String TRUST_STORES = "trustStores";
// Attributes
public static final Collection<String> AVAILABLE_ATTRIBUTES =
@@ -67,7 +69,9 @@ public interface Port extends ConfiguredObject
RECEIVE_BUFFER_SIZE,
NEED_CLIENT_AUTH,
WANT_CLIENT_AUTH,
- AUTHENTICATION_PROVIDER
+ AUTHENTICATION_PROVIDER,
+ KEY_STORE,
+ TRUST_STORES
));
@@ -75,6 +79,10 @@ public interface Port extends ConfiguredObject
int getPort();
+ KeyStore getKeyStore();
+
+ Collection<TrustStore> getTrustStores();
+
Collection<Transport> getTransports();
void addTransport(Transport transport) throws IllegalStateException,
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/TrustStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/TrustStore.java
index 53498ab431..c686e7bd50 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/TrustStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/TrustStore.java
@@ -38,9 +38,9 @@ public interface TrustStore extends ConfiguredObject
String PATH = "path";
String PASSWORD = "password";
- String PEERS_ONLY = "peersOnly";
String TYPE = "type";
- String KEY_MANAGER_FACTORY_ALGORITHM = "keyManagerFactoryAlgorithm";
+ String PEERS_ONLY = "peersOnly";
+ String TRUST_MANAGER_FACTORY_ALGORITHM = "trustManagerFactoryAlgorithm";
public static final Collection<String> AVAILABLE_ATTRIBUTES =
Collections.unmodifiableList(
@@ -56,9 +56,9 @@ public interface TrustStore extends ConfiguredObject
DESCRIPTION,
PATH,
PASSWORD,
- PEERS_ONLY,
TYPE,
- KEY_MANAGER_FACTORY_ALGORITHM
+ PEERS_ONLY,
+ TRUST_MANAGER_FACTORY_ALGORITHM
));
public String getPassword();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java
index 20929a337a..51fd3a5c78 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java
@@ -63,6 +63,7 @@ abstract class AbstractAdapter implements ConfiguredObject
{
if (attributes.containsKey(name))
{
+ //TODO: dont put nulls
_attributes.put(name, attributes.get(name));
}
}
@@ -254,6 +255,7 @@ abstract class AbstractAdapter implements ConfiguredObject
if((currentValue == null && expected == null)
|| (currentValue != null && currentValue.equals(expected)))
{
+ //TODO: dont put nulls
_attributes.put(name, desired);
return true;
}
@@ -397,4 +399,51 @@ abstract class AbstractAdapter implements ConfiguredObject
{
return _defaultAttributes;
}
+
+ /**
+ * Returns a map of effective attribute values that would result
+ * if applying the supplied changes. Does not apply the changes.
+ */
+ protected Map<String, Object> generateEffectiveAttributes(Map<String,Object> changedValues)
+ {
+ //Build a new set of effective attributes that would be
+ //the result of applying the attribute changes, so we
+ //can validate the configuration that would result
+
+ Map<String, Object> defaultValues = getDefaultAttributes();
+ Map<String, Object> existingActualValues = getActualAttributes();
+
+ //create a new merged map, starting with the defaults
+ Map<String, Object> merged = new HashMap<String, Object>(defaultValues);
+
+ for(String name : getAttributeNames())
+ {
+ if(changedValues.containsKey(name))
+ {
+ Object changedValue = changedValues.get(name);
+ if(changedValue != null)
+ {
+ //use the new non-null value for the merged values
+ merged.put(name, changedValue);
+ }
+ else
+ {
+ //we just use the default (if there was one) since the changed
+ //value is null and effectively clears any existing actual value
+ }
+ }
+ else if(existingActualValues.get(name) != null)
+ {
+ //Use existing non-null actual value for the merge
+ merged.put(name, existingActualValues.get(name));
+ }
+ else
+ {
+ //There was neither a change or an existing non-null actual
+ //value, so just use the default value (if there was one).
+ }
+ }
+
+ return merged;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractKeyStoreAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractKeyStoreAdapter.java
index 80196c395e..707cf8076d 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractKeyStoreAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractKeyStoreAdapter.java
@@ -37,20 +37,21 @@ import org.apache.qpid.server.util.MapValueConverter;
public abstract class AbstractKeyStoreAdapter extends AbstractAdapter
{
+ public static final String DUMMY_PASSWORD_MASK = "********";
+ public static final String DEFAULT_KEYSTORE_TYPE = java.security.KeyStore.getDefaultType();
+
private String _name;
private String _password;
- protected AbstractKeyStoreAdapter(UUID id, Broker broker, Map<String, Object> attributes)
+ protected AbstractKeyStoreAdapter(UUID id, Broker broker, Map<String, Object> defaults,
+ Map<String, Object> attributes)
{
- super(id, broker.getTaskExecutor());
+ super(id, defaults, attributes, broker.getTaskExecutor());
addParent(Broker.class, broker);
+
_name = MapValueConverter.getStringAttribute(TrustStore.NAME, attributes);
_password = MapValueConverter.getStringAttribute(TrustStore.PASSWORD, attributes);
- setMandatoryAttribute(TrustStore.PATH, attributes);
- setOptionalAttribute(TrustStore.PEERS_ONLY, attributes);
- setOptionalAttribute(TrustStore.TYPE, attributes);
- setOptionalAttribute(TrustStore.KEY_MANAGER_FACTORY_ALGORITHM, attributes);
- setOptionalAttribute(TrustStore.DESCRIPTION, attributes);
+ MapValueConverter.assertMandatoryAttribute(KeyStore.PATH, attributes);
}
@Override
@@ -163,15 +164,16 @@ public abstract class AbstractKeyStoreAdapter extends AbstractAdapter
}
else if(KeyStore.PASSWORD.equals(name))
{
- return null; // for security reasons we don't expose the password
+ // For security reasons we don't expose the password
+ if (getPassword() != null)
+ {
+ return DUMMY_PASSWORD_MASK;
+ }
+
+ return null;
}
- return super.getAttribute(name);
- }
- @Override
- protected boolean setState(State currentState, State desiredState)
- {
- return false;
+ return super.getAttribute(name);
}
public String getPassword()
@@ -183,25 +185,4 @@ public abstract class AbstractKeyStoreAdapter extends AbstractAdapter
{
_password = password;
}
-
- private void setMandatoryAttribute(String name, Map<String, Object> attributeValues)
- {
- changeAttribute(name, null, MapValueConverter.getStringAttribute(name, attributeValues));
- }
-
- private void setOptionalAttribute(String name, Map<String, Object> attributeValues)
- {
- Object attrValue = attributeValues.get(name);
- if (attrValue != null)
- {
- if (attrValue instanceof Boolean)
- {
- changeAttribute(name, null, MapValueConverter.getBooleanAttribute(name, attributeValues));
- }
- else
- {
- changeAttribute(name, null, MapValueConverter.getStringAttribute(name, attributeValues));
- }
- }
- }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AmqpPortAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AmqpPortAdapter.java
index e7057f89d3..71f5397d2b 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AmqpPortAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AmqpPortAdapter.java
@@ -133,15 +133,11 @@ public class AmqpPortAdapter extends PortAdapter
private SSLContext createSslContext()
{
- KeyStore keyStore = _broker.getDefaultKeyStore();
- if (keyStore == null)
- {
- throw new IllegalConfigurationException("SSL was requested on AMQP port '"
- + this.getName() + "' but no key store defined");
- }
+ KeyStore keyStore = getKeyStore();
- Collection<TrustStore> trustStores = _broker.getTrustStores();
- if (((Boolean)getAttribute(NEED_CLIENT_AUTH) || (Boolean)getAttribute(WANT_CLIENT_AUTH)) && trustStores.isEmpty())
+ Collection<TrustStore> trustStores = getTrustStores();
+ boolean needClientCert = (Boolean)getAttribute(NEED_CLIENT_AUTH) || (Boolean)getAttribute(WANT_CLIENT_AUTH);
+ if (needClientCert && trustStores.isEmpty())
{
throw new IllegalConfigurationException("Client certificate authentication is enabled on AMQP port '"
+ this.getName() + "' but no trust store defined");
@@ -165,7 +161,7 @@ public class AmqpPortAdapter extends PortAdapter
trustStore.getPassword(),
(String)trustStore.getAttribute(TrustStore.TYPE),
(Boolean) trustStore.getAttribute(TrustStore.PEERS_ONLY),
- (String)trustStore.getAttribute(TrustStore.KEY_MANAGER_FACTORY_ALGORITHM)));
+ (String)trustStore.getAttribute(TrustStore.TRUST_MANAGER_FACTORY_ALGORITHM)));
}
sslContext = SSLContextFactory.buildClientContext(trstWrappers, keystorePath,
keystorePassword, keystoreType,
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
index e968d91e79..ae30f70877 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
@@ -24,7 +24,6 @@ import java.lang.reflect.Type;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.security.AccessControlException;
-import java.security.KeyStoreException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -32,13 +31,12 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
-import javax.net.ssl.KeyManagerFactory;
-import java.security.cert.Certificate;
-
import org.apache.log4j.Logger;
import org.apache.qpid.common.QpidProperties;
import org.apache.qpid.server.configuration.ConfigurationEntryStore;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.configuration.store.ManagementModeStoreHandler;
+import org.apache.qpid.server.configuration.updater.TaskExecutor;
import org.apache.qpid.server.logging.LogRecorder;
import org.apache.qpid.server.logging.RootMessageLogger;
import org.apache.qpid.server.logging.actors.BrokerActor;
@@ -58,22 +56,18 @@ import org.apache.qpid.server.model.Statistics;
import org.apache.qpid.server.model.TrustStore;
import org.apache.qpid.server.model.UUIDGenerator;
import org.apache.qpid.server.model.VirtualHost;
-import org.apache.qpid.server.configuration.store.ManagementModeStoreHandler;
-import org.apache.qpid.server.configuration.updater.TaskExecutor;
+import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.security.access.Operation;
import org.apache.qpid.server.security.group.FileGroupManager;
import org.apache.qpid.server.security.group.GroupManager;
-import org.apache.qpid.server.security.SecurityManager;
-import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.stats.StatisticsGatherer;
import org.apache.qpid.server.store.MessageStoreCreator;
import org.apache.qpid.server.util.MapValueConverter;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
-import org.apache.qpid.transport.network.security.ssl.SSLUtil;
public class BrokerAdapter extends AbstractAdapter implements Broker, ConfigurationChangeListener
{
-
private static final Logger LOGGER = Logger.getLogger(BrokerAdapter.class);
@SuppressWarnings("serial")
@@ -100,13 +94,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
put(DEFAULT_VIRTUAL_HOST, String.class);
put(DEFAULT_AUTHENTICATION_PROVIDER, String.class);
- put(KEY_STORE_PATH, String.class);
- put(KEY_STORE_PASSWORD, String.class);
- put(KEY_STORE_CERT_ALIAS, String.class);
- put(TRUST_STORE_PATH, String.class);
- put(TRUST_STORE_PASSWORD, String.class);
- put(PEER_STORE_PATH, String.class);
- put(PEER_STORE_PASSWORD, String.class);
put(GROUP_FILE, String.class);
put(VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_CLOSE, Long.class);
put(VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_WARN, Long.class);
@@ -133,12 +120,7 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
public static final long DEFAULT_STORE_TRANSACTION_IDLE_TIMEOUT_WARN = 0l;
public static final long DEFAULT_STORE_TRANSACTION_OPEN_TIMEOUT_CLOSE = 0l;
public static final long DEFAULT_STORE_TRANSACTION_OPEN_TIMEOUT_WARN = 0l;
- private static final String DEFAULT_KEY_STORE_NAME = "defaultKeyStore";
- private static final String DEFAULT_TRUST_STORE_NAME = "defaultTrustStore";
private static final String DEFAULT_GROUP_PROVIDER_NAME = "defaultGroupProvider";
- private static final String DEFAULT_PEER_STORE_NAME = "defaultPeerStore";
-
- private static final String DUMMY_PASSWORD_MASK = "********";
@SuppressWarnings("serial")
private static final Map<String, Object> DEFAULTS = Collections.unmodifiableMap(new HashMap<String, Object>(){{
@@ -182,16 +164,14 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
private final Map<UUID, AuthenticationProvider> _authenticationProviders = new HashMap<UUID, AuthenticationProvider>();
private final Map<String, GroupProvider> _groupProviders = new HashMap<String, GroupProvider>();
private final Map<UUID, ConfiguredObject> _plugins = new HashMap<UUID, ConfiguredObject>();
- private final Map<UUID, KeyStore> _keyStores = new HashMap<UUID, KeyStore>();
- private final Map<UUID, TrustStore> _trustStores = new HashMap<UUID, TrustStore>();
+ private final Map<String, KeyStore> _keyStores = new HashMap<String, KeyStore>();
+ private final Map<String, TrustStore> _trustStores = new HashMap<String, TrustStore>();
private final AuthenticationProviderFactory _authenticationProviderFactory;
private AuthenticationProvider _defaultAuthenticationProvider;
private final PortFactory _portFactory;
private final SecurityManager _securityManager;
- private final UUID _defaultKeyStoreId;
- private final UUID _defaultTrustStoreId;
private final Collection<String> _supportedStoreTypes;
private final ConfigurationEntryStore _brokerStore;
@@ -212,8 +192,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
_portFactory = portFactory;
_securityManager = new SecurityManager((String)getAttribute(ACL_FILE));
addChangeListener(_securityManager);
- _defaultKeyStoreId = UUIDGenerator.generateBrokerChildUUID(KeyStore.class.getSimpleName(), DEFAULT_KEY_STORE_NAME);
- _defaultTrustStoreId = UUIDGenerator.generateBrokerChildUUID(TrustStore.class.getSimpleName(), DEFAULT_TRUST_STORE_NAME);
createBrokerChildrenFromAttributes();
_supportedStoreTypes = new MessageStoreCreator().getStoreTypes();
_brokerStore = brokerStore;
@@ -226,9 +204,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
private void createBrokerChildrenFromAttributes()
{
createGroupProvider();
- createKeyStore();
- createTrustStore();
- createPeerStore();
}
private void createGroupProvider()
@@ -248,80 +223,12 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
}
}
- private void createKeyStore()
- {
- Map<String, Object> actualAttributes = getActualAttributes();
- String keyStorePath = (String) getAttribute(KEY_STORE_PATH);
- if (keyStorePath != null)
- {
- Map<String, Object> keyStoreAttributes = new HashMap<String, Object>();
- keyStoreAttributes.put(KeyStore.NAME, DEFAULT_KEY_STORE_NAME);
- keyStoreAttributes.put(KeyStore.PATH, keyStorePath);
- keyStoreAttributes.put(KeyStore.PASSWORD, (String) actualAttributes.get(KEY_STORE_PASSWORD));
- keyStoreAttributes.put(KeyStore.TYPE, java.security.KeyStore.getDefaultType());
- keyStoreAttributes.put(KeyStore.CERTIFICATE_ALIAS, getAttribute(KEY_STORE_CERT_ALIAS));
- keyStoreAttributes.put(KeyStore.KEY_MANAGER_FACTORY_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm());
- KeyStoreAdapter keyStoreAdapter = new KeyStoreAdapter(_defaultKeyStoreId, this, keyStoreAttributes);
- _keyStores.put(keyStoreAdapter.getId(), keyStoreAdapter);
- }
- else
- {
- _keyStores.remove(_defaultKeyStoreId);
- }
- }
-
- private void createTrustStore()
- {
- Map<String, Object> actualAttributes = getActualAttributes();
- String trustStorePath = (String) getAttribute(TRUST_STORE_PATH);
- if (trustStorePath != null)
- {
- Map<String, Object> trsustStoreAttributes = new HashMap<String, Object>();
- trsustStoreAttributes.put(TrustStore.NAME, DEFAULT_TRUST_STORE_NAME);
- trsustStoreAttributes.put(TrustStore.PATH, trustStorePath);
- trsustStoreAttributes.put(TrustStore.PEERS_ONLY, Boolean.FALSE);
- trsustStoreAttributes.put(TrustStore.PASSWORD, (String) actualAttributes.get(TRUST_STORE_PASSWORD));
- trsustStoreAttributes.put(TrustStore.TYPE, java.security.KeyStore.getDefaultType());
- trsustStoreAttributes.put(TrustStore.KEY_MANAGER_FACTORY_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm());
- TrustStoreAdapter trustStore = new TrustStoreAdapter(_defaultTrustStoreId, this, trsustStoreAttributes);
- _trustStores.put(trustStore.getId(), trustStore);
- }
- else
- {
- _trustStores.remove(_defaultTrustStoreId);
- }
- }
-
- private void createPeerStore()
- {
- Map<String, Object> actualAttributes = getActualAttributes();
- String peerStorePath = (String) getAttribute(PEER_STORE_PATH);
- UUID peerStoreId = UUIDGenerator.generateBrokerChildUUID(TrustStore.class.getSimpleName(), DEFAULT_PEER_STORE_NAME);
- if (peerStorePath != null)
- {
- Map<String, Object> peerStoreAttributes = new HashMap<String, Object>();
- peerStoreAttributes.put(TrustStore.NAME, peerStoreId.toString());
- peerStoreAttributes.put(TrustStore.PATH, peerStorePath);
- peerStoreAttributes.put(TrustStore.PEERS_ONLY, Boolean.TRUE);
- peerStoreAttributes.put(TrustStore.PASSWORD, (String) actualAttributes.get(PEER_STORE_PASSWORD));
- peerStoreAttributes.put(TrustStore.TYPE, java.security.KeyStore.getDefaultType());
- peerStoreAttributes.put(TrustStore.KEY_MANAGER_FACTORY_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm());
- TrustStoreAdapter trustStore = new TrustStoreAdapter(peerStoreId, this, peerStoreAttributes);
- _trustStores.put(trustStore.getId(), trustStore);
- }
- else
- {
- _trustStores.remove(peerStoreId);
- }
- }
-
public Collection<VirtualHost> getVirtualHosts()
{
synchronized(_vhostAdapters)
{
return new ArrayList<VirtualHost>(_vhostAdapters.values());
}
-
}
public Collection<Port> getPorts()
@@ -354,6 +261,22 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
return null;
}
+ public KeyStore findKeyStoreByName(String keyStoreName)
+ {
+ synchronized(_keyStores)
+ {
+ return _keyStores.get(keyStoreName);
+ }
+ }
+
+ public TrustStore findTrustStoreByName(String trustStoreName)
+ {
+ synchronized(_trustStores)
+ {
+ return _trustStores.get(trustStoreName);
+ }
+ }
+
@Override
public AuthenticationProvider getDefaultAuthenticationProvider()
{
@@ -396,14 +319,14 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
// permission has already been granted to create the virtual host
// disable further access check on other operations, e.g. create exchange
- _securityManager.setAccessChecksDisabled(true);
+ SecurityManager.setAccessChecksDisabled(true);
try
{
virtualHostAdapter.setDesiredState(State.INITIALISING, State.ACTIVE);
}
finally
{
- _securityManager.setAccessChecksDisabled(false);
+ SecurityManager.setAccessChecksDisabled(false);
}
return virtualHostAdapter;
}
@@ -526,6 +449,14 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
{
return (C) createAuthenticationProvider(attributes);
}
+ else if(childClass == KeyStore.class)
+ {
+ return (C) createKeyStore(attributes);
+ }
+ else if(childClass == TrustStore.class)
+ {
+ return (C) createTrustStore(attributes);
+ }
else
{
throw new IllegalArgumentException("Cannot create child of class " + childClass.getSimpleName());
@@ -618,40 +549,76 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
throw new UnsupportedOperationException("Not implemented yet!");
}
+ private KeyStore createKeyStore(Map<String, Object> attributes)
+ {
+ KeyStore keyStore = new KeyStoreAdapter(UUIDGenerator.generateRandomUUID(), this, attributes);
+ addKeyStore(keyStore);
+
+ return keyStore;
+ }
+
+ private TrustStore createTrustStore(Map<String, Object> attributes)
+ {
+ TrustStore trustStore = new TrustStoreAdapter(UUIDGenerator.generateRandomUUID(), this, attributes);
+ addTrustStore(trustStore);
+
+ return trustStore;
+ }
+
private void addKeyStore(KeyStore keyStore)
{
synchronized (_keyStores)
{
- if(_keyStores.containsKey(keyStore.getId()))
+ if(_keyStores.containsKey(keyStore.getName()))
{
- throw new IllegalConfigurationException("Cannot add KeyStore because one with id " + keyStore.getId() + " already exists");
+ throw new IllegalConfigurationException("Can't add KeyStore because one with name " + keyStore.getName() + " already exists");
}
- _keyStores.put(keyStore.getId(), keyStore);
+ _keyStores.put(keyStore.getName(), keyStore);
}
keyStore.addChangeListener(this);
}
private boolean deleteKeyStore(KeyStore object)
{
- throw new UnsupportedOperationException("Not implemented yet!");
+ synchronized(_keyStores)
+ {
+ String name = object.getName();
+ KeyStore removedKeyStore = _keyStores.remove(name);
+ if(removedKeyStore != null)
+ {
+ removedKeyStore.removeChangeListener(this);
+ }
+
+ return removedKeyStore != null;
+ }
}
private void addTrustStore(TrustStore trustStore)
{
synchronized (_trustStores)
{
- if(_trustStores.containsKey(trustStore.getId()))
+ if(_trustStores.containsKey(trustStore.getName()))
{
- throw new IllegalConfigurationException("Cannot add TrustStore because one with id " + trustStore.getId() + " already exists");
+ throw new IllegalConfigurationException("Can't add TrustStore because one with name " + trustStore.getName() + " already exists");
}
- _trustStores.put(trustStore.getId(), trustStore);
+ _trustStores.put(trustStore.getName(), trustStore);
}
trustStore.addChangeListener(this);
}
private boolean deleteTrustStore(TrustStore object)
{
- throw new UnsupportedOperationException("Not implemented yet!");
+ synchronized(_trustStores)
+ {
+ String name = object.getName();
+ TrustStore removedTrustStore = _trustStores.remove(name);
+ if(removedTrustStore != null)
+ {
+ removedTrustStore.removeChangeListener(this);
+ }
+
+ return removedTrustStore != null;
+ }
}
@Override
@@ -726,14 +693,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
{
return _authenticationProviderFactory.getSupportedAuthenticationProviders();
}
- else if (KEY_STORE_PASSWORD.equals(name) || TRUST_STORE_PASSWORD.equals(name) || PEER_STORE_PASSWORD.equals(name))
- {
- if (getActualAttributes().get(name) != null)
- {
- return DUMMY_PASSWORD_MASK;
- }
- return null;
- }
else if (MODEL_VERSION.equals(name))
{
return Model.MODEL_MAJOR_VERSION + "." + Model.MODEL_MINOR_VERSION;
@@ -885,6 +844,7 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
{
childDeleted = deleteTrustStore((TrustStore)object);
}
+
if(childDeleted)
{
childRemoved(object);
@@ -1034,18 +994,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
}
@Override
- public KeyStore getDefaultKeyStore()
- {
- return _keyStores.get(_defaultKeyStoreId);
- }
-
- @Override
- public TrustStore getDefaultTrustStore()
- {
- return _trustStores.get(_defaultTrustStoreId);
- }
-
- @Override
public TaskExecutor getTaskExecutor()
{
return super.getTaskExecutor();
@@ -1058,9 +1006,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
Map<String, Object> convertedAttributes = MapValueConverter.convert(attributes, ATTRIBUTE_TYPES);
validateAttributes(convertedAttributes);
- boolean keyStoreChanged = false;
- boolean trustStoreChanged = false;
- boolean peerStoreChanged = false;
Collection<String> names = AVAILABLE_ATTRIBUTES;
for (String name : names)
{
@@ -1081,34 +1026,11 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
_defaultAuthenticationProvider = findAuthenticationProviderByName((String)desired);
}
}
- else if (KEY_STORE_PATH.equals(name) || KEY_STORE_PASSWORD.equals(name) || KEY_STORE_CERT_ALIAS.equals(name))
- {
- keyStoreChanged = true;
- }
- else if (TRUST_STORE_PATH.equals(name) || TRUST_STORE_PASSWORD.equals(name))
- {
- trustStoreChanged = true;
- }
- else if (PEER_STORE_PATH.equals(name) || PEER_STORE_PASSWORD.equals(name))
- {
- peerStoreChanged = true;
- }
+
attributeSet(name, expected, desired);
}
}
}
- if (keyStoreChanged)
- {
- createKeyStore();
- }
- if (trustStoreChanged)
- {
- createTrustStore();
- }
- if (peerStoreChanged)
- {
- createPeerStore();
- }
}
private void validateAttributes(Map<String, Object> convertedAttributes)
@@ -1125,9 +1047,7 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
// create a group manager to validate the groups specified in file
new FileGroupManager(groupFile);
}
- validateKeyStoreAttributes(convertedAttributes, "key store", KEY_STORE_PATH, KEY_STORE_PASSWORD, KEY_STORE_CERT_ALIAS);
- validateKeyStoreAttributes(convertedAttributes, "trust store", TRUST_STORE_PATH, TRUST_STORE_PASSWORD, null);
- validateKeyStoreAttributes(convertedAttributes, "peer store", PEER_STORE_PATH, PEER_STORE_PASSWORD, null);
+
String defaultAuthenticationProvider = (String) convertedAttributes.get(DEFAULT_AUTHENTICATION_PROVIDER);
if (defaultAuthenticationProvider != null)
{
@@ -1176,59 +1096,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
}
}
- private void validateKeyStoreAttributes(Map<String, Object> convertedAttributes, String type, String pathAttribute,
- String passwordAttribute, String aliasAttribute)
- {
- String keyStoreFile = (String) convertedAttributes.get(pathAttribute);
- String password = (String) convertedAttributes.get(passwordAttribute);
- String alias = aliasAttribute!= null? (String) convertedAttributes.get(aliasAttribute) : null;
- if (keyStoreFile != null || password != null || alias != null)
- {
- if (keyStoreFile == null)
- {
- keyStoreFile = (String) getActualAttributes().get(pathAttribute);
- }
- if (password == null)
- {
- password = (String) getActualAttributes().get(passwordAttribute);
- }
- java.security.KeyStore keyStore = null;
- try
- {
- keyStore = SSLUtil.getInitializedKeyStore(keyStoreFile, password, java.security.KeyStore.getDefaultType());
- }
- catch (Exception e)
- {
- throw new IllegalConfigurationException("Cannot instantiate " + type + " at " + keyStoreFile, e);
- }
- if (aliasAttribute != null)
- {
- if (alias == null)
- {
- alias = (String) getActualAttributes().get(aliasAttribute);
- }
- if (alias != null)
- {
- Certificate cert = null;
- try
- {
- cert = keyStore.getCertificate(alias);
- }
- catch (KeyStoreException e)
- {
- // key store should be initialized above
- throw new RuntimeException("Key store has not been initialized", e);
- }
- if (cert == null)
- {
- throw new IllegalConfigurationException("Cannot find a certificate with alias " + alias + "in " + type
- + " : " + keyStoreFile);
- }
- }
- }
- }
- }
-
@Override
protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/KeyStoreAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/KeyStoreAdapter.java
index 113d895e62..4d4d3bb31d 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/KeyStoreAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/KeyStoreAdapter.java
@@ -20,23 +20,63 @@
*/
package org.apache.qpid.server.model.adapter;
+import java.lang.reflect.Type;
+import java.security.AccessControlException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
+import javax.net.ssl.KeyManagerFactory;
+
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.IntegrityViolationException;
import org.apache.qpid.server.model.KeyStore;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.util.MapValueConverter;
+import org.apache.qpid.transport.network.security.ssl.SSLUtil;
public class KeyStoreAdapter extends AbstractKeyStoreAdapter implements KeyStore
{
+ @SuppressWarnings("serial")
+ public static final Map<String, Type> ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap<String, Type>(){{
+ put(NAME, String.class);
+ put(PATH, String.class);
+ put(PASSWORD, String.class);
+ put(TYPE, String.class);
+ put(CERTIFICATE_ALIAS, String.class);
+ put(KEY_MANAGER_FACTORY_ALGORITHM, String.class);
+ }});
+
+ @SuppressWarnings("serial")
+ public static final Map<String, Object> DEFAULTS = Collections.unmodifiableMap(new HashMap<String, Object>(){{
+ put(KeyStore.TYPE, DEFAULT_KEYSTORE_TYPE);
+ put(KeyStore.KEY_MANAGER_FACTORY_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm());
+ }});
+
+ private Broker _broker;
public KeyStoreAdapter(UUID id, Broker broker, Map<String, Object> attributes)
{
- super(id, broker, attributes);
- if (attributes.get(CERTIFICATE_ALIAS) != null)
- {
- changeAttribute(CERTIFICATE_ALIAS, null, attributes.get(CERTIFICATE_ALIAS));
- }
+ super(id, broker, DEFAULTS, MapValueConverter.convert(attributes, ATTRIBUTE_TYPES));
+ _broker = broker;
+
+ String keyStorePath = (String)getAttribute(KeyStore.PATH);
+ String keyStorePassword = getPassword();
+ String keyStoreType = (String)getAttribute(KeyStore.TYPE);
+ String keyManagerFactoryAlgorithm = (String)getAttribute(KeyStore.KEY_MANAGER_FACTORY_ALGORITHM);
+ String certAlias = (String)getAttribute(KeyStore.CERTIFICATE_ALIAS);
+
+ validateKeyStoreAttributes(keyStoreType, keyStorePath, keyStorePassword,
+ certAlias, keyManagerFactoryAlgorithm);
}
@Override
@@ -45,4 +85,129 @@ public class KeyStoreAdapter extends AbstractKeyStoreAdapter implements KeyStore
return AVAILABLE_ATTRIBUTES;
}
+ @Override
+ protected boolean setState(State currentState, State desiredState)
+ {
+ if(desiredState == State.DELETED)
+ {
+ // verify that it is not in use
+ String storeName = getName();
+
+ Collection<Port> ports = new ArrayList<Port>(_broker.getPorts());
+ for (Port port : ports)
+ {
+ if (storeName.equals(port.getAttribute(Port.KEY_STORE)))
+ {
+ throw new IntegrityViolationException("Key store '" + storeName + "' can't be deleted as it is in use by a port:" + port.getName());
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException
+ {
+ if(desiredState == State.DELETED)
+ {
+ if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), KeyStore.class, Operation.DELETE))
+ {
+ throw new AccessControlException("Deletion of key store is denied");
+ }
+ }
+ }
+
+ @Override
+ protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException
+ {
+ authoriseSetAttribute();
+ }
+
+ @Override
+ protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException
+ {
+ authoriseSetAttribute();
+ }
+
+ private void authoriseSetAttribute()
+ {
+ if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), KeyStore.class, Operation.UPDATE))
+ {
+ throw new AccessControlException("Setting key store attributes is denied");
+ }
+ }
+
+ @Override
+ protected void changeAttributes(Map<String, Object> attributes)
+ {
+ Map<String, Object> changedValues = MapValueConverter.convert(attributes, ATTRIBUTE_TYPES);
+ if(changedValues.containsKey(KeyStore.NAME))
+ {
+ String newName = (String) changedValues.get(KeyStore.NAME);
+ if(!getName().equals(newName))
+ {
+ throw new IllegalConfigurationException("Changing the key store name is not allowed");
+ }
+ }
+
+ Map<String, Object> merged = generateEffectiveAttributes(changedValues);
+
+ String keyStorePath = (String)merged.get(KeyStore.PATH);
+ String keyStorePassword = (String) merged.get(KeyStore.PASSWORD);
+ String keyStoreType = (String)merged.get(KeyStore.TYPE);
+ String keyManagerFactoryAlgorithm = (String)merged.get(KeyStore.KEY_MANAGER_FACTORY_ALGORITHM);
+ String certAlias = (String)merged.get(KeyStore.CERTIFICATE_ALIAS);
+
+ validateKeyStoreAttributes(keyStoreType, keyStorePath, keyStorePassword,
+ certAlias, keyManagerFactoryAlgorithm);
+
+ super.changeAttributes(changedValues);
+ }
+
+ private void validateKeyStoreAttributes(String type, String keyStorePath,
+ String keyStorePassword, String alias,
+ String keyManagerFactoryAlgorithm)
+ {
+ java.security.KeyStore keyStore = null;
+ try
+ {
+ keyStore = SSLUtil.getInitializedKeyStore(keyStorePath, keyStorePassword, type);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalConfigurationException("Cannot instantiate key store at " + keyStorePath, e);
+ }
+
+ if (alias != null)
+ {
+ Certificate cert = null;
+ try
+ {
+ cert = keyStore.getCertificate(alias);
+ }
+ catch (KeyStoreException e)
+ {
+ // key store should be initialized above
+ throw new RuntimeException("Key store has not been initialized", e);
+ }
+ if (cert == null)
+ {
+ throw new IllegalConfigurationException("Cannot find a certificate with alias " + alias
+ + "in key store : " + keyStorePath);
+ }
+ }
+
+ try
+ {
+ KeyManagerFactory.getInstance(keyManagerFactoryAlgorithm);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new IllegalConfigurationException("Unknown keyManagerFactoryAlgorithm: "
+ + keyManagerFactoryAlgorithm);
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java
index 4250de17a7..0c1249d20e 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java
@@ -37,12 +37,14 @@ import org.apache.qpid.server.model.AuthenticationProvider;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.ConfiguredObject;
import org.apache.qpid.server.model.Connection;
+import org.apache.qpid.server.model.KeyStore;
import org.apache.qpid.server.model.LifetimePolicy;
import org.apache.qpid.server.model.Port;
import org.apache.qpid.server.model.Protocol;
import org.apache.qpid.server.model.State;
import org.apache.qpid.server.model.Statistics;
import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.server.model.TrustStore;
import org.apache.qpid.server.model.VirtualHost;
import org.apache.qpid.server.model.VirtualHostAlias;
import org.apache.qpid.server.security.access.Operation;
@@ -58,6 +60,8 @@ public class PortAdapter extends AbstractAdapter implements Port
put(NAME, String.class);
put(PROTOCOLS, new ParameterizedTypeImpl(Set.class, Protocol.class));
put(TRANSPORTS, new ParameterizedTypeImpl(Set.class, Transport.class));
+ put(TRUST_STORES, new ParameterizedTypeImpl(Set.class, String.class));
+ put(KEY_STORE, String.class);
put(PORT, Integer.class);
put(TCP_NO_DELAY, Boolean.class);
put(RECEIVE_BUFFER_SIZE, Integer.class);
@@ -373,16 +377,40 @@ public class PortAdapter extends AbstractAdapter implements Port
boolean requiresCertificate = (needClientCertificate != null && needClientCertificate.booleanValue())
|| (wantClientCertificate != null && wantClientCertificate.booleanValue());
- if (transports != null && transports.contains(Transport.SSL))
+ String keyStoreName = (String) merged.get(KEY_STORE);
+ boolean hasKeyStore = keyStoreName != null;
+ if(keyStoreName != null)
{
- if (_broker.getKeyStores().isEmpty())
+ if (_broker.findKeyStoreByName(keyStoreName) == null)
{
- throw new IllegalConfigurationException("Can't create port which requires SSL as the broker has no keystore configured.");
+ throw new IllegalConfigurationException("Can't find key store with name '" + keyStoreName + "' for port " + getName());
+ }
+ }
+
+ Set<String> trustStoreNames = (Set<String>) merged.get(TRUST_STORES);
+ boolean hasTrustStore = trustStoreNames != null && !trustStoreNames.isEmpty();
+ if(hasTrustStore)
+ {
+ for (String trustStoreName : trustStoreNames)
+ {
+ if (_broker.findTrustStoreByName(trustStoreName) == null)
+ {
+ throw new IllegalConfigurationException("Cannot find trust store with name '" + trustStoreName + "'");
+ }
+ }
+ }
+
+ boolean usesSsl = transports != null && transports.contains(Transport.SSL);
+ if (usesSsl)
+ {
+ if (keyStoreName == null)
+ {
+ throw new IllegalConfigurationException("Can't create port which requires SSL but has no key store configured.");
}
- if (_broker.getTrustStores().isEmpty() && requiresCertificate)
+ if (!hasTrustStore && requiresCertificate)
{
- throw new IllegalConfigurationException("Can't create port which requests SSL client certificates as the broker has no trust/peer stores configured.");
+ throw new IllegalConfigurationException("Can't create port which requests SSL client certificates but has no trust store configured.");
}
}
else
@@ -393,9 +421,14 @@ public class PortAdapter extends AbstractAdapter implements Port
}
}
- if (protocols != null && protocols.contains(Protocol.HTTPS) && _broker.getKeyStores().isEmpty())
+ if (protocols != null && protocols.contains(Protocol.HTTPS) && !hasKeyStore)
{
- throw new IllegalConfigurationException("Can't create port which requires SSL as the broker has no keystore configured.");
+ throw new IllegalConfigurationException("Can't create port which requires SSL but has no key store configured.");
+ }
+
+ if (protocols != null && protocols.contains(Protocol.RMI) && usesSsl)
+ {
+ throw new IllegalConfigurationException("Can't create RMI Registry port which requires SSL.");
}
String authenticationProviderName = (String)merged.get(AUTHENTICATION_PROVIDER);
@@ -450,4 +483,42 @@ public class PortAdapter extends AbstractAdapter implements Port
throw new AccessControlException("Setting of port attributes is denied");
}
}
+
+ @Override
+ public KeyStore getKeyStore()
+ {
+ String keyStoreName = (String)getAttribute(Port.KEY_STORE);
+ KeyStore keyStore = _broker.findKeyStoreByName(keyStoreName);
+
+ if (keyStoreName != null && keyStore == null)
+ {
+ throw new IllegalConfigurationException("Can't find key store with name '" + keyStoreName + "' for port " + getName());
+ }
+
+ return keyStore;
+ }
+
+ @Override
+ public Collection<TrustStore> getTrustStores()
+ {
+ Set<String> trustStoreNames = (Set<String>) getAttribute(TRUST_STORES);
+ boolean hasTrustStoreName = trustStoreNames != null && !trustStoreNames.isEmpty();
+
+ final Collection<TrustStore> trustStores = new ArrayList<TrustStore>();
+ if(hasTrustStoreName)
+ {
+ for (String name : trustStoreNames)
+ {
+ TrustStore trustStore = _broker.findTrustStoreByName(name);
+ if (trustStore == null)
+ {
+ throw new IllegalConfigurationException("Can't find trust store with name '" + name + "' for port " + getName());
+ }
+
+ trustStores.add(trustStore);
+ }
+ }
+
+ return trustStores;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortFactory.java
index ffbd24997a..2efe189d73 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortFactory.java
@@ -106,9 +106,9 @@ public class PortFactory
port = new AmqpPortAdapter(id, broker, attributes, defaults, broker.getTaskExecutor());
boolean useClientAuth = (Boolean) port.getAttribute(Port.NEED_CLIENT_AUTH) || (Boolean) port.getAttribute(Port.WANT_CLIENT_AUTH);
- if(useClientAuth && broker.getTrustStores().isEmpty())
+ if(useClientAuth && port.getTrustStores().isEmpty())
{
- throw new IllegalConfigurationException("Can't create port which requests SSL client certificates as the broker has no trust/peer stores configured.");
+ throw new IllegalConfigurationException("Can't create port which requests SSL client certificates but has no trust stores configured.");
}
if(useClientAuth && !port.getTransports().contains(Transport.SSL))
@@ -142,13 +142,19 @@ public class PortFactory
defaults.put(Port.NAME, portValue + "-" + protocol.name());
port = new PortAdapter(id, broker, attributes, defaults, broker.getTaskExecutor());
+
+ boolean rmiPort = port.getProtocols().contains(Protocol.RMI);
+ if (rmiPort && port.getTransports().contains(Transport.SSL))
+ {
+ throw new IllegalConfigurationException("Can't create RMI registry port which requires SSL");
+ }
}
if(port.getTransports().contains(Transport.SSL) || port.getProtocols().contains(Protocol.HTTPS))
{
- if(broker.getKeyStores().isEmpty())
+ if(port.getKeyStore() == null)
{
- throw new IllegalConfigurationException("Can't create port which requires SSL as the broker has no keystore configured.");
+ throw new IllegalConfigurationException("Can't create port which requires SSL but has no key store configured.");
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/TrustStoreAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/TrustStoreAdapter.java
index bdffe605ec..06089e43c6 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/TrustStoreAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/TrustStoreAdapter.java
@@ -20,18 +20,61 @@
*/
package org.apache.qpid.server.model.adapter;
+import java.lang.reflect.Type;
+import java.security.AccessControlException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
+import javax.net.ssl.TrustManagerFactory;
+
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.IntegrityViolationException;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.State;
import org.apache.qpid.server.model.TrustStore;
+import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.util.MapValueConverter;
+import org.apache.qpid.transport.network.security.ssl.SSLUtil;
public class TrustStoreAdapter extends AbstractKeyStoreAdapter implements TrustStore
{
+ @SuppressWarnings("serial")
+ public static final Map<String, Type> ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap<String, Type>(){{
+ put(NAME, String.class);
+ put(PATH, String.class);
+ put(PASSWORD, String.class);
+ put(TYPE, String.class);
+ put(PEERS_ONLY, Boolean.class);
+ put(TRUST_MANAGER_FACTORY_ALGORITHM, String.class);
+ }});
+
+ @SuppressWarnings("serial")
+ public static final Map<String, Object> DEFAULTS = Collections.unmodifiableMap(new HashMap<String, Object>(){{
+ put(TrustStore.TYPE, DEFAULT_KEYSTORE_TYPE);
+ put(TrustStore.PEERS_ONLY, Boolean.FALSE);
+ put(TrustStore.TRUST_MANAGER_FACTORY_ALGORITHM, TrustManagerFactory.getDefaultAlgorithm());
+ }});
+
+ private Broker _broker;
+
public TrustStoreAdapter(UUID id, Broker broker, Map<String, Object> attributes)
{
- super(id, broker, attributes);
+ super(id, broker, DEFAULTS, MapValueConverter.convert(attributes, ATTRIBUTE_TYPES));
+ _broker = broker;
+
+ String trustStorePath = (String) getAttribute(TrustStore.PATH);
+ String trustStorePassword = getPassword();
+ String trustStoreType = (String) getAttribute(TrustStore.TYPE);
+ String trustManagerFactoryAlgorithm = (String) getAttribute(TrustStore.TRUST_MANAGER_FACTORY_ALGORITHM);
+
+ validateTrustStoreAttributes(trustStoreType, trustStorePath,
+ trustStorePassword, trustManagerFactoryAlgorithm);
}
@Override
@@ -40,4 +83,110 @@ public class TrustStoreAdapter extends AbstractKeyStoreAdapter implements TrustS
return AVAILABLE_ATTRIBUTES;
}
+ @Override
+ protected boolean setState(State currentState, State desiredState)
+ {
+ if(desiredState == State.DELETED)
+ {
+ // verify that it is not in use
+ String storeName = getName();
+
+ Collection<Port> ports = new ArrayList<Port>(_broker.getPorts());
+ for (Port port : ports)
+ {
+ Collection<TrustStore> trustStores = port.getTrustStores();
+ for(TrustStore store : trustStores)
+ {
+ if (storeName.equals(store.getAttribute(TrustStore.NAME)))
+ {
+ throw new IntegrityViolationException("Trust store '" + storeName + "' can't be deleted as it is in use by a port: " + port.getName());
+ }
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException
+ {
+ if(desiredState == State.DELETED)
+ {
+ if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), TrustStore.class, Operation.DELETE))
+ {
+ throw new AccessControlException("Deletion of key store is denied");
+ }
+ }
+ }
+
+ @Override
+ protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException
+ {
+ authoriseSetAttribute();
+ }
+
+ @Override
+ protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException
+ {
+ authoriseSetAttribute();
+ }
+
+ private void authoriseSetAttribute()
+ {
+ if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), TrustStore.class, Operation.UPDATE))
+ {
+ throw new AccessControlException("Setting key store attributes is denied");
+ }
+ }
+
+ @Override
+ protected void changeAttributes(Map<String, Object> attributes)
+ {
+ Map<String, Object> changedValues = MapValueConverter.convert(attributes, ATTRIBUTE_TYPES);
+ if(changedValues.containsKey(TrustStore.NAME))
+ {
+ String newName = (String) changedValues.get(TrustStore.NAME);
+ if(!getName().equals(newName))
+ {
+ throw new IllegalConfigurationException("Changing the trust store name is not allowed");
+ }
+ }
+
+ Map<String, Object> merged = generateEffectiveAttributes(changedValues);
+
+ String trustStorePath = (String)merged.get(TrustStore.PATH);
+ String trustStorePassword = (String) merged.get(TrustStore.PASSWORD);
+ String trustStoreType = (String)merged.get(TrustStore.TYPE);
+ String trustManagerFactoryAlgorithm = (String)merged.get(TrustStore.TRUST_MANAGER_FACTORY_ALGORITHM);
+
+ validateTrustStoreAttributes(trustStoreType, trustStorePath,
+ trustStorePassword, trustManagerFactoryAlgorithm);
+
+ super.changeAttributes(changedValues);
+ }
+
+ private void validateTrustStoreAttributes(String type, String trustStorePath,
+ String password, String trustManagerFactoryAlgorithm)
+ {
+ try
+ {
+ SSLUtil.getInitializedKeyStore(trustStorePath, password, type);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalConfigurationException("Cannot instantiate trust store at " + trustStorePath, e);
+ }
+
+ try
+ {
+ TrustManagerFactory.getInstance(trustManagerFactoryAlgorithm);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new IllegalConfigurationException("Unknown trustManagerFactoryAlgorithm: " + trustManagerFactoryAlgorithm);
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/MapValueConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/MapValueConverter.java
index 8c57d04348..16e717a9c7 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/MapValueConverter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/MapValueConverter.java
@@ -62,7 +62,7 @@ public class MapValueConverter
return getStringAttribute(name, attributes, null);
}
- private static void assertMandatoryAttribute(String name, Map<String, Object> attributes)
+ public static void assertMandatoryAttribute(String name, Map<String, Object> attributes)
{
if (!attributes.containsKey(name))
{
@@ -326,6 +326,10 @@ public class MapValueConverter
public static <T> Set<T> toSet(Object rawValue, Class<T> setItemClass, String attributeName)
{
+ if (rawValue == null)
+ {
+ return null;
+ }
HashSet<T> set = new HashSet<T>();
if (rawValue instanceof Iterable)
{