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.support.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 * @param camelContext The camel context 246 * 247 * @return a newly configured instance 248 * 249 * @throws GeneralSecurityException if there is a problem in this instances 250 * configuration or that of its nested configuration options 251 * @throws IOException if there is an error reading a key/trust store 252 */ 253 public SSLContext createSSLContext(CamelContext camelContext) throws GeneralSecurityException, IOException { 254 if (camelContext != null) { 255 // setup CamelContext before creating SSLContext 256 setCamelContext(camelContext); 257 if (keyManagers != null) { 258 keyManagers.setCamelContext(camelContext); 259 } 260 if (trustManagers != null) { 261 trustManagers.setCamelContext(camelContext); 262 } 263 if (secureRandom != null) { 264 secureRandom.setCamelContext(camelContext); 265 } 266 if (clientParameters != null) { 267 clientParameters.setCamelContext(camelContext); 268 } 269 if (serverParameters != null) { 270 serverParameters.setCamelContext(camelContext); 271 } 272 } 273 274 LOG.trace("Creating SSLContext from SSLContextParameters [{}].", this); 275 276 LOG.info("Available providers: {}.", Security.getProviders()); 277 278 KeyManager[] keyManagers = this.keyManagers == null ? null : this.keyManagers.createKeyManagers(); 279 TrustManager[] trustManagers = this.trustManagers == null ? null : this.trustManagers.createTrustManagers(); 280 SecureRandom secureRandom = this.secureRandom == null ? null : this.secureRandom.createSecureRandom(); 281 282 SSLContext context; 283 if (this.getProvider() == null) { 284 context = SSLContext.getInstance(this.parsePropertyValue(this.getSecureSocketProtocol())); 285 } else { 286 context = SSLContext.getInstance(this.parsePropertyValue(this.getSecureSocketProtocol()), 287 this.parsePropertyValue(this.getProvider())); 288 } 289 290 if (this.getCertAlias() != null && keyManagers != null) { 291 for (int idx = 0; idx < keyManagers.length; idx++) { 292 if (keyManagers[idx] instanceof X509KeyManager) { 293 try { 294 keyManagers[idx] = new AliasedX509ExtendedKeyManager(this.getCertAlias(), 295 (X509KeyManager)keyManagers[idx]); 296 } catch (Exception e) { 297 throw new GeneralSecurityException(e); 298 } 299 } 300 } 301 } 302 303 LOG.debug("SSLContext [{}], initialized from [{}], is using provider [{}], protocol [{}], key managers {}, trust managers {}, and secure random [{}].", 304 new Object[] {context, this, context.getProvider(), context.getProtocol(), keyManagers, trustManagers, secureRandom}); 305 306 context.init(keyManagers, trustManagers, secureRandom); 307 308 this.configureSSLContext(context); 309 310 // Decorate the context. 311 context = new SSLContextDecorator( 312 new SSLContextSpiDecorator( 313 context, 314 this.getSSLEngineConfigurers(context), 315 this.getSSLSocketFactoryConfigurers(context), 316 this.getSSLServerSocketFactoryConfigurers(context))); 317 318 return context; 319 } 320 321 @Override 322 protected void configureSSLContext(SSLContext context) throws GeneralSecurityException { 323 LOG.trace("Configuring client and server side SSLContext parameters on SSLContext [{}]...", context); 324 super.configureSSLContext(context); 325 326 if (this.getClientParameters() != null) { 327 LOG.trace("Overriding client-side SSLContext parameters on SSLContext [{}] with configured client parameters.", 328 context); 329 this.getClientParameters().configureSSLContext(context); 330 } 331 332 if (this.getServerParameters() != null) { 333 LOG.trace("Overriding server-side SSLContext parameters on SSLContext [{}] with configured server parameters.", 334 context); 335 this.getServerParameters().configureSSLContext(context); 336 } 337 338 LOG.trace("Configured client and server side SSLContext parameters on SSLContext [{}].", context); 339 } 340 341 @Override 342 protected List<Configurer<SSLEngine>> getSSLEngineConfigurers(SSLContext context) { 343 LOG.trace("Collecting client and server side SSLEngine configurers on SSLContext [{}]...", context); 344 List<Configurer<SSLEngine>> configurers = super.getSSLEngineConfigurers(context); 345 346 if (this.getClientParameters() != null) { 347 LOG.trace("Augmenting SSLEngine configurers with configurers from client parameters on SSLContext [{}].", 348 context); 349 configurers.addAll(this.getClientParameters().getSSLEngineConfigurers(context)); 350 } 351 352 if (this.getServerParameters() != null) { 353 LOG.trace("Augmenting SSLEngine configurers with configurers from server parameters on SSLContext [{}].", 354 context); 355 configurers.addAll(this.getServerParameters().getSSLEngineConfigurers(context)); 356 } 357 358 LOG.trace("Collected client and server side SSLEngine configurers on SSLContext [{}].", context); 359 360 return configurers; 361 } 362 363 @Override 364 protected List<Configurer<SSLSocketFactory>> getSSLSocketFactoryConfigurers(SSLContext context) { 365 LOG.trace("Collecting SSLSocketFactory configurers on SSLContext [{}]...", context); 366 List<Configurer<SSLSocketFactory>> configurers = super.getSSLSocketFactoryConfigurers(context); 367 368 if (this.getClientParameters() != null) { 369 LOG.trace("Augmenting SSLSocketFactory configurers with configurers from client parameters on SSLContext [{}].", 370 context); 371 configurers.addAll(this.getClientParameters().getSSLSocketFactoryConfigurers(context)); 372 } 373 374 LOG.trace("Collected SSLSocketFactory configurers on SSLContext [{}].", context); 375 376 return configurers; 377 } 378 379 @Override 380 protected List<Configurer<SSLServerSocketFactory>> getSSLServerSocketFactoryConfigurers(SSLContext context) { 381 LOG.trace("Collecting SSLServerSocketFactory configurers for SSLContext [{}]...", context); 382 List<Configurer<SSLServerSocketFactory>> configurers = super.getSSLServerSocketFactoryConfigurers(context); 383 384 if (this.getServerParameters() != null) { 385 LOG.trace("Augmenting SSLServerSocketFactory configurers with configurers from server parameters for SSLContext [{}].", 386 context); 387 configurers.addAll(this.getServerParameters().getSSLServerSocketFactoryConfigurers(context)); 388 } 389 390 LOG.trace("Collected client and server side SSLServerSocketFactory configurers for SSLContext [{}].", context); 391 392 return configurers; 393 } 394 395 @Override 396 public String toString() { 397 StringBuilder builder = new StringBuilder(); 398 builder.append("SSLContextParameters[keyManagers="); 399 builder.append(keyManagers); 400 builder.append(", trustManagers="); 401 builder.append(trustManagers); 402 builder.append(", secureRandom="); 403 builder.append(secureRandom); 404 builder.append(", clientParameters="); 405 builder.append(clientParameters); 406 builder.append(", serverParameters="); 407 builder.append(serverParameters); 408 builder.append(", provider="); 409 builder.append(provider); 410 builder.append(", secureSocketProtocol="); 411 builder.append(secureSocketProtocol); 412 builder.append(", certAlias="); 413 builder.append(certAlias); 414 builder.append(", getCipherSuites()="); 415 builder.append(getCipherSuites()); 416 builder.append(", getCipherSuitesFilter()="); 417 builder.append(getCipherSuitesFilter()); 418 builder.append(", getSecureSocketProtocols()="); 419 builder.append(getSecureSocketProtocols()); 420 builder.append(", getSecureSocketProtocolsFilter()="); 421 builder.append(getSecureSocketProtocolsFilter()); 422 builder.append(", getSessionTimeout()="); 423 builder.append(getSessionTimeout()); 424 builder.append("]"); 425 return builder.toString(); 426 } 427 428}