001    package org.cumulus4j.keymanager.api.internal.local;
002    
003    import java.io.File;
004    import java.io.IOException;
005    import java.net.MalformedURLException;
006    import java.net.URI;
007    import java.net.URISyntaxException;
008    import java.net.URL;
009    import java.util.Collections;
010    import java.util.HashMap;
011    import java.util.Map;
012    
013    import org.cumulus4j.keymanager.AppServer;
014    import org.cumulus4j.keymanager.AppServerManager;
015    import org.cumulus4j.keymanager.api.AuthenticationException;
016    import org.cumulus4j.keymanager.api.CannotDeleteLastUserException;
017    import org.cumulus4j.keymanager.api.CryptoSession;
018    import org.cumulus4j.keymanager.api.DateDependentKeyStrategyInitParam;
019    import org.cumulus4j.keymanager.api.DateDependentKeyStrategyInitResult;
020    import org.cumulus4j.keymanager.api.KeyManagerAPIConfiguration;
021    import org.cumulus4j.keymanager.api.KeyManagerAPIInstantiationException;
022    import org.cumulus4j.keymanager.api.KeyStoreNotEmptyException;
023    import org.cumulus4j.keymanager.api.internal.AbstractKeyManagerAPI;
024    import org.cumulus4j.keystore.DateDependentKeyStrategy;
025    import org.cumulus4j.keystore.KeyStore;
026    import org.cumulus4j.keystore.UserNotFoundException;
027    
028    /**
029     * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
030     */
031    public class LocalKeyManagerAPI extends AbstractKeyManagerAPI
032    {
033            private KeyStore keyStore;
034            private AppServerManager appServerManager;
035            private Map<String, String> appServerBaseURL2appServerID = Collections.synchronizedMap(new HashMap<String, String>());
036    
037            private KeyStore getKeyStore() throws IOException
038            {
039                    KeyStore ks = this.keyStore;
040    
041                    if (ks == null) {
042                            ks = new KeyStore(getKeyStoreFile());
043                            this.keyStore = ks;
044                    }
045    
046                    return ks;
047            }
048    
049            private AppServerManager getAppServerManager() throws IOException
050            {
051                    AppServerManager asm = this.appServerManager;
052    
053                    if (asm == null) {
054                            asm = new AppServerManager(getKeyStore());
055                            this.appServerManager = asm;
056                    }
057    
058                    return asm;
059            }
060    
061            private File getKeyStoreFile() throws IOException
062            {
063                    File keyStoreDir;
064                    String keyManagerBaseURL = getKeyManagerBaseURL();
065    
066                    if (keyManagerBaseURL == null) {
067                            String userHome = System.getProperty("user.home"); //$NON-NLS-1$
068                            if (userHome == null)
069                                    throw new IllegalStateException("System property user.home is not set! This should never happen!"); //$NON-NLS-1$
070    
071                            keyStoreDir = new File(userHome, ".cumulus4j");
072                    }
073                    else {
074                            if (!keyManagerBaseURL.startsWith(FILE_URL_PREFIX))
075                                    throw new IllegalStateException("keyManagerBaseURL does not start with \"" + FILE_URL_PREFIX + "\"!!!");
076    
077                            // see: http://weblogs.java.net/blog/kohsuke/archive/2007/04/how_to_convert.html
078                            try {
079                                    keyStoreDir = new File(new URI(keyManagerBaseURL));
080                            } catch (URISyntaxException x) {
081                                    try {
082                                            keyStoreDir = new File(new URL(keyManagerBaseURL).getPath());
083                                    } catch (MalformedURLException e) {
084                                            throw new IllegalStateException("keyManagerBaseURL is malformed: " + e, e);
085                                    }
086                            }
087                    }
088    
089                    if (!keyStoreDir.isDirectory()) {
090                            keyStoreDir.mkdirs();
091    
092                            if (!keyStoreDir.isDirectory())
093                                    throw new IOException("Creating directory \"" + keyStoreDir.getAbsolutePath() + "\" failed! Check permissions!");
094                    }
095    
096                    return new File(keyStoreDir, getKeyStoreID() + ".keystore");
097            }
098    
099            @Override
100            public void setConfiguration(KeyManagerAPIConfiguration configuration) throws IllegalArgumentException, KeyManagerAPIInstantiationException
101            {
102                    super.setConfiguration(configuration);
103                    this.keyStore = null;
104                    this.appServerManager = null;
105                    appServerBaseURL2appServerID.clear();
106            }
107    
108            public LocalKeyManagerAPI()
109            throws KeyManagerAPIInstantiationException
110            {
111                    // We test here, whether the KeyStore is accessible. If it is not, it means the local stuff is not deployed
112                    // and it should not be possible to instantiate a LocalKeyManagerAPI.
113                    KeyStore.class.getConstructors();
114            }
115    
116            @Override
117            public DateDependentKeyStrategyInitResult initDateDependentKeyStrategy(DateDependentKeyStrategyInitParam param)
118            throws KeyStoreNotEmptyException, IOException
119            {
120                    if (param == null)
121                            throw new IllegalArgumentException("param == null");
122    
123                    DateDependentKeyStrategyInitResult result = new DateDependentKeyStrategyInitResult();
124    
125                    try {
126                            KeyStore keyStore = getKeyStore();
127                            DateDependentKeyStrategy keyStrategy = new DateDependentKeyStrategy(keyStore);
128                            keyStrategy.init(getAuthUserName(), getAuthPassword(), param.getKeyActivityPeriodMSec(), param.getKeyStorePeriodMSec());
129    
130                            result.setGeneratedKeyCount(
131                                            keyStore.getKeyIDs(getAuthUserName(), getAuthPassword()).size()
132                            );
133    
134                            return result;
135                    } catch (org.cumulus4j.keystore.KeyStoreNotEmptyException e) {
136                            throw new KeyStoreNotEmptyException(e);
137                    } catch (org.cumulus4j.keystore.AuthenticationException e) {
138                            throw new IOException(e); // Should never happen, because we were able to initialise the key-store with this auth-data.
139                    }
140            }
141    
142            @Override
143            public void putUser(String userName, char[] password) throws AuthenticationException, IOException
144            {
145                    KeyStore keyStore = getKeyStore();
146                    try {
147                            try {
148                                    keyStore.createUser(getAuthUserName(), getAuthPassword(), userName, password);
149                            } catch (org.cumulus4j.keystore.UserAlreadyExistsException e) {
150                                    try {
151                                            keyStore.changeUserPassword(getAuthUserName(), getAuthPassword(), userName, password);
152                                    } catch (UserNotFoundException e1) {
153                                            throw new RuntimeException("What the hell?! Just caught a UserAlreadyExistsException - why is the user not existing now?!", e1);
154                                    }
155                            }
156                    } catch (org.cumulus4j.keystore.AuthenticationException e) {
157                            throw new AuthenticationException(e);
158                    }
159    
160                    // If we changed the current user's password, we automatically re-configure this API instance.
161                    KeyManagerAPIConfiguration conf = getConf();
162                    if (conf.getAuthUserName() != null && conf.getAuthUserName().equals(userName)) {
163                            KeyManagerAPIConfiguration newConf = new KeyManagerAPIConfiguration(conf);
164                            newConf.setAuthPassword(password);
165                            try {
166                                    setConfiguration(newConf);
167                            } catch (KeyManagerAPIInstantiationException e) {
168                                    throw new RuntimeException(e); // Shouldn't happen, because we copied the old configuration.
169                            }
170                    }
171            }
172    
173            @Override
174            public void deleteUser(String userName) throws AuthenticationException, CannotDeleteLastUserException, IOException
175            {
176                    KeyStore keyStore = getKeyStore();
177                    try {
178                            keyStore.deleteUser(getAuthUserName(), getAuthPassword(), userName);
179                    } catch (org.cumulus4j.keystore.UserNotFoundException e) {
180                            // silently ignore
181                            doNothing();
182                    } catch (org.cumulus4j.keystore.CannotDeleteLastUserException e) {
183                            throw new CannotDeleteLastUserException(e);
184                    } catch (org.cumulus4j.keystore.AuthenticationException e) {
185                            throw new AuthenticationException(e);
186                    }
187            }
188    
189            private static final void doNothing() { }
190    
191            @Override
192            public CryptoSession getCryptoSession(String appServerBaseURL) throws IOException, AuthenticationException
193            {
194    //              try {
195                            AppServerManager appServerManager = getAppServerManager();
196                            AppServer appServer;
197                            synchronized (appServerBaseURL2appServerID) {
198                                    String appServerID = appServerBaseURL2appServerID.get(appServerBaseURL);
199                                    if (appServerID == null) {
200                                            appServer = new AppServer(appServerManager, appServerID, appServerBaseURL);
201                                            appServerManager.putAppServer(appServer);
202                                            appServer.getAppServerID();
203                                    }
204                                    else
205                                            appServer = appServerManager.getAppServerForAppServerID(appServerID);
206                            }
207    
208    //                      // Try to open the session already now, so that we know already here, whether this works (but lock it immediately, again).
209    //                      appServer.getSessionManager().acquireSession(getAuthUserName(), getAuthPassword()).release();
210    
211                            return new LocalCryptoSession(this, appServer);
212    //              } catch (org.cumulus4j.keystore.AuthenticationException e) {
213    //                      throw new AuthenticationException(e);
214    //              }
215            }
216    
217    }