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.security.GeneralSecurityException;
021    import java.security.SecureRandom;
022    import java.security.Security;
023    import java.util.List;
024    
025    import javax.net.ssl.KeyManager;
026    import javax.net.ssl.SSLContext;
027    import javax.net.ssl.SSLEngine;
028    import javax.net.ssl.SSLServerSocketFactory;
029    import javax.net.ssl.SSLSocketFactory;
030    import javax.net.ssl.TrustManager;
031    
032    import org.slf4j.Logger;
033    import org.slf4j.LoggerFactory;
034    
035    /**
036     * Represents {@link SSLContext} configuration options used in instantiating an
037     * {@code SSLContext} instance.
038     */
039    public class SSLContextParameters extends BaseSSLContextParameters {
040        
041        protected static final String DEFAULT_SECURE_SOCKET_PROTOCOL = "TLS";
042        
043        private static final Logger LOG = LoggerFactory.getLogger(SSLContextParameters.class);
044    
045        /**
046         * The optional key manager configuration for creating the
047         * {@link KeyManager}s used in constructing an {@link SSLContext}.
048         */
049        private KeyManagersParameters keyManagers;
050        
051        /**
052         * The optional trust manager configuration for creating the
053         * {@link TrustManager}s used in constructing an {@link SSLContext}.
054         */
055        private TrustManagersParameters trustManagers;
056            
057        /**
058         * The optional secure random configuration options to use for constructing
059         * the {@link SecureRandom} used in the creation of an {@link SSLContext].
060         */
061        private SecureRandomParameters secureRandom;
062        
063        /**
064         * The optional configuration options to be applied purely to the client side settings
065         * of the {@link SSLContext}.  Settings specified here override any duplicate settings
066         * provided at the overall level by this class.  These parameters apply to 
067         * {@link SSLSocketFactory}s and {@link SSLEngine}s produced by the the {@code SSLContext}
068         * produced from this class as well as to the {@code SSLContext} itself.
069         */
070        private SSLContextClientParameters clientParameters;
071        
072        /**
073         * The optional configuration options to be applied purely to the server side settings
074         * of the {@link SSLContext}.  Settings specified here override any duplicate settings
075         * provided at the overall level by this class.  These parameters apply to 
076         * {@link SSLServerSocketFactory}s and {@link SSLEngine}s produced by the the {@code SSLContext}
077         * produced from this class as well as to the {@code SSLContext} itself.
078         */
079        private SSLContextServerParameters serverParameters;
080    
081        /**
082         * The optional provider identifier for the JSSE implementation to use when
083         * constructing an {@link SSLContext}.
084         */
085        private String provider;
086    
087        /**
088         * The optional protocol for the secure sockets created by the {@link SSLContext}
089         * represented by this instance's configuration. See Appendix A in the <a
090         * href="http://download.oracle.com/javase/6/docs/technotes/guides//security/jsse/JSSERefGuide.html#AppA"
091         * >Java Secure Socket Extension Reference Guide</a> for information about
092         * standard protocol names.
093         */
094        private String secureSocketProtocol;    
095    
096        public KeyManagersParameters getKeyManagers() {
097            return keyManagers;
098        }
099    
100        /**
101         * Sets the optional key manager configuration for creating the
102         * {@link KeyManager}s used in constructing an {@link SSLContext}.
103         * 
104         * @param keyManagers the options or {@code null} to provide no
105         *            {@code KeyManager}s
106         */
107        public void setKeyManagers(KeyManagersParameters keyManagers) {
108            this.keyManagers = keyManagers;
109        }
110    
111        public TrustManagersParameters getTrustManagers() {
112            return trustManagers;
113        }
114    
115        /**
116         * Sets the optional trust manager configuration for creating the
117         * {@link TrustManager}s used in constructing an {@link SSLContext}.
118         * 
119         * @param trustManagers the options or {@code null} to provide no
120         *            {@code TrustManager}s
121         */
122        public void setTrustManagers(TrustManagersParameters trustManagers) {
123            this.trustManagers = trustManagers;
124        }
125    
126        public SecureRandomParameters getSecureRandom() {
127            return secureRandom;
128        }
129    
130        /**
131         * Sets the optional secure random configuration options to use for 
132         * constructing the {@link SecureRandom} used in the creation of an {@link SSLContext}.
133         *
134         * @param secureRandom the options or {@code null} to use the default
135         */
136        public void setSecureRandom(SecureRandomParameters secureRandom) {
137            this.secureRandom = secureRandom;
138        }
139        
140        public SSLContextClientParameters getClientParameters() {
141            return clientParameters;
142        }
143    
144        /**
145         * The optional configuration options to be applied purely to the client side settings
146         * of the {@link SSLContext}.  Settings specified here override any duplicate settings
147         * provided at the overall level by this class.  These parameters apply to 
148         * {@link SSLSocketFactory}s and {@link SSLEngine}s produced by the the {@code SSLContext}
149         * produced from this class as well as to the {@code SSLContext} itself.
150         *
151         * @param clientParameters the optional additional client-side parameters
152         */
153        public void setClientParameters(SSLContextClientParameters clientParameters) {
154            this.clientParameters = clientParameters;
155        }
156    
157        public SSLContextServerParameters getServerParameters() {
158            return serverParameters;
159        }
160    
161        /**
162         * The optional configuration options to be applied purely to the server side settings
163         * of the {@link SSLContext}.  Settings specified here override any duplicate settings
164         * provided at the overall level by this class.  These parameters apply to 
165         * {@link SSLServerSocketFactory}s and {@link SSLEngine}s produced by the the {@code SSLContext}
166         * produced from this class as well as to the {@code SSLContext} itself.
167         *
168         * @param serverParameters the optional additional client-side parameters
169         */
170        public void setServerParameters(SSLContextServerParameters serverParameters) {
171            this.serverParameters = serverParameters;
172        }
173    
174        public String getProvider() {
175            return provider;
176        }
177    
178        /**
179         * Sets the optional provider identifier to use when constructing an
180         * {@link SSLContext}.
181         * 
182         * @param provider the identifier (from the list of available providers
183         *            returned by {@link Security#getProviders()}) or {@code null}
184         *            to use the highest priority provider implementing the secure
185         *            socket protocol
186         *
187         * @see Security#getProviders(java.util.Map)
188         * @see #setSecureSocketProtocol(String)            
189         */
190        public void setProvider(String provider) {
191            this.provider = provider;
192        }
193    
194        public String getSecureSocketProtocol() {
195            if (this.secureSocketProtocol == null) {
196                return DEFAULT_SECURE_SOCKET_PROTOCOL;
197            }
198            return this.secureSocketProtocol;
199        }
200    
201        /**
202         * Sets the optional protocol for the secure sockets created by the
203         * {@link SSLContext} represented by this instance's configuration. Defaults
204         * to TLS. See Appendix A in the <a href=
205         * "http://download.oracle.com/javase/6/docs/technotes/guides//security/jsse/JSSERefGuide.html#AppA"
206         * >Java Secure Socket Extension Reference Guide</a> for information about
207         * standard protocol names.
208         * 
209         * @param secureSocketProtocol the name of the protocol or {@code null} to
210         *            use the default (TLS)
211         */
212        public void setSecureSocketProtocol(String secureSocketProtocol) {
213            this.secureSocketProtocol = secureSocketProtocol;
214        }
215        
216        ////////////////////////////////////////////
217        
218        /**
219         * Creates an {@link SSLContext} based on the related configuration options
220         * of this instance. Namely, {@link #keyManagers}, {@link #trustManagers}, and
221         * {@link #secureRandom}, but also respecting the chosen provider and secure
222         * socket protocol as well.
223         * 
224         * @return a newly configured instance
225         *
226         * @throws GeneralSecurityException if there is a problem in this instances
227         *             configuration or that of its nested configuration options
228         * @throws IOException if there is an error reading a key/trust store
229         */
230        public SSLContext createSSLContext() throws GeneralSecurityException, IOException {
231            
232            LOG.trace("Creating SSLContext from SSLContextParameters [{}].", this);
233            
234            LOG.info("Available providers: {}.", Security.getProviders());
235    
236            KeyManager[] keyManagers = this.keyManagers == null ? null : this.keyManagers.createKeyManagers();
237            TrustManager[] trustManagers = this.trustManagers == null ? null : this.trustManagers.createTrustManagers();
238            SecureRandom secureRandom = this.secureRandom == null ? null : this.secureRandom.createSecureRandom();
239    
240            SSLContext context;
241            if (this.getProvider() == null) {
242                context = SSLContext.getInstance(this.parsePropertyValue(this.getSecureSocketProtocol()));
243            } else {
244                context = SSLContext.getInstance(this.parsePropertyValue(this.getSecureSocketProtocol()),
245                                                 this.parsePropertyValue(this.getProvider()));
246            }
247            
248            LOG.debug("SSLContext [{}], initialized from [{}], is using provider [{}], protocol [{}], key managers {}, trust managers {}, and secure random [{}].",
249                     new Object[] {context, this, context.getProvider(), context.getProtocol(), keyManagers, trustManagers, secureRandom});
250            
251            context.init(keyManagers, trustManagers, secureRandom);
252            
253            this.configureSSLContext(context);
254            
255            // Decorate the context.
256            context = new SSLContextDecorator(
257                    new SSLContextSpiDecorator(
258                            context,
259                            this.getSSLEngineConfigurers(context),
260                            this.getSSLSocketFactoryConfigurers(context),
261                            this.getSSLServerSocketFactoryConfigurers(context)));
262    
263            return context;
264        }
265        
266        @Override
267        protected void configureSSLContext(SSLContext context) throws GeneralSecurityException {
268            LOG.trace("Configuring client and server side SSLContext parameters on SSLContext [{}]...", context);
269            super.configureSSLContext(context);
270            
271            if (this.getClientParameters() != null) {
272                LOG.trace("Overriding client-side SSLContext parameters on SSLContext [{}] with configured client parameters.",
273                          context);
274                this.getClientParameters().configureSSLContext(context);
275            }
276    
277            if (this.getServerParameters() != null) {
278                LOG.trace("Overriding server-side SSLContext parameters on SSLContext [{}] with configured server parameters.",
279                          context);
280                this.getServerParameters().configureSSLContext(context);
281            }        
282            
283            LOG.trace("Configured client and server side SSLContext parameters on SSLContext [{}].", context);
284        }
285        
286        @Override
287        protected List<Configurer<SSLEngine>> getSSLEngineConfigurers(SSLContext context) {
288            LOG.trace("Collecting client and server side SSLEngine configurers on SSLContext [{}]...", context);
289            List<Configurer<SSLEngine>> configurers = super.getSSLEngineConfigurers(context);
290            
291            if (this.getClientParameters() != null) {
292                LOG.trace("Augmenting SSLEngine configurers with configurers from client parameters on SSLContext [{}].",
293                          context);
294                configurers.addAll(this.getClientParameters().getSSLEngineConfigurers(context));
295            }
296            
297            if (this.getServerParameters() != null) {
298                LOG.trace("Augmenting SSLEngine configurers with configurers from server parameters on SSLContext [{}].",
299                          context);
300                configurers.addAll(this.getServerParameters().getSSLEngineConfigurers(context));
301            }
302            
303            LOG.trace("Collected client and server side SSLEngine configurers on SSLContext [{}].", context);
304            
305            return configurers;
306        }
307        
308        @Override
309        protected List<Configurer<SSLSocketFactory>> getSSLSocketFactoryConfigurers(SSLContext context) {
310            LOG.trace("Collecting SSLSocketFactory configurers on SSLContext [{}]...", context);
311            List<Configurer<SSLSocketFactory>> configurers = super.getSSLSocketFactoryConfigurers(context);
312            
313            if (this.getClientParameters() != null) {
314                LOG.trace("Augmenting SSLSocketFactory configurers with configurers from client parameters on SSLContext [{}].",
315                          context);
316                configurers.addAll(this.getClientParameters().getSSLSocketFactoryConfigurers(context));
317            }
318            
319            LOG.trace("Collected SSLSocketFactory configurers on SSLContext [{}].", context);
320            
321            return configurers;
322        }
323    
324        @Override
325        protected List<Configurer<SSLServerSocketFactory>> getSSLServerSocketFactoryConfigurers(SSLContext context) {
326            LOG.trace("Collecting SSLServerSocketFactory configurers for SSLContext [{}]...", context);
327            List<Configurer<SSLServerSocketFactory>> configurers = super.getSSLServerSocketFactoryConfigurers(context);
328            
329            if (this.getServerParameters() != null) {
330                LOG.trace("Augmenting SSLServerSocketFactory configurers with configurers from server parameters for SSLContext [{}].",
331                          context);
332                configurers.addAll(this.getServerParameters().getSSLServerSocketFactoryConfigurers(context));
333            }
334            
335            LOG.trace("Collected client and server side SSLServerSocketFactory configurers for SSLContext [{}].", context);
336            
337            return configurers;
338        }
339    
340        @Override
341        public String toString() {
342            StringBuilder builder = new StringBuilder();
343            builder.append("SSLContextParameters [keyManagers=");
344            builder.append(keyManagers);
345            builder.append(", trustManagers=");
346            builder.append(trustManagers);
347            builder.append(", secureRandom=");
348            builder.append(secureRandom);
349            builder.append(", clientParameters=");
350            builder.append(clientParameters);
351            builder.append(", serverParameters=");
352            builder.append(serverParameters);
353            builder.append(", provider=");
354            builder.append(provider);
355            builder.append(", secureSocketProtocol=");
356            builder.append(secureSocketProtocol);
357            builder.append(", getCipherSuites()=");
358            builder.append(getCipherSuites());
359            builder.append(", getCipherSuitesFilter()=");
360            builder.append(getCipherSuitesFilter());
361            builder.append(", getSecureSocketProtocols()=");
362            builder.append(getSecureSocketProtocols());
363            builder.append(", getSecureSocketProtocolsFilter()=");
364            builder.append(getSecureSocketProtocolsFilter());
365            builder.append(", getSessionTimeout()=");
366            builder.append(getSessionTimeout());
367            builder.append(", getContext()=");
368            builder.append(getCamelContext());
369            builder.append("]");
370            return builder.toString();
371        }
372    }