| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.karaf.jaas.config.impl; |
| |
| import java.io.BufferedInputStream; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.security.Key; |
| import java.security.KeyStore; |
| import java.security.KeyStoreException; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.PrivateKey; |
| import java.security.UnrecoverableKeyException; |
| import java.security.cert.Certificate; |
| import java.security.cert.CertificateException; |
| import java.util.ArrayList; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.net.URL; |
| import java.net.URI; |
| |
| import javax.net.ssl.KeyManager; |
| import javax.net.ssl.KeyManagerFactory; |
| import javax.net.ssl.TrustManager; |
| import javax.net.ssl.TrustManagerFactory; |
| |
| import org.apache.karaf.jaas.config.KeystoreInstance; |
| import org.apache.karaf.jaas.config.KeystoreIsLocked; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * |
| */ |
| public class ResourceKeystoreInstance implements KeystoreInstance { |
| |
| private final Logger logger = LoggerFactory.getLogger(ResourceKeystoreInstance.class); |
| |
| private static final String JKS = "JKS"; |
| |
| private String name; |
| private int rank; |
| private URL path; |
| private String keystorePassword; |
| private Map keyPasswords = new HashMap(); |
| private File keystoreFile; // Only valid after startup and if the resource points to a file |
| |
| // The following variables are the state of the keystore, which should be chucked if the file on disk changes |
| private List privateKeys = new ArrayList(); |
| private List trustCerts = new ArrayList(); |
| private KeyStore keystore; |
| private long keystoreReadDate = Long.MIN_VALUE; |
| |
| /** |
| * @return the keystoreName |
| */ |
| public String getName() { |
| return name; |
| } |
| |
| /** |
| * @param keystoreName the keystoreName to set |
| */ |
| public void setName(String keystoreName) { |
| this.name = keystoreName; |
| } |
| |
| /** |
| * @return the rank |
| */ |
| public int getRank() { |
| return rank; |
| } |
| |
| /** |
| * @param rank the rank to set |
| */ |
| public void setRank(int rank) { |
| this.rank = rank; |
| } |
| |
| /** |
| * @return the keystorePath |
| */ |
| public URL getPath() { |
| return path; |
| } |
| |
| /** |
| * @param keystorePath the keystorePath to set |
| */ |
| public void setPath(URL keystorePath) throws IOException { |
| this.path = keystorePath; |
| if (keystorePath.getProtocol().equals("file")) { |
| URI uri = URI.create(keystorePath.toString().replace(" ", "%20")); |
| this.keystoreFile = new File(uri.getSchemeSpecificPart()); |
| } |
| } |
| |
| /** |
| * @param keystorePassword the keystorePassword to set |
| */ |
| public void setKeystorePassword(String keystorePassword) { |
| this.keystorePassword = keystorePassword; |
| } |
| |
| /** |
| * @param keyPasswords the keyPasswords to set |
| */ |
| public void setKeyPasswords(String keyPasswords) { |
| if (keyPasswords != null) { |
| String[] keys = keyPasswords.split("\\]\\!\\["); |
| for (int i = 0; i < keys.length; i++) { |
| String key = keys[i]; |
| int pos = key.indexOf('='); |
| this.keyPasswords.put(key.substring(0, pos), key.substring(pos + 1).toCharArray()); |
| } |
| } |
| } |
| |
| public Certificate getCertificate(String alias) { |
| if (!loadKeystoreData()) { |
| return null; |
| } |
| try { |
| return keystore.getCertificate(alias); |
| } catch (KeyStoreException e) { |
| logger.error("Unable to read certificate from keystore", e); |
| } |
| return null; |
| } |
| |
| public String getCertificateAlias(Certificate cert) { |
| if (!loadKeystoreData()) { |
| return null; |
| } |
| try { |
| return keystore.getCertificateAlias(cert); |
| } catch (KeyStoreException e) { |
| logger.error("Unable to read retrieve alias for given certificate from keystore", e); |
| } |
| return null; |
| } |
| |
| public Certificate[] getCertificateChain(String alias) { |
| if (!loadKeystoreData()) { |
| return null; |
| } |
| try { |
| return keystore.getCertificateChain(alias); |
| } catch (KeyStoreException e) { |
| logger.error("Unable to read certificate chain from keystore", e); |
| } |
| return null; |
| } |
| |
| public KeyManager[] getKeyManager(String algorithm, String keyAlias) throws KeystoreIsLocked, |
| NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException { |
| if (isKeystoreLocked()) { |
| throw new KeystoreIsLocked("Keystore '" + name + "' is locked."); |
| } |
| if (!loadKeystoreData()) { |
| return null; |
| } |
| KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(algorithm); |
| keyFactory.init(keystore, (char[]) keyPasswords.get(keyAlias)); |
| return keyFactory.getKeyManagers(); |
| } |
| |
| public PrivateKey getPrivateKey(String alias) { |
| if (!loadKeystoreData()) { |
| return null; |
| } |
| try { |
| if (isKeyLocked(alias)) { |
| return null; |
| } |
| Key key = keystore.getKey(alias, (char[]) keyPasswords.get(alias)); |
| if (key instanceof PrivateKey) { |
| return (PrivateKey) key; |
| } |
| } catch (KeyStoreException e) { |
| logger.error("Unable to read private key from keystore", e); |
| } catch (NoSuchAlgorithmException e) { |
| logger.error("Unable to read private key from keystore", e); |
| } catch (UnrecoverableKeyException e) { |
| logger.error("Unable to read private key from keystore", e); |
| } |
| return null; |
| } |
| |
| public TrustManager[] getTrustManager(String algorithm) throws KeyStoreException, |
| NoSuchAlgorithmException, KeystoreIsLocked { |
| if (isKeystoreLocked()) { |
| throw new KeystoreIsLocked("Keystore '" + name + "' is locked."); |
| } |
| if (!loadKeystoreData()) { |
| return null; |
| } |
| TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(algorithm); |
| trustFactory.init(keystore); |
| return trustFactory.getTrustManagers(); |
| } |
| |
| public boolean isKeyLocked(String keyAlias) { |
| return keyPasswords.get(keyAlias) == null; |
| } |
| |
| public boolean isKeystoreLocked() { |
| return keystorePassword == null; |
| } |
| |
| public String[] listPrivateKeys() { |
| if (!loadKeystoreData()) { |
| return null; |
| } |
| return (String[]) privateKeys.toArray(new String[privateKeys.size()]); |
| } |
| |
| public String[] listTrustCertificates() { |
| if (!loadKeystoreData()) { |
| return null; |
| } |
| return (String[]) trustCerts.toArray(new String[trustCerts.size()]); |
| } |
| |
| // ==================== Internals ===================== |
| |
| private boolean loadKeystoreData() { |
| // Check to reload the data if needed |
| if (keystoreFile != null && keystoreReadDate >= keystoreFile.lastModified()) { |
| return true; |
| } |
| // If not a file, just not reload the data if it has already been loaded |
| if (keystoreFile == null && keystore != null) { |
| return true; |
| } |
| // Check if the file is invalid |
| if (keystoreFile != null && (!keystoreFile.exists() || !keystoreFile.canRead())) { |
| throw new IllegalArgumentException("Invalid keystore file (" + path + " = " + keystoreFile.getAbsolutePath() + ")"); |
| } |
| // Load the keystore data |
| try { |
| keystoreReadDate = System.currentTimeMillis(); |
| privateKeys.clear(); |
| trustCerts.clear(); |
| if (keystore == null) { |
| keystore = KeyStore.getInstance(JKS); |
| } |
| InputStream in = new BufferedInputStream(path.openStream()); |
| keystore.load(in, keystorePassword == null ? new char[0] : keystorePassword.toCharArray()); |
| in.close(); |
| Enumeration aliases = keystore.aliases(); |
| while (aliases.hasMoreElements()) { |
| String alias = (String) aliases.nextElement(); |
| if (keystore.isKeyEntry(alias)) { |
| privateKeys.add(alias); |
| } else if (keystore.isCertificateEntry(alias)) { |
| trustCerts.add(alias); |
| } |
| } |
| return true; |
| } catch (KeyStoreException e) { |
| logger.error("Unable to open keystore with provided password", e); |
| } catch (IOException e) { |
| logger.error("Unable to open keystore with provided password", e); |
| } catch (NoSuchAlgorithmException e) { |
| logger.error("Unable to open keystore with provided password", e); |
| } catch (CertificateException e) { |
| logger.error("Unable to open keystore with provided password", e); |
| } |
| return false; |
| } |
| |
| } |