From 2be645039124c47883165c83bff284824af5b9a9 Mon Sep 17 00:00:00 2001
From: Patrick Diligent <patrick.diligent@forgerock.com>
Date: Wed, 22 Jul 2015 12:37:35 +0000
Subject: [PATCH] OPENDJ-1056 CR-7615
---
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedKeyManagerProvider.java | 88 ++++++++++++++++-----
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java | 41 +++++++++
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java | 37 ++++++++
opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/protocol.properties | 9 +
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/util/SelectableCertificateKeyManager.java | 8 +-
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/api/KeyManagerProvider.java | 25 ++++++
opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/extension.properties | 4
7 files changed, 174 insertions(+), 38 deletions(-)
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/api/KeyManagerProvider.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/api/KeyManagerProvider.java
index d7b086c..e6bfe18 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/api/KeyManagerProvider.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/api/KeyManagerProvider.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2006-2008 Sun Microsystems, Inc.
- * Portions Copyright 2014 ForgeRock AS
+ * Portions Copyright 2015 ForgeRock AS
*/
package org.opends.server.api;
import org.forgerock.i18n.LocalizableMessage;
@@ -76,6 +76,29 @@
throws ConfigException, InitializationException;
+ /**
+ *
+ * Verifies that an alias is defined in the scope of this Key Manager.
+ *
+ * @param alias
+ * The alias to check.
+ * @return true if the alias exists, false otherwise
+ */
+ public boolean containsKeyWithAlias(String alias)
+ {
+ return true;
+ }
+
+ /**
+ *
+ * Verifies that the keystore has at least one usable key.
+ *
+ * @return true if the keystore has at least one usable key, false otherwise
+ */
+ public boolean containsAtLeastOneKey()
+ {
+ return true;
+ }
/**
* Indicates whether the provided configuration is acceptable for
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedKeyManagerProvider.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedKeyManagerProvider.java
index 3636e02..d3ccd49 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedKeyManagerProvider.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedKeyManagerProvider.java
@@ -229,25 +229,41 @@
/**
- * Retrieves a set of <CODE>KeyManager</CODE> objects that may be used for
- * interactions requiring access to a key manager.
- *
- * @return A set of <CODE>KeyManager</CODE> objects that may be used for
- * interactions requiring access to a key manager.
- *
- * @throws DirectoryException If a problem occurs while attempting to obtain
- * the set of key managers.
+ * {@inheritDoc}
*/
@Override
- public KeyManager[] getKeyManagers() throws DirectoryException
- {
+ public boolean containsKeyWithAlias(String alias) {
+ KeyStore keyStore;
+
+ try {
+ keyStore = getKeystore();
+ } catch (DirectoryException e) {
+ return false;
+ }
+
+ try {
+ Enumeration<String> aliases = keyStore.aliases();
+ while (aliases.hasMoreElements()) {
+ String theAlias = aliases.nextElement();
+ if (alias.equals(theAlias) && keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
+ return true;
+ }
+ }
+ } catch (KeyStoreException e) {
+ }
+
+ return false;
+ }
+
+ private KeyStore getKeystore()
+ throws DirectoryException {
KeyStore keyStore;
try
{
keyStore = KeyStore.getInstance(keyStoreType);
FileInputStream inputStream =
- new FileInputStream(getFileForPath(keyStoreFile));
+ new FileInputStream(getFileForPath(keyStoreFile));
try
{
keyStore.load(inputStream, keyStorePIN);
@@ -262,24 +278,36 @@
logger.traceException(e);
LocalizableMessage message = ERR_FILE_KEYMANAGER_CANNOT_LOAD.get(
- keyStoreFile, getExceptionMessage(e));
+ keyStoreFile, getExceptionMessage(e));
throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
- message, e);
+ message, e);
}
+ return keyStore;
+ }
- try {
- // Troubleshooting aid; Analyse the keystore for the presence of at least one private entry.
- if (!findOneKeyEntry(keyStore))
- {
- logger.warn(INFO_NO_KEY_ENTRY_IN_KEYSTORE, keyStoreFile);
- }
- }
- catch (Exception e) {
- logger.traceException(e);
- }
+ /**
+ * Retrieves a set of <CODE>KeyManager</CODE> objects that may be used for
+ * interactions requiring access to a key manager.
+ *
+ * @return A set of <CODE>KeyManager</CODE> objects that may be used for
+ * interactions requiring access to a key manager.
+ *
+ * @throws DirectoryException If a problem occurs while attempting to obtain
+ * the set of key managers.
+ */
+ @Override
+ public KeyManager[] getKeyManagers() throws DirectoryException
+ {
+ KeyStore keyStore = getKeystore();
try
{
+ if (! findOneKeyEntry(keyStore))
+ {
+ // Troubleshooting message to let now of possible config error
+ logger.error(ERR_NO_KEY_ENTRY_IN_KEYSTORE, keyStoreFile);
+ }
+
String keyManagerAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory keyManagerFactory =
KeyManagerFactory.getInstance(keyManagerAlgorithm);
@@ -297,6 +325,20 @@
}
}
+ /** {@inheritDoc} */
+ @Override
+ public boolean containsAtLeastOneKey()
+ {
+ try
+ {
+ return findOneKeyEntry(getKeystore());
+ }
+ catch (Exception e) {
+ logger.traceException(e);
+ }
+ return false;
+ }
+
private boolean findOneKeyEntry(KeyStore keyStore) throws KeyStoreException
{
Enumeration<String> aliases = keyStore.aliases();
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
index 7019709..65f7e49 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
@@ -446,6 +446,8 @@
public void initializeConnectionHandler(HTTPConnectionHandlerCfg config)
throws ConfigException, InitializationException
{
+ this.enabled = config.isEnabled();
+
if (friendlyName == null)
{
friendlyName = config.dn().rdn().getAttributeValue(0).toString();
@@ -462,6 +464,7 @@
// Configure SSL if needed.
try
{
+ // This call may disable the connector if wrong SSL settings
configureSSL(config);
}
catch (DirectoryException e)
@@ -482,7 +485,6 @@
this.initConfig = config;
this.currentConfig = config;
- this.enabled = this.currentConfig.isEnabled();
}
private String getHandlerName(HTTPConnectionHandlerCfg config)
@@ -649,6 +651,8 @@
setName(handlerName);
boolean lastIterationFailed = false;
+ boolean starting = true;
+
while (!shutdownRequested)
{
// If this connection handler is not enabled, then just sleep
@@ -660,6 +664,20 @@
stopHttpServer();
}
+ if (starting)
+ {
+ // This may happen if there was an initialisation error
+ // which led to disable the connector.
+ // The main thread is waiting for the connector to listen
+ // on its port, which will not occur yet,
+ // so notify here to allow the server startup to complete.
+ synchronized (waitListen)
+ {
+ starting = false;
+ waitListen.notify();
+ }
+ }
+
StaticUtils.sleep(1000);
continue;
}
@@ -992,9 +1010,17 @@
DN keyMgrDN = config.getKeyManagerProviderDN();
KeyManagerProvider<?> keyManagerProvider =
DirectoryServer.getKeyManagerProvider(keyMgrDN);
- if (keyManagerProvider == null)
- {
+ if (keyManagerProvider == null) {
+ logger.error(ERR_NULL_KEY_PROVIDER_MANAGER, keyMgrDN, friendlyName);
+ logger.warn(INFO_DISABLE_CONNECTION, friendlyName);
keyManagerProvider = new NullKeyManagerProvider();
+ enabled = false;
+ }
+ else if (! keyManagerProvider.containsAtLeastOneKey())
+ {
+ logger.error(ERR_INVALID_KEYSTORE, friendlyName);
+ logger.warn(INFO_DISABLE_CONNECTION, friendlyName);
+ enabled = false;
}
String alias = config.getSSLCertNickname();
@@ -1005,6 +1031,11 @@
}
else
{
+ if (! keyManagerProvider.containsKeyWithAlias(alias)) {
+ logger.error(ERR_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, alias, friendlyName);
+ logger.warn(INFO_DISABLE_CONNECTION, friendlyName);
+ enabled = false;
+ }
keyManagers =
SelectableCertificateKeyManager.wrap(keyManagerProvider
.getKeyManagers(), alias);
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
index 205dd87..bca67f2 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
@@ -674,6 +674,7 @@
// Configure SSL if needed.
try
{
+ // This call may disable the connector if wrong SSL settings
configureSSL(config);
}
catch (DirectoryException e)
@@ -929,6 +930,7 @@
{
setName(handlerName);
boolean listening = false;
+ boolean starting = true;
while (!shutdownRequested)
{
@@ -944,6 +946,20 @@
logger.info(NOTE_CONNHANDLER_STOPPED_LISTENING, handlerName);
}
+ if (starting)
+ {
+ // This may happen if there was an initialisation error
+ // which led to disable the connector.
+ // The main thread is waiting for the connector to listen
+ // on its port, which will not occur yet,
+ // so notify here to allow the server startup to complete.
+ synchronized (waitListen)
+ {
+ starting = false;
+ waitListen.notify();
+ }
+ }
+
StaticUtils.sleep(1000);
continue;
}
@@ -1376,6 +1392,15 @@
+ private void disableAndWarnIfUseSSL(LDAPConnectionHandlerCfg config)
+ {
+ if (config.isUseSSL())
+ {
+ logger.warn(INFO_DISABLE_CONNECTION, friendlyName);
+ enabled = false;
+ }
+ }
+
private SSLContext createSSLContext(LDAPConnectionHandlerCfg config)
throws DirectoryException
{
@@ -1386,10 +1411,15 @@
.getKeyManagerProvider(keyMgrDN);
if (keyManagerProvider == null)
{
- if (config.isUseSSL()) {
- logger.warn(INFO_NULL_KEY_PROVIDER_MANAGER, keyMgrDN, friendlyName);
- }
+ logger.error(ERR_NULL_KEY_PROVIDER_MANAGER, keyMgrDN, friendlyName);
+ disableAndWarnIfUseSSL(config);
keyManagerProvider = new NullKeyManagerProvider();
+ // The SSL connection is unusable without a key manager provider
+ }
+ else if (! keyManagerProvider.containsAtLeastOneKey())
+ {
+ logger.error(ERR_INVALID_KEYSTORE, friendlyName);
+ disableAndWarnIfUseSSL(config);
}
String alias = config.getSSLCertNickname();
@@ -1400,6 +1430,11 @@
}
else
{
+ if (!keyManagerProvider.containsKeyWithAlias(alias))
+ {
+ logger.error(ERR_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, alias, friendlyName);
+ disableAndWarnIfUseSSL(config);
+ }
keyManagers = SelectableCertificateKeyManager.wrap(
keyManagerProvider.getKeyManagers(), alias, friendlyName);
}
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/util/SelectableCertificateKeyManager.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/util/SelectableCertificateKeyManager.java
index 7ea0319..10f0b64 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/util/SelectableCertificateKeyManager.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/util/SelectableCertificateKeyManager.java
@@ -135,7 +135,7 @@
}
}
}
- logger.warn(INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, keyType, alias, componentName);
+ logger.warn(INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, componentName, keyType, alias);
return null;
}
@@ -175,7 +175,7 @@
}
}
- logger.warn(INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, keyType, alias, componentName);
+ logger.warn(INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, componentName, keyType, alias);
return null;
}
@@ -210,7 +210,7 @@
}
}
- logger.warn(INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, keyType, alias, componentName);
+ logger.warn(INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, componentName, keyType, alias);
return null;
}
@@ -249,7 +249,7 @@
}
}
- logger.warn(INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, keyType, alias, componentName);
+ logger.warn(INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, componentName, keyType, alias);
return null;
}
diff --git a/opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/extension.properties b/opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/extension.properties
index bc04302..ac37b48 100644
--- a/opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/extension.properties
+++ b/opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/extension.properties
@@ -1023,5 +1023,5 @@
definition '%s' is invalid because the range '%s' is missing the minus
ERR_CHARSET_VALIDATOR_SHORT_RANGE_635=The provided character range \
definition '%s' is invalid because the range '%s' is too short
-INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS_636=The %s key with alias '%s' was not found for '%s'
-INFO_NO_KEY_ENTRY_IN_KEYSTORE_637=There is no key entry in keystore %s
\ No newline at end of file
+ERR_NO_KEY_ENTRY_IN_KEYSTORE_636=There is no private key entry in keystore %s
+INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS_637=handshake for '%s': cipher is expecting key %s to be of type %s
\ No newline at end of file
diff --git a/opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/protocol.properties b/opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/protocol.properties
index ddca568..91d6c42 100644
--- a/opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/protocol.properties
+++ b/opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/protocol.properties
@@ -907,7 +907,12 @@
whitespace character at the current position: %s
ERR_GSER_NO_VALID_IDENTIFIEDCHOICE_1523=The GSER value does not \
contain a valid IdentifiedChoiceValue at the current position: %s
-INFO_NULL_KEY_PROVIDER_MANAGER_1524=The keystore %s seems to be missing, \
- this may render the secure port inoperative for '%s'
+ERR_NULL_KEY_PROVIDER_MANAGER_1524=The keystore %s seems to be missing, \
+ this may render the secure port inoperative for '%s'. \
+ Verify the keystore setting in the configuration.
ERR_PROXYAUTH_AUTHZ_NOT_PERMITTED_1525=Authorization as '%s' specified in \
the proxied authorization control is not permitted
+ERR_KEYSTORE_DOES_NOT_CONTAIN_ALIAS_1526=The key with alias '%s' was not found for '%s'. \
+ Verify that the keystore is properly configured
+ERR_INVALID_KEYSTORE_1527=No usable key was found for '%s'. Verify the keystore content
+INFO_DISABLE_CONNECTION_1528=Disabling %s
--
Gitblit v1.10.0