001    package org.cumulus4j.keymanager.front.webapp;
002    
003    import java.io.File;
004    import java.io.IOException;
005    import java.util.HashMap;
006    import java.util.Map;
007    
008    import javax.ws.rs.core.Context;
009    
010    import org.cumulus4j.keymanager.AppServerManager;
011    import org.cumulus4j.keymanager.back.shared.SystemPropertyUtil;
012    import org.cumulus4j.keystore.KeyStore;
013    import org.slf4j.Logger;
014    import org.slf4j.LoggerFactory;
015    
016    /**
017     * <p>
018     * Manager for {@link KeyStore}s mapping a <code>keyStoreID</code> to a file name in the local
019     * file system.
020     * </p><p>
021     * One instance of this class is held as a REST-app-singleton and injected into the REST services
022     * via {@link Context} like this example:
023     * </p>
024     * <pre>
025     * private &#64;Context KeyStoreManager keyStoreManager;
026     * </pre>
027     *
028     * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
029     */
030    public class KeyStoreManager
031    {
032            private static final Logger logger = LoggerFactory.getLogger(KeyStoreManager.class);
033    
034            /**
035             * <p>
036             * System property to control which directory is used to manage key store files. If not specified,
037             * the directory "&#36;{user.home}/.cumulus4j/" will be used.
038             * </p>
039             * <p>
040             * You can use system properties in this system-property's value. For example
041             * passing "-Dcumulus4j.keyStoreDir=&#36;{java.io.tmpdir}/cumulus4j-key-stores"
042             * to the java command will be resolved to "/tmp/cumulus4j-key-stores" on GNU+Linux.
043             * </p>
044             */
045            public static final String SYSTEM_PROPERTY_KEY_STORE_DIR = "cumulus4j.keyStoreDir";
046    
047            private static File getUserHome()
048            {
049                    String userHome = System.getProperty("user.home"); //$NON-NLS-1$
050                    if (userHome == null)
051                            throw new IllegalStateException("System property user.home is not set! This should never happen!"); //$NON-NLS-1$
052    
053                    return new File(userHome);
054            }
055    
056            private Map<String, KeyStore> keyStoreID2keyStore = new HashMap<String, KeyStore>();
057    
058            private Map<String, AppServerManager> keyStoreID2appServerManager = new HashMap<String, AppServerManager>();
059    
060            private File getKeyStoreDir() throws IOException
061            {
062                    String keyStoreDirSysPropVal = System.getProperty(SYSTEM_PROPERTY_KEY_STORE_DIR);
063                    File keyStoreDir;
064    
065                    if (keyStoreDirSysPropVal == null || keyStoreDirSysPropVal.trim().isEmpty()) {
066                            keyStoreDir = new File(getUserHome(), ".cumulus4j");
067                            logger.info(
068                                            "getSingletons: System property '{}' is empty or not specified. Using default keyStoreDir '{}'.",
069                                            SYSTEM_PROPERTY_KEY_STORE_DIR, keyStoreDir.getAbsolutePath()
070                            );
071                    }
072                    else {
073                            String keyStoreDirSysPropValResolved = SystemPropertyUtil.resolveSystemProperties(keyStoreDirSysPropVal);
074                            keyStoreDir = new File(keyStoreDirSysPropValResolved);
075                            logger.info(
076                                            "getSingletons: System property '{}' was set to '{}'. Using keyStoreDir '{}'.",
077                                            new Object[] { SYSTEM_PROPERTY_KEY_STORE_DIR, keyStoreDirSysPropVal, keyStoreDir.getAbsolutePath() }
078                            );
079                    }
080    
081                    if (!keyStoreDir.isDirectory()) {
082                            keyStoreDir.mkdirs();
083    
084                            if (!keyStoreDir.isDirectory())
085                                    throw new IOException("Creating directory \"" + keyStoreDir.getAbsolutePath() + "\" failed! Check permissions!");
086                    }
087                    return keyStoreDir;
088            }
089    
090            /**
091             * Get the <code>KeyStore</code> identified by the given <code>keyStoreID</code>. If it does not exist,
092             * it is implicitely created.
093             * @param keyStoreID the identfier of the {@link KeyStore} to be returned. Must not be <code>null</code>.
094             * @return the <code>KeyStore</code> identified by the given <code>keyStoreID</code>.
095             * @throws IOException if reading from / writing to the local file system failed.
096             */
097            public synchronized KeyStore getKeyStore(String keyStoreID) throws IOException
098            {
099                    if (keyStoreID == null)
100                            throw new IllegalArgumentException("keyStoreID == null");
101    
102                    KeyStore keyStore = keyStoreID2keyStore.get(keyStoreID);
103                    if (keyStore == null) {
104                            File keyStoreFile = new File(getKeyStoreDir(), keyStoreID + ".keystore");
105                            keyStore = new KeyStore(keyStoreID, keyStoreFile);
106                            keyStoreID2keyStore.put(keyStoreID, keyStore);
107                    }
108                    return keyStore;
109            }
110    
111            /**
112             * Get the <code>AppServerManager</code> that is assigned (in a 1-1-relation) to the {@link KeyStore}
113             * identified by the given ID.
114             *
115             * @param keyStoreID the identfier of the {@link KeyStore} whose <code>AppServerManager</code> shall be returned. Must not be <code>null</code>.
116             * @return the <code>AppServerManager</code> that is assigned (in a 1-1-relation) to the {@link KeyStore}
117             * identified by the given ID.
118             * @throws IOException if reading from / writing to the local file system failed.
119             */
120            public synchronized AppServerManager getAppServerManager(String keyStoreID) throws IOException
121            {
122                    if (keyStoreID == null)
123                            throw new IllegalArgumentException("keyStoreID == null");
124    
125                    AppServerManager appServerManager = keyStoreID2appServerManager.get(keyStoreID);
126                    if (appServerManager == null) {
127                            appServerManager = new AppServerManager(getKeyStore(keyStoreID));
128                            keyStoreID2appServerManager.put(keyStoreID, appServerManager);
129                    }
130                    return appServerManager;
131            }
132    }