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