001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.util.jsse;
018    
019    import java.io.IOException;
020    import java.io.InputStream;
021    import java.security.GeneralSecurityException;
022    import java.security.KeyStore;
023    import java.security.Security;
024    import java.util.Enumeration;
025    import java.util.LinkedList;
026    import java.util.List;
027    
028    import org.slf4j.Logger;
029    import org.slf4j.LoggerFactory;
030    
031    /**
032     * A representation of configuration options for creating and loading a
033     * {@link KeyStore} instance.
034     */
035    public class KeyStoreParameters extends JsseParameters {
036    
037        private static final Logger LOG = LoggerFactory.getLogger(KeyStoreParameters.class);
038    
039        /**
040         * The optional type of the key store to load. See Appendix A in the 
041         * <a href="http://download.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html#KeyStore">
042         * Java Cryptography Architecture Standard Algorithm Name Documentation</a> for more information on standard names.
043         */
044        protected String type;
045        
046        /**
047         * The optional password for reading/opening/verifying the key store.
048         */
049        protected String password;
050        
051        /**
052         * The optional provider identifier for instantiating the key store.
053         */
054        protected String provider;
055        
056        /**
057         * The optional file path, class path resource, or URL of the resource
058         * used to load the key store.
059         */
060        protected String resource;
061    
062        /**
063         * @see #setType(String)
064         */
065        public String getType() {
066            return type;
067        }
068    
069        /**
070         * Sets the type of the key store to create and load. See Appendix A in the
071         * <a href="http://download.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html#KeyStore"
072         * >Java Cryptography Architecture Standard Algorithm Name
073         * Documentation</a> for more information on standard names.
074         * 
075         * @param value the key store type identifier (may be {@code null})
076         */
077        public void setType(String value) {
078            this.type = value;
079        }
080    
081        /**
082         * @see #getPassword()
083         */
084        public String getPassword() {
085            return password;
086        }
087    
088        /**
089         * Set the optional password for reading/opening/verifying the key store.
090         * 
091         * @param value the password value (may be {@code null})
092         */
093        public void setPassword(String value) {
094            this.password = value;
095        }
096    
097        /**
098         * @see #setProvider(String)
099         */
100        public String getProvider() {
101            return provider;
102        }
103    
104        /**
105         * Sets the optional provider identifier for instantiating the key store.
106         *
107         * @param value the provider identifier (may be {@code null})
108         *
109         * @see Security#getProviders()
110         */
111        public void setProvider(String value) {
112            this.provider = value;
113        }
114    
115        /**
116         * @see #getResource()
117         */
118        public String getResource() {
119            return resource;
120        }
121    
122        /**
123         * Sets the optional file path, class path resource, or URL of the resource
124         * used to load the key store.
125         * 
126         * @param value the resource (may be {@code null})
127         */
128        public void setResource(String value) {
129            this.resource = value;
130        }
131    
132        /**
133         * Creates a {@link KeyStoreParameters} instance based off of the configuration state
134         * of this instance. If {@link #getType()} returns {@code null}, the default
135         * key store type is loaded, otherwise the type will be of that specified.
136         * <p/>
137         * The created instance will always be loaded, but if the type requires an
138         * input stream and {@link #getResource()} returns {@code null}, the
139         * instance will be empty. The loading of the resource, if not {@code null},
140         * is attempted by treating the resource as a file path, a class path
141         * resource, and a URL in that order. An exception is thrown if the resource
142         * cannot be resolved to readable input stream using any of the above
143         * methods.
144         * 
145         * @return a configured and loaded key store
146         * @throws GeneralSecurityException if there is an error creating an instance
147         *             with the given configuration
148         * @throws IOException if there is an error resolving the configured
149         *             resource to an input stream
150         */
151        public KeyStore createKeyStore() throws GeneralSecurityException, IOException {
152            LOG.trace("Creating KeyStore instance from KeyStoreParameters [{}].", this);
153    
154            String ksType = this.parsePropertyValue(this.type);
155            if (ksType == null) {
156                ksType = KeyStore.getDefaultType();
157            }
158    
159            char[] ksPassword = null;
160            if (this.password != null) {
161                ksPassword = this.parsePropertyValue(this.password).toCharArray();
162            }
163    
164            KeyStore ks;
165            if (this.provider == null) {
166                ks = KeyStore.getInstance(ksType);
167            } else {
168                ks = KeyStore.getInstance(ksType, this.parsePropertyValue(this.provider));
169            }
170            
171            if (this.resource == null) {
172                ks.load(null, ksPassword);
173            } else {
174                InputStream is = this.resolveResource(this.parsePropertyValue(this.resource));
175                ks.load(is, ksPassword);
176            }
177            
178            if (LOG.isDebugEnabled()) {
179                List<String> aliases = new LinkedList<String>();
180                
181                Enumeration<String> aliasEnum = ks.aliases();
182                while (aliasEnum.hasMoreElements()) {
183                    aliases.add(aliasEnum.nextElement());
184                }
185                
186                LOG.debug("KeyStore [{}], initialized from [{}], is using provider [{}], has type [{}], and contains aliases {}.",
187                          new Object[] {ks, this, ks.getProvider(), ks.getType(), aliases});
188            }
189            
190            return ks;
191        }
192    
193        @Override
194        public String toString() {
195            StringBuilder builder = new StringBuilder();
196            builder.append("KeyStoreParameters [type=");
197            builder.append(type);
198            builder.append(", password=");
199            builder.append("********");
200            builder.append(", provider=");
201            builder.append(provider);
202            builder.append(", resource=");
203            builder.append(resource);
204            builder.append(", getContext()=");
205            builder.append(getCamelContext());
206            builder.append("]");
207            return builder.toString();
208        }
209    }