From 1912f79bd9b292a2c8ebf79e206992be99658908 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Sun, 3 Aug 2014 23:14:07 +0000 Subject: QPID-5946 : [Java Broker] Add ability to parse PKCS#1 format private keys and improve the presentation of keys stores on the broker tab in the HTTP management UI git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1615462 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/model/AbstractConfiguredObject.java | 66 +++++++++++++- .../apache/qpid/server/security/FileKeyStore.java | 3 + .../qpid/server/security/FileKeyStoreImpl.java | 13 --- .../qpid/server/security/FileTrustStore.java | 4 + .../qpid/server/security/NonJavaKeyStore.java | 2 + .../qpid/server/security/NonJavaKeyStoreImpl.java | 100 ++++++++++++++++++++- .../qpid/server/security/NonJavaTrustStore.java | 2 + .../server/security/NonJavaTrustStoreImpl.java | 17 ++-- .../java/resources/js/qpid/management/Broker.js | 6 +- 9 files changed, 183 insertions(+), 30 deletions(-) (limited to 'qpid/java') 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 2755c8dba4..8b9effbd16 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 @@ -595,21 +595,81 @@ public abstract class AbstractConfiguredObject> im protected void onResolve() { + Set> unresolved = new HashSet<>(); + Set> derived = new HashSet<>(); + + + for (ConfiguredObjectAttribute attr : _attributeTypes.values()) + { + if (attr.isAutomated()) + { + unresolved.add(attr); + } + else if(attr.isDerived()) + { + derived.add(attr); + } + } + // If there is a context attribute, resolve it first, so that other attribute values // may support values containing references to context keys. ConfiguredObjectAttribute contextAttribute = _attributeTypes.get("context"); if (contextAttribute != null && contextAttribute.isAutomated()) { resolveAutomatedAttribute((ConfiguredAutomatedAttribute) contextAttribute); + unresolved.remove(contextAttribute); } - for (ConfiguredObjectAttribute attr : _attributeTypes.values()) + boolean changed = true; + while(!unresolved.isEmpty() || !changed) { - if (attr != contextAttribute && attr.isAutomated()) + changed = false; + Iterator> attrIter = unresolved.iterator(); + + while (attrIter.hasNext()) { - resolveAutomatedAttribute((ConfiguredAutomatedAttribute) attr); + ConfiguredObjectAttribute attr = attrIter.next(); + + if(!(dependsOn(attr, unresolved) || (!derived.isEmpty() && dependsOn(attr, derived)))) + { + resolveAutomatedAttribute((ConfiguredAutomatedAttribute) attr); + attrIter.remove(); + changed = true; + } } + // TODO - really we should define with meta data which attributes any given derived attr is dependent upon + // and only remove the derived attr as an obstacle when those fields are themselves resolved + if(!changed && !derived.isEmpty()) + { + changed = true; + derived.clear(); + } + } + } + + private boolean dependsOn(final ConfiguredObjectAttribute attr, + final Set> unresolved) + { + Object value = _attributes.get(attr.getName()); + if(value == null && !"".equals(((ConfiguredAutomatedAttribute)attr).defaultValue())) + { + value = ((ConfiguredAutomatedAttribute)attr).defaultValue(); } + if(value instanceof String) + { + String interpolated = interpolate(this, (String)value); + if(interpolated.contains("${this:")) + { + for(ConfiguredObjectAttribute unresolvedAttr : unresolved) + { + if(interpolated.contains("${this:"+unresolvedAttr.getName())) + { + return true; + } + } + } + } + return false; } private void resolveAutomatedAttribute(final ConfiguredAutomatedAttribute autoAttr) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java index d8a8c3f5cf..899e98fa22 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java @@ -57,6 +57,9 @@ public interface FileKeyStore> extends KeyStore } }; + @ManagedAttribute(defaultValue = "${this:path}") + String getDescription(); + @ManagedAttribute( mandatory = true) String getPath(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreImpl.java index d755380210..ac28619d2d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreImpl.java @@ -21,7 +21,6 @@ package org.apache.qpid.server.security; import java.io.IOException; -import java.lang.reflect.Type; import java.security.AccessControlException; import java.security.GeneralSecurityException; import java.security.KeyStoreException; @@ -29,8 +28,6 @@ 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.Set; @@ -56,16 +53,6 @@ import org.apache.qpid.transport.network.security.ssl.SSLUtil; @ManagedObject( category = false ) public class FileKeyStoreImpl extends AbstractConfiguredObject implements FileKeyStore { - @SuppressWarnings("serial") - public static final Map ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap(){{ - put(NAME, String.class); - put(PATH, String.class); - put(PASSWORD, String.class); - put(KEY_STORE_TYPE, String.class); - put(CERTIFICATE_ALIAS, String.class); - put(KEY_MANAGER_FACTORY_ALGORITHM, String.class); - }}); - @ManagedAttributeField private String _type; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStore.java index 5f220848cc..86d7d5e4b8 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStore.java @@ -57,6 +57,10 @@ public interface FileTrustStore> extends TrustStore< } }; + + @ManagedAttribute(defaultValue = "${this:path}") + String getDescription(); + @ManagedAttribute( mandatory = true ) String getPath(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStore.java index 9563f98579..458daa4b7a 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStore.java @@ -28,6 +28,8 @@ import org.apache.qpid.server.model.ManagedObject; @ManagedObject( category = false, type = "NonJavaKeyStore" ) public interface NonJavaKeyStore> extends KeyStore { + @ManagedAttribute(defaultValue = "${this:subjectName}") + String getDescription(); @ManagedAttribute( mandatory = true, secure = true ) String getPrivateKeyUrl(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStoreImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStoreImpl.java index efcd40c638..299ba6c249 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStoreImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStoreImpl.java @@ -26,8 +26,10 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; +import java.math.BigInteger; import java.net.MalformedURLException; import java.net.URL; +import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.security.AccessControlException; @@ -38,7 +40,9 @@ import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -393,12 +397,102 @@ public class NonJavaKeyStoreImpl extends AbstractConfiguredObject> extends TrustStore { + @ManagedAttribute(defaultValue = "${this:certificateDetails}") + String getDescription(); @ManagedAttribute( mandatory = true ) String getCertificatesUrl(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaTrustStoreImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaTrustStoreImpl.java index c709d5d8e7..4f7f913776 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaTrustStoreImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaTrustStoreImpl.java @@ -101,15 +101,18 @@ public class NonJavaTrustStoreImpl public List> getCertificateDetails() { List> certificateDetails = new ArrayList<>(); - for(X509Certificate certificate : _certificates) + if(_certificates != null) { - Map details = new EnumMap<>(CertificateDetails.class); + for (X509Certificate certificate : _certificates) + { + Map details = new EnumMap<>(CertificateDetails.class); - details.put(CertificateDetails.SUBJECT_NAME, getNameFromCertificate(certificate)); - details.put(CertificateDetails.ISSUER_NAME, certificate.getIssuerX500Principal().getName()); - details.put(CertificateDetails.VALID_START, certificate.getNotBefore()); - details.put(CertificateDetails.VALID_END, certificate.getNotAfter()); - certificateDetails.add(details); + details.put(CertificateDetails.SUBJECT_NAME, getNameFromCertificate(certificate)); + details.put(CertificateDetails.ISSUER_NAME, certificate.getIssuerX500Principal().getName()); + details.put(CertificateDetails.VALID_START, certificate.getNotBefore()); + details.put(CertificateDetails.VALID_END, certificate.getNotAfter()); + certificateDetails.add(details); + } } return certificateDetails; } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js index ff33d8e7c6..3ae4537807 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js @@ -544,10 +544,8 @@ define(["dojo/_base/xhr", that.keyStoresGrid = new UpdatableStore(that.brokerData.keystores, query(".broker-key-stores")[0], [ { name: "Name", field: "name", width: "20%"}, - { name: "Path", field: "path", width: "40%"}, - { name: "Type", field: "keyStoreType", width: "5%"}, - { name: "Key Manager Algorithm", field: "keyManagerFactoryAlgorithm", width: "20%"}, - { name: "Alias", field: "certificateAlias", width: "15%"} + { name: "Type", field: "type", width: "20%"}, + { name: "Description", field: "description", width: "60%"} ], function(obj) { connect.connect(obj.grid, "onRowDblClick", obj.grid, function(evt){ -- cgit v1.2.1