/* * Copyright 2014, The Sporting Exchange Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.betfair.cougar.util; import com.betfair.cougar.util.configuration.PropertyConfigurer; import org.springframework.core.io.Resource; import javax.management.*; import java.io.FileInputStream; import java.io.InputStream; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.*; public class KeyStoreManagement implements DynamicMBean { private KeyStore keyStore; private SortedMap<String, X509Certificate> certificates = new TreeMap<String, X509Certificate>(); private SortedMap<String, X509Certificate[]> certificateChains = new TreeMap<String, X509Certificate[]>(); private Map<String, ValueResolver> attributeValues = new HashMap<String, ValueResolver>(); private static String STRING = "java.lang.String"; private final Resource source; private final String type; public static KeyStoreManagement getKeyStoreManagement(String type, Resource source, String pass) throws Exception { if (type == null) { throw new IllegalArgumentException("type cannot be null"); } KeyStore store = KeyStore.getInstance(type); if (source == null || source.getFilename().equals(PropertyConfigurer.NO_DEFAULT)) { return null; } InputStream is = source.getInputStream(); try { store.load(is, pass.toCharArray()); } finally { if (is != null) { is.close(); } } return new KeyStoreManagement(store, source, type); } private KeyStoreManagement(KeyStore keyStore, Resource source, String type) throws KeyStoreException { this.keyStore = keyStore; this.source = source; this.type = type; Enumeration<String> aliases = keyStore.aliases(); while (aliases.hasMoreElements()) { String alias = aliases.nextElement(); if (keyStore.isCertificateEntry(alias)) { addCertificate(alias); } else { addCertificateChain(alias); } } } private void addCertificateChain(String alias) throws KeyStoreException { Certificate[] certChain = keyStore.getCertificateChain(alias); if (certChain == null) { return; } X509Certificate[] newChain = new X509Certificate[certChain.length]; for (int i = 0; i < certChain.length; i++) { if (!(certChain[i] instanceof X509Certificate)) { throw new IllegalArgumentException("Only support X509 certificates: " + certChain[i]); } newChain[i] = (X509Certificate)certChain[i]; } certificateChains.put(alias, newChain); } private void addCertificate(String alias) throws KeyStoreException { Certificate cert = keyStore.getCertificate(alias); if (!(cert instanceof X509Certificate)) { throw new IllegalArgumentException("Only support X509 certificates: " + cert); } certificates.put(alias, (X509Certificate)cert); } public KeyStore getKeyStore() { return keyStore; } @Override public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { throw new UnsupportedOperationException("No write attributes exist"); } @Override public AttributeList setAttributes(AttributeList attributes) { throw new UnsupportedOperationException("No write attributes exist"); } @Override public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException { throw new UnsupportedOperationException("Unsupported operation: " + actionName); } @Override public MBeanInfo getMBeanInfo() { return new MBeanInfo(getClass().getName(), "KeyStore Management Info", getAttributes(), new MBeanConstructorInfo[0], new MBeanOperationInfo[0], new MBeanNotificationInfo[0]); } @Override public Object getAttribute(String attribute) { ValueResolver vr = attributeValues.get(attribute); if (vr == null) { throw new IllegalArgumentException("Unsupported attribute: " + attribute); } return vr.resolve(); } @Override public AttributeList getAttributes(String[] attributes) { AttributeList ret = new AttributeList(); for (String s : attributes) { ret.add(new Attribute(s, getAttribute(s))); } return ret; } private void addComplexAttribute(List<MBeanAttributeInfo> ret, String name, String type, String description, ValueResolver vr) { MBeanAttributeInfo attr = new MBeanAttributeInfo( name, type, description, true, false, false); ret.add(attr); attributeValues.put(name, vr); } private void addCertificateAttributes(List<MBeanAttributeInfo> ret, final X509Certificate certificate, String prefix) { addComplexAttribute(ret, prefix + ".SubjectDN", STRING, "", new ValueResolver() { @Override public Object resolve() { return certificate.getSubjectDN().getName(); } }); addComplexAttribute(ret, prefix + ".StartDate", STRING, "", new ValueResolver() { @Override public Object resolve() { return certificate.getNotBefore(); } }); addComplexAttribute(ret, prefix + ".ExpiryDate", STRING, "", new ValueResolver() { @Override public Object resolve() { return certificate.getNotAfter(); } }); addComplexAttribute(ret, prefix + ".IssuerDN", STRING, "", new ValueResolver() { @Override public Object resolve() { return certificate.getIssuerDN().getName(); } }); addComplexAttribute(ret, prefix + ".SignatureAlgorithm", STRING, "", new ValueResolver() { @Override public Object resolve() { return certificate.getSigAlgName(); } }); } private MBeanAttributeInfo[] getAttributes() { List<MBeanAttributeInfo> ret = new ArrayList<MBeanAttributeInfo>(); // source info first.. // ret.add(new MBeanAttributeInfo()); addComplexAttribute(ret, "KeyStore.Source", STRING, "", new ValueResolver() { @Override public Object resolve() { return source.getFilename(); } }); addComplexAttribute(ret, "KeyStore.Type", STRING, "", new ValueResolver() { @Override public Object resolve() { return type; } }); // individual certs first for (String alias : certificates.keySet()) { X509Certificate certificate = certificates.get(alias); String prefix = "Certificate." + alias; addCertificateAttributes(ret, certificate, prefix); } // chains next for (String alias : certificateChains.keySet()) { int index = 0; for (X509Certificate certificate : certificateChains.get(alias)) { String prefix = "CertificateChain." + alias + ".Certificate[" + index + "]"; addCertificateAttributes(ret, certificate, prefix); index++; } } return ret.toArray(new MBeanAttributeInfo[ret.size()]); } public static interface ValueResolver { Object resolve(); } }