001    package org.cumulus4j.keymanager.api;
002    
003    import java.io.Serializable;
004    import java.util.Arrays;
005    
006    import org.cumulus4j.keystore.KeyStore;
007    
008    /**
009     * <p>
010     * Configuration of the {@link KeyManagerAPI}.
011     * </p><p>
012     * An instance of this class tells the <code>KeyManagerAPI</code> {@link #getKeyManagerBaseURL() where} the key store
013     * is located and which key-store (identified by its {@link #getKeyStoreID() keyStoreID}) is to be used (among other things).
014     * </p><p>
015     * When you pass a <code>KeyManagerAPIConfiguration</code> instance to {@link KeyManagerAPI#setConfiguration(KeyManagerAPIConfiguration)},
016     * it becomes {@link #isReadOnly() immutable}. If you want to change the configuration afterwards,
017     * {@link #KeyManagerAPIConfiguration(KeyManagerAPIConfiguration) create a new one} and call
018     * <code>KeyManagerAPI.setConfiguration(KeyManagerAPIConfiguration)</code> again.
019     * </p>
020     *
021     * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
022     */
023    public class KeyManagerAPIConfiguration
024    implements Serializable
025    {
026            private static final long serialVersionUID = 1L;
027    
028            private boolean readOnly;
029    
030            private String authUserName;
031    
032            private char[] authPassword;
033    
034            private String keyStoreID;
035    
036            private String keyManagerBaseURL;
037    
038            /**
039             * Create an empty configuration.
040             */
041            public KeyManagerAPIConfiguration() { }
042    
043            /**
044             * Create a copy of another configuration. You can use this to modify an existing (already immutable) configuration.
045             * @param source the original configuration to be copied. Can be <code>null</code>, which means that the new configuration
046             * will be completely empty (just as if it was created by the default constructor).
047             */
048            public KeyManagerAPIConfiguration(KeyManagerAPIConfiguration source)
049            {
050                    if (source != null) {
051                            setAuthUserName(source.getAuthUserName());
052                            setAuthPassword(source.getAuthPassword());
053                            setKeyStoreID(source.getKeyStoreID());
054                            setKeyManagerBaseURL(source.getKeyManagerBaseURL());
055                    }
056            }
057    
058            /**
059             * Ensure that the configuration can be modified.
060             *
061             * @throws IllegalStateException if {@link #isReadOnly()}<code> == true</code>.
062             */
063            private void assertNotReadOnly()
064            throws IllegalStateException
065            {
066                    if (readOnly)
067                            throw new IllegalStateException("This instance of KeyManagerAPIConfiguration is read-only! Cannot modify it, anymore!");
068            }
069    
070            /**
071             * Get the immutable flag. Iff <code>true</code>, every attempt to modify this instance (i.e. every setter)
072             * will throw an {@link IllegalStateException}.
073             * @return the immutable flag.
074             * @see #markReadOnly()
075             */
076            public boolean isReadOnly() {
077                    return readOnly;
078            }
079    
080            /**
081             * Set the immutable flag. After this method was called, every setter will throw an {@link IllegalStateException}
082             * rendering this instance read-only.
083             * @see #isReadOnly()
084             */
085            public void markReadOnly() {
086                    this.readOnly = true;
087            }
088    
089            /**
090             * Get the user name that will be used for authentication at the {@link KeyStore}.
091             * @return the user name for authentication at the {@link KeyStore}.
092             * @see #setAuthUserName(String)
093             */
094            public String getAuthUserName() {
095                    return authUserName;
096            }
097    
098            /**
099             * Set the user name that will be used for authentication at the {@link KeyStore}.
100             * @param authUserName the user name for authentication at the {@link KeyStore}.
101             * @see #getAuthUserName()
102             */
103            public void setAuthUserName(String authUserName) {
104                    assertNotReadOnly();
105                    this.authUserName = authUserName;
106            }
107    
108            /**
109             * Get the password that will be used for authentication at the {@link KeyStore}.
110             * @return the password for authentication at the {@link KeyStore}.
111             * @see #setAuthPassword(char[])
112             */
113            public char[] getAuthPassword() {
114                    return authPassword;
115            }
116    
117            /**
118             * Set the password that will be used for authentication at the {@link KeyStore}.
119             * @param authPassword the password for authentication at the {@link KeyStore}.
120             * This will be copied, i.e. later modifications to the given password will not
121             * affect this configuration. You indeed should zero-out the given password as soon
122             * as you don't need to keep it in memory, anymore.
123             * @see #getAuthPassword()
124             */
125            public void setAuthPassword(char[] authPassword) {
126                    assertNotReadOnly();
127    
128                    char[] oldPw = this.authPassword;
129                    if (oldPw != null)
130                            Arrays.fill(oldPw, (char)0);
131    
132                    this.authPassword = authPassword == null ? null : authPassword.clone(); // Cloning is essential, because we clear it later on.
133            }
134    
135            /**
136             * <p>
137             * Get the {@link KeyStore}'s identifier.
138             * </p><p>
139             * One key manager can manage multiple key stores. This identifier specifies which one to use.
140             * </p>
141             * @return the {@link KeyStore}'s identifier.
142             * @see #setKeyStoreID(String)
143             */
144            public String getKeyStoreID() {
145                    return keyStoreID;
146            }
147    
148            /**
149             * Set the {@link KeyStore}'s identifier.
150             * @param keyStoreID the {@link KeyStore}'s identifier. This should not contain spaces and other special characters that
151             * might not be used in restricted operating-systems (like Windows), because this might be used as (part of) a file name.
152             * Actually, it should contain only characters that can be used in URLs.
153             * @see #getKeyStoreID()
154             */
155            public void setKeyStoreID(String keyStoreID) {
156                    assertNotReadOnly();
157                    this.keyStoreID = keyStoreID;
158            }
159    
160            /**
161             * Get the URL where the {@link KeyStore} is accessible. This can either be a local directory (the URL starts with
162             * "file:") or a key-server (accessible via REST over HTTP or HTTPS).
163             * @return the {@link KeyStore}'s base-URL (the complete URL is composed of this and the {@link #getKeyStoreID() key-store-ID}.
164             * @see #setKeyManagerBaseURL(String)
165             */
166            public String getKeyManagerBaseURL() {
167                    return keyManagerBaseURL;
168            }
169    
170            /**
171             * Set the URL where the {@link KeyStore} is accessible. This can either be a local directory (the URL starts with
172             * "file:") or a key-server (accessible via REST over HTTP or HTTPS).
173             * @param keyManagerBaseURL the base-URL of the remote key-server or a local file-URL (referencing a directory!),
174             * if a local key-store is to be used. This argument can be <code>null</code>, which means to use a local file in
175             * the default directory "&#36;{user.home}/.cumulus4j/".
176             * @see #getKeyManagerBaseURL()
177             */
178            public void setKeyManagerBaseURL(String keyManagerBaseURL) {
179                    assertNotReadOnly();
180                    this.keyManagerBaseURL = keyManagerBaseURL;
181            }
182    
183            @Override
184            protected void finalize() throws Throwable {
185                    readOnly = false; // otherwise the following setAuthPassword(...) fails.
186                    setAuthPassword(null);
187                    super.finalize();
188            }
189    }