001: /*
002: * BEGIN_HEADER - DO NOT EDIT
003: *
004: * The contents of this file are subject to the terms
005: * of the Common Development and Distribution License
006: * (the "License"). You may not use this file except
007: * in compliance with the License.
008: *
009: * You can obtain a copy of the license at
010: * https://open-esb.dev.java.net/public/CDDLv1.0.html.
011: * See the License for the specific language governing
012: * permissions and limitations under the License.
013: *
014: * When distributing Covered Code, include this CDDL
015: * HEADER in each file and include the License file at
016: * https://open-esb.dev.java.net/public/CDDLv1.0.html.
017: * If applicable add the following below this CDDL HEADER,
018: * with the fields enclosed by brackets "[]" replaced with
019: * your own identifying information: Portions Copyright
020: * [year] [name of copyright owner]
021: */
022:
023: /*
024: * @(#)SSLHelper.java
025: * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
026: *
027: * END_HEADER - DO NOT EDIT
028: */
029: /**
030: * SSLHelper.java
031: *
032: * SUN PROPRIETARY/CONFIDENTIAL.
033: * This software is the proprietary information of Sun Microsystems, Inc.
034: * Use is subject to license terms.
035: *
036: * Created on November 11, 2004, 7:15 PM
037: */package com.sun.jbi.internal.security.https;
038:
039: import com.sun.jbi.StringTranslator;
040:
041: import com.sun.jbi.binding.security.Context;
042: import com.sun.jbi.binding.security.Endpoint;
043: import com.sun.jbi.internal.security.KeyStoreManager;
044: import com.sun.jbi.internal.security.ContextImpl;
045: import com.sun.jbi.internal.security.SecurityService;
046:
047: import com.sun.jbi.internal.security.config.EndpointSecurityConfig;
048: import com.sun.jbi.internal.security.config.SecurityContext;
049:
050: import java.security.KeyManagementException;
051: import java.security.KeyStoreException;
052: import java.security.NoSuchAlgorithmException;
053: import java.security.UnrecoverableKeyException;
054:
055: import javax.net.ssl.KeyManagerFactory;
056: import javax.net.ssl.SSLContext;
057: import javax.net.ssl.TrustManagerFactory;
058: import javax.net.ssl.X509KeyManager;
059:
060: import java.util.logging.Logger;
061: import java.util.HashMap;
062: import java.util.Properties;
063:
064: /**
065: * This is a internal helper class which is created by the SecurityHandler. The
066: * The SecurityHandler creates this class during its initialization, this class gets
067: * a handle to the SecurityHandler, which can be used to get the Installtime Security
068: * configuration, UserManager, KeyStoreManager etc.
069: *
070: * This class is used by the HttpSecurityHandler for creation of the SSL Contexts. The
071: * DeploymentListener notifies this class of Endpoint deployments and Undeployments, the
072: * SSL helper gets the deployment time Security Context from these deployments.
073: *
074: * @author Sun Microsystems, Inc.
075: */
076: public class SSLHelper implements
077: com.sun.jbi.internal.security.DeploymentObserver {
078:
079: /** The Logger. */
080: private Logger mLogger;
081:
082: /** The map which contains endpointKey -> TlsContexts. */
083: private HashMap mEndptTlsCtxs;
084:
085: /** String Translator.
086: */
087: private StringTranslator mTranslator;
088:
089: /**
090: * Creates a new instance of SSLHelper.
091: *
092: */
093: public SSLHelper() {
094: mTranslator = SecurityService
095: .getStringTranslator(HttpConstants.PACKAGE);
096: mLogger = Logger
097: .getLogger(com.sun.jbi.internal.security.Constants.PACKAGE);
098: mEndptTlsCtxs = new HashMap();
099: }
100:
101: /**
102: * Add an endpoint deployment. The deployment time security configuration is
103: * combined with the install time security configuration and based on the result a
104: * SSL Context is created for the endpoint. The endpoint deployment configuration
105: * overrides the installtime security configuration.
106: *
107: *
108: * @param endpoint is the Endpoint being deployed
109: * @param epSecConfig is the Security Configuration for the deployed endpoint.
110: * @throws Exception on errors
111: */
112: public void registerEndpointDeployment(Endpoint endpoint,
113: EndpointSecurityConfig epSecConfig) throws Exception {
114: // -- Get the Security Context used by the endpoint
115: SecurityContext deplSecCtx = epSecConfig.getSecurityContext();
116:
117: // -- System Transport Security Ctx
118: Properties instCtx = SecurityService
119: .getTransportSecurityContext();
120:
121: // -- Get the KeyStoreManager configured for the Endpoint
122: KeyStoreManager ksMgr = SecurityService
123: .getKeyStoreManager(deplSecCtx.getKeyStoreManagerName());
124:
125: if (ksMgr == null) {
126: mLogger.info(mTranslator.getString(
127: HttpConstants.BC_INFO_KSMGR_USED, endpoint
128: .getEndpointName(), SecurityService
129: .getDefaultKeyStoreManagerName()));
130: ksMgr = SecurityService.getDefaultKeyStoreManager();
131: } else {
132: mLogger.info(mTranslator.getString(
133: HttpConstants.BC_INFO_KSMGR_USED, endpoint
134: .getEndpointName(), deplSecCtx
135: .getKeyStoreManagerName()));
136: }
137:
138: // -- Merge with the deplSecCtx
139: TlsContext tlsCtx = createTlsContext(mergeContexts(instCtx,
140: deplSecCtx), ksMgr);
141:
142: // -- Add to registry
143: mLogger.info(mTranslator.getString(
144: HttpConstants.BC_INFO_CREATE_TLS_CTX, endpoint
145: .getEndpointName(), endpoint.getServiceName()
146: .getLocalPart(), endpoint.getServiceName()
147: .getNamespaceURI()));
148: mEndptTlsCtxs.put(getKey(endpoint), tlsCtx);
149: }
150:
151: /**
152: * Unregister an Endpoint deployment.
153: *
154: * @param endpoint is the Endpoint being undeployed
155: */
156: public void unregisterEndpointDeployment(Endpoint endpoint) {
157: mEndptTlsCtxs.remove(getKey(endpoint));
158: }
159:
160: /**
161: * Merge the Contexts
162: *
163: * @param instCtx is the Installation time Security Context.
164: * @param deplCtx is the Deployment time Security Context
165: * @return the merged contexts, deployment context overrides install context.
166: */
167: private Context mergeContexts(Properties instCtx, Context deplCtx) {
168: Context newCtx = new ContextImpl(SecurityService
169: .getStringTranslator(HttpConstants.MAIN_PACKAGE));
170:
171: newCtx.setValue(HttpConstants.PARAM_SSL_USE_DEFAULT,
172: new Boolean(getValue(
173: HttpConstants.PARAM_SSL_USE_DEFAULT, instCtx,
174: deplCtx, true)));
175:
176: newCtx.setValue(HttpConstants.PARAM_SSL_PROTOCOL, getValue(
177: HttpConstants.PARAM_SSL_PROTOCOL, instCtx, deplCtx,
178: HttpConstants.DEFAULT_SSL_PROTOCOL));
179:
180: newCtx.setValue(HttpConstants.PARAM_SSL_REQ_CLIENT_AUTH,
181: new Boolean(getValue(
182: HttpConstants.PARAM_SSL_REQ_CLIENT_AUTH,
183: instCtx, deplCtx,
184: HttpConstants.DEFAULT_SSL_REQ_CLIENT_AUTH)));
185:
186: newCtx.setValue(HttpConstants.PARAM_SSL_CLIENT_ALIAS, getValue(
187: HttpConstants.PARAM_SSL_CLIENT_ALIAS, instCtx, deplCtx,
188: HttpConstants.DEFAULT_CLIENT_ALIAS));
189:
190: newCtx.setValue(HttpConstants.PARAM_SSL_CLIENT_ALIAS_PASSWD,
191: getValue(HttpConstants.PARAM_SSL_CLIENT_ALIAS_PASSWD,
192: instCtx, deplCtx,
193: HttpConstants.DEFAULT_CLIENT_ALIAS_PWD));
194:
195: newCtx.print(mLogger, java.util.logging.Level.FINEST);
196: return newCtx;
197: }
198:
199: /**
200: * Get the value for a particular key from the depl ctx, if not specified
201: * then get it from the install ctx, if not specified use default.
202: *
203: * @param key is the Key whose value is required.
204: * @param instCtx is the Installation time Security Context.
205: * @param deplCtx is the Deployment time Security Context
206: * @param defVal is the default value that applies if the key is not found
207: * @return the required value for the key.
208: */
209: private boolean getValue(String key, Properties instCtx,
210: Context deplCtx, boolean defVal) {
211: if (deplCtx.containsKey(key)) {
212: return new Boolean((String) deplCtx.getValue(key))
213: .booleanValue();
214: }
215:
216: if (instCtx.containsKey(key)) {
217: return new Boolean(instCtx.getProperty(key)).booleanValue();
218: }
219:
220: return defVal;
221:
222: }
223:
224: /**
225: * Get the value for a particular key from the depl ctx, if not specified
226: * then get it from the install ctx, if not specified use default.
227: *
228: * @param key is the Key whose value is required.
229: * @param instCtx is the Installation time Security Context.
230: * @param deplCtx is the Deployment time Security Context
231: * @param defVal is the Default value that applies
232: * @return the required value for the key.
233: */
234: private String getValue(String key, Properties instCtx,
235: Context deplCtx, String defVal) {
236: if (deplCtx.containsKey(key)) {
237: return (String) deplCtx.getValue(key);
238: }
239:
240: if (instCtx.containsKey(key)) {
241: return instCtx.getProperty(key);
242: }
243:
244: return defVal;
245:
246: }
247:
248: /**
249: * Get a Key based on the endpoint
250: * @return the Key generated from the Endpoint. The Key is of the
251: * form TargetNamespace:Service:Endpoint
252: * @param endpt is the Endpoint
253: */
254: private String getKey(Endpoint endpt) {
255: StringBuffer strBuffer = new StringBuffer();
256: String separator = ":";
257: if (endpt != null) {
258: strBuffer.append(endpt.getServiceName().getNamespaceURI());
259: strBuffer.append(separator);
260: strBuffer.append(endpt.getServiceName().getLocalPart()
261: .trim());
262: strBuffer.append(separator);
263: strBuffer.append(endpt.getEndpointName().trim());
264: }
265:
266: return strBuffer.toString();
267: }
268:
269: /**
270: * Create and initialize an SSL Context for the Endpoint
271: * @return a TlsContext initialized with the appropriate SSLContext
272: * @param secCtx is the merged Security Context for the endpoint
273: * @param ksMgr is the KeyStoreManager
274: */
275: private TlsContext createTlsContext(Context secCtx,
276: KeyStoreManager ksMgr) {
277: boolean useDefaultSSLCtx = ((Boolean) secCtx
278: .getValue(HttpConstants.PARAM_SSL_USE_DEFAULT))
279: .booleanValue();
280:
281: SSLContext sslc = null;
282: if (!useDefaultSSLCtx) {
283: try {
284: sslc = createSSLContext(secCtx, ksMgr);
285: } catch (Exception ex) {
286: // -- If any problem occurs log a warning and use the default
287: mLogger.warning(mTranslator.getString(
288: HttpConstants.BC_ERR_SSL_CTX_FAIL_USE_DEFAULT,
289: ex.toString()));
290: // -- ex.printStackTrace();
291: sslc = null;
292: }
293: }
294: return new TlsContext(sslc, ((Boolean) secCtx
295: .getValue(HttpConstants.PARAM_SSL_REQ_CLIENT_AUTH))
296: .booleanValue(), ksMgr);
297: }
298:
299: /**
300: * Create a SSL Context as required by the Endpoint
301: *
302: * @param ksMgr is the KeyStoreManager
303: * @param secCtx is the Security Context to be used for creating the SSLContext.
304: * @throws NoSuchAlgorithmException if algorithm incorrect
305: * @throws KeyManagementException on key management problems
306: * @throws KeyStoreException on KeyStore related errors.
307: * @throws UnrecoverableKeyException if a key cannot be obtained from any
308: * of the KeyStores.
309: * @return the newly created SSLContext.
310: */
311: private SSLContext createSSLContext(Context secCtx,
312: KeyStoreManager ksMgr) throws NoSuchAlgorithmException,
313: KeyManagementException, KeyStoreException,
314: UnrecoverableKeyException {
315: KeyManagerFactory kmf = null;
316: TrustManagerFactory tmf = null;
317: try {
318: kmf = KeyManagerFactory
319: .getInstance(HttpConstants.DEFAULT_KEY_MANAGEMENT_ALGO);
320: tmf = TrustManagerFactory
321: .getInstance(HttpConstants.DEFAULT_KEY_MANAGEMENT_ALGO);
322: } catch (NoSuchAlgorithmException ex) {
323: mLogger.severe(mTranslator.getString(
324: HttpConstants.BC_ERR_KEYMGMT_ALGO_NOT_SUPPORTED,
325: HttpConstants.DEFAULT_KEY_MANAGEMENT_ALGO));
326: throw ex;
327: }
328: SSLContext sslc = null;
329: try {
330:
331: tmf.init(getTrustStore(ksMgr));
332:
333: if (HttpConstants.DEFAULT_CLIENT_ALIAS.equals(secCtx
334: .getValue(HttpConstants.PARAM_SSL_CLIENT_ALIAS))) {
335: // -- The Client SSL socket uses any client key pair for Client auth.
336:
337: // -- If the Key Store Manager is directly hooked into the App Srv. Env
338: // -- use the default SSL context.
339: if (ksMgr.getType() == KeyStoreManager.SJSAS) {
340: return sslc;
341: } else // -- Create a new SSL Context and init it with the key/trust info
342: {
343: sslc = SSLContext
344: .getInstance((String) secCtx
345: .getValue(HttpConstants.PARAM_SSL_PROTOCOL));
346: kmf.init(ksMgr.getKeyStore(), ksMgr
347: .getKeyStorePassword().toCharArray());
348: sslc.init(kmf.getKeyManagers(), tmf
349: .getTrustManagers(), null);
350: }
351: } else {
352: String clientAlias = (String) secCtx
353: .getValue(HttpConstants.PARAM_SSL_CLIENT_ALIAS);
354: mLogger.fine(mTranslator.getString(
355: HttpConstants.BC_INFO_CLIENT_AUTH_DETAILS,
356: clientAlias, ksMgr.getName(), ksMgr.getType()));
357: sslc = SSLContext.getInstance((String) secCtx
358: .getValue(HttpConstants.PARAM_SSL_PROTOCOL));
359: X509KeyManager[] keyManagers = { new SSLClientKeyManager(
360: ksMgr, clientAlias, mTranslator), };
361: sslc.init(keyManagers, tmf.getTrustManagers(), null);
362: }
363: } catch (KeyStoreException ksex) {
364: mLogger.warning(mTranslator.getString(
365: HttpConstants.BC_ERR_SSL_CONTEXT_CREATION_FAILED,
366: ksex.toString()));
367: throw ksex;
368: } catch (KeyManagementException kmex) {
369: mLogger.warning(mTranslator.getString(
370: HttpConstants.BC_ERR_SSL_CONTEXT_CREATION_FAILED,
371: kmex.toString()));
372: throw kmex;
373: }
374:
375: return sslc;
376: }
377:
378: /**
379: * Get the TlsContext for a Endpoint.
380: *
381: * @param endpoint is the Endpoint whose TLS Context is to be obtained.
382: * @return a TlsContext for an Endpoint, returns null if the Endpoint has not been
383: * registered.
384: */
385: public TlsContext getTlsContext(Endpoint endpoint) {
386: return (TlsContext) mEndptTlsCtxs.get(getKey(endpoint));
387: }
388:
389: /**
390: * Get the TrustStore for initializing the TrustStoreManager.
391: *
392: * @param ksMgr is the KeyStoreManager
393: * @return the TrustStore handle.
394: * @throws KeyStoreException if the truststore cannot be obtained.
395: */
396: private java.security.KeyStore getTrustStore(KeyStoreManager ksMgr)
397: throws KeyStoreException {
398: try {
399: // -- Create a TrustStore Callback
400: // -- Ask the ksMgr to handle it
401: com.sun.enterprise.security.jauth.callback.TrustStoreCallback tsCB = new com.sun.enterprise.security.jauth.callback.TrustStoreCallback();
402: ksMgr
403: .handle(new javax.security.auth.callback.Callback[] { tsCB });
404:
405: // -- Get back the Trust Store and return it
406: return tsCB.getTrustStore();
407:
408: } catch (Exception ex) {
409: throw new KeyStoreException(ex.toString());
410: }
411: }
412:
413: }
|