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: * @(#)SecurityProcessor.java
025: * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
026: *
027: * END_HEADER - DO NOT EDIT
028: */
029: /**
030: * SecurityProcessor.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: */package com.sun.jbi.internal.security.msg;
037:
038: // -- Pre-JSR 196 classes
039: import com.sun.enterprise.security.jauth.AuthConfig;
040: import com.sun.enterprise.security.jauth.AuthParam;
041: import com.sun.enterprise.security.jauth.SOAPAuthParam;
042: import com.sun.enterprise.security.jauth.ClientAuthContext;
043: import com.sun.enterprise.security.jauth.ServerAuthContext;
044:
045: import com.sun.jbi.internal.security.ComponentContext;
046: import com.sun.jbi.StringTranslator;
047: import com.sun.jbi.binding.security.Endpoint;
048: import com.sun.jbi.binding.security.MessageContext;
049: import com.sun.jbi.binding.security.MessageHandlerException;
050: import com.sun.jbi.binding.security.Interceptor;
051:
052: import com.sun.jbi.internal.security.config.EndpointInfo;
053: import com.sun.jbi.internal.security.config.EndpointInfoImpl;
054: import com.sun.jbi.internal.security.config.EndpointSecurityConfig;
055: import com.sun.jbi.internal.security.config.MessageSecPolicy;
056:
057: import com.sun.jbi.internal.security.KeyStoreManager;
058: import com.sun.jbi.internal.security.UserDomain;
059: import com.sun.jbi.internal.security.Constants;
060: import com.sun.jbi.internal.security.DeploymentObserver;
061: import com.sun.jbi.internal.security.LocalStringConstants;
062: import com.sun.jbi.internal.security.ThreadLocalContext;
063:
064: import java.util.logging.Logger;
065: import java.util.HashMap;
066: import javax.security.auth.Subject;
067:
068: /**
069: * Implementation of the Deployment Listener and Interceptor.
070: *
071: * @author Sun Microsystems, Inc.
072: */
073: public class SecurityProcessor implements DeploymentObserver,
074: Interceptor {
075:
076: /**
077: * Client Auth Modules
078: */
079: private HashMap mClientAuthContexts;
080:
081: /**
082: * Server Auth Modules
083: */
084: private HashMap mServerAuthContexts;
085:
086: /** The Logger */
087: private Logger mLogger = null;
088:
089: /** The Component Context. */
090: private ComponentContext mCmpCtx;
091:
092: /** The StringTranslator Used for getting localized strings. */
093: private StringTranslator mTranslator;
094:
095: /** The AuthType. */
096: private String mAuthType;
097:
098: /**
099: * Creates a new instance of SecurityProcessor.
100: *
101: * @param cmpCtx is the ComponentContext
102: */
103: public SecurityProcessor(ComponentContext cmpCtx) {
104: this (cmpCtx, "SOAP");
105: }
106:
107: /**
108: * Creates a new instance of SecurityProcessor.
109: *
110: * @param cmpCtx is the ComponentContext
111: * @param authLayer is the authnetication layer ( ex. SOAP )
112: */
113: public SecurityProcessor(ComponentContext cmpCtx, String authLayer) {
114: mLogger = Logger
115: .getLogger(com.sun.jbi.internal.security.Constants.PACKAGE);
116:
117: mAuthType = authLayer;
118: mClientAuthContexts = new HashMap();
119: mServerAuthContexts = new HashMap();
120: mCmpCtx = cmpCtx;
121: mTranslator = cmpCtx.getStringTranslator(Constants.PACKAGE);
122: }
123:
124: /**
125: * Process an incoming message. For an Inbound endpoint the incoming message is
126: * a request being sent to invoke a particular operation in a Service. For an
127: * Outbound endpoint the incoming message is a Response to a earlier message.
128: *
129: * @param endpoint is the deployed Endpoint which is the sink of the Message
130: * @param operation is the operation being invoked
131: * @param subject is the Subject to be updated with the senders Identity.
132: * @param msgCtx is the MessageContext which is a wrapper around the message.
133: * @throws MessageHandlerException on Errors
134: */
135: public void processIncomingMessage(final Endpoint endpoint,
136: final String operation, final MessageContext msgCtx,
137: final Subject subject) throws MessageHandlerException {
138: try {
139: // -- Run in the Security Service Protection domain.
140: java.security.AccessController
141: .doPrivileged(new java.security.PrivilegedExceptionAction() {
142: /**
143: * @return null
144: * @throws MessageHandlerException on execution errors.
145: */
146: public Object run() throws Exception {
147: privProcessIncomingMessage(endpoint,
148: operation, msgCtx, subject);
149: return null;
150: }
151: });
152: } catch (java.security.PrivilegedActionException pex) {
153: throw (MessageHandlerException) pex.getException();
154: }
155: }
156:
157: /**
158: * Process an incoming message. For an Inbound endpoint the incoming message is
159: * a request being sent to invoke a particular operation in a Service. For an
160: * Outbound endpoint the incoming message is a Response to a earlier message.
161: *
162: * @param endpoint is the deployed Endpoint which is the sink of the Message
163: * @param operation is the operation being invoked
164: * @param subject is the Subject to be updated with the senders Identity.
165: * @param msgCtx is the MessageContext which is a wrapper around the message.
166: * @throws MessageHandlerException on Errors
167: */
168: private void privProcessIncomingMessage(Endpoint endpoint,
169: String operation, MessageContext msgCtx, Subject subject)
170: throws MessageHandlerException {
171:
172: // -- If the Subject is null, create a new one and set it on the thread ctx
173: // -- this way JAAS Authenticator updates the same subject
174: if (subject == null) {
175: if (ThreadLocalContext.getLocalSubject() != null) {
176: // -- This is an incoming request over HTTPS with Client Auth
177: subject = ThreadLocalContext.getLocalSubject();
178: } else {
179: subject = new Subject();
180: }
181: }
182: ThreadLocalContext.setLocalSubject(subject);
183:
184: HashMap options = new HashMap();
185: try {
186: if (endpoint.getRole() == javax.jbi.messaging.MessageExchange.Role.CONSUMER) {
187: mLogger
188: .finest("Retrieving a Server Auth Context for Endpoint "
189: + endpoint.getEndpointName()
190: + ":"
191: + endpoint.getServiceName().toString()
192: + " and operation " + operation);
193: ServerAuthContext authModule = (ServerAuthContext) mServerAuthContexts
194: .get(getKey(endpoint, operation));
195:
196: if (authModule != null) {
197: AuthParam authParam = getAuthParam(msgCtx, true);
198: authModule.validateRequest(authParam, subject,
199: options);
200: checkAuthParamForResponse(authParam, msgCtx);
201:
202: } else {
203: mLogger
204: .finest("No Server Auth Context defined for Endpoint "
205: + endpoint.getEndpointName()
206: + ":"
207: + endpoint.getServiceName()
208: .toString()
209: + " and operation " + operation);
210: }
211:
212: } else {
213: mLogger
214: .finest("Retrieving a Client Auth Context for Endpoint "
215: + endpoint.getEndpointName()
216: + ":"
217: + endpoint.getServiceName().toString()
218: + " and operation " + operation);
219: ClientAuthContext authModule = (ClientAuthContext) mClientAuthContexts
220: .get(getKey(endpoint, operation));
221:
222: if (authModule != null) {
223: AuthParam authParam = getAuthParam(msgCtx, false);
224: authModule.validateResponse(authParam, subject,
225: options);
226: checkAuthParamForResponse(authParam, msgCtx);
227: } else {
228: mLogger
229: .finest("No Client Auth Context defined for Endpoint "
230: + endpoint.getEndpointName()
231: + ":"
232: + endpoint.getServiceName()
233: .toString()
234: + " and operation " + operation);
235: }
236: }
237: } catch (Exception ex) {
238: ex.printStackTrace();
239: String errMsg = mTranslator
240: .getString(
241: LocalStringConstants.ERR_PROCESSING_INCOMING_MESSAGE,
242: new Object[] {
243: endpoint.getEndpointName(),
244: endpoint.getServiceName()
245: .toString(),
246: ex.getMessage(), });
247:
248: mLogger.severe(errMsg);
249:
250: throw new MessageHandlerException(errMsg, ex);
251: }
252: }
253:
254: /**
255: * Process an incoming message. For an Inbound endpoint the incoming message is
256: * a request being sent to invoke a particular operation in a Service. For an
257: * Outbound endpoint the incoming message is a Response to a earlier message.
258: *
259: * @param endpoint is the deployed Endpoint which is the sink of the Message
260: * @param operation is the operation being invoked
261: * @param subject is the Subject which identifies the Sender.
262: * @param msgCtx is the MessageContext which is a wrapper around the message.
263: * @throws MessageHandlerException on Errors
264: */
265: public void processOutgoingMessage(final Endpoint endpoint,
266: final String operation, final MessageContext msgCtx,
267: final Subject subject) throws MessageHandlerException {
268: try {
269: // -- Run in the Security Service Protection domain.
270: java.security.AccessController
271: .doPrivileged(new java.security.PrivilegedExceptionAction() {
272: /**
273: * @return null
274: * @throws MessageHandlerException on execution errors.
275: */
276: public Object run() throws Exception {
277: privProcessOutgoingMessage(endpoint,
278: operation, msgCtx, subject);
279: return null;
280: }
281: });
282: } catch (java.security.PrivilegedActionException pex) {
283: throw (MessageHandlerException) pex.getException();
284: }
285: }
286:
287: /**
288: * Process an outbound message. For an Inbound endpoint the outgoind message is
289: * a response being sent to an earlier request to the Endpoint to invoke a particular
290: * operation in a Service. For an Outbound endpoint the outbound message is a Request
291: * being sent to a remote Service to invoke a operation.
292: *
293: * @param endpoint is the deployed Endpoint which is the source of the Message
294: * @param operation is the operation being invoked
295: * @param subj is the Subject which identifies the Sender.
296: * @param msgCtx is the MessageContext which is a wrapper around the message.
297: * @throws MessageHandlerException on Errors
298: */
299: private void privProcessOutgoingMessage(Endpoint endpoint,
300: String operation, MessageContext msgCtx, Subject subj)
301: throws MessageHandlerException {
302: ThreadLocalContext.setLocalSubject(subj);
303:
304: HashMap options = new HashMap();
305: try {
306: if (endpoint.getRole() == javax.jbi.messaging.MessageExchange.Role.CONSUMER) {
307: mLogger
308: .finest("Retrieving a Server Auth Module for Endpoint "
309: + endpoint.getEndpointName()
310: + ":"
311: + endpoint.getServiceName().toString()
312: + " and operation " + operation);
313: ServerAuthContext authModule = (ServerAuthContext) mServerAuthContexts
314: .get(getKey(endpoint, operation));
315:
316: if (authModule != null) {
317: authModule.secureResponse(getAuthParam(msgCtx,
318: false), subj, options);
319: } else {
320: mLogger
321: .finest("No Server Auth Context defined for Endpoint "
322: + endpoint.getEndpointName()
323: + ":"
324: + endpoint.getServiceName()
325: .toString()
326: + " and operation " + operation);
327: }
328: } else {
329: mLogger
330: .finest("Retrieving a Client Auth Context for Endpoint "
331: + endpoint.getEndpointName()
332: + ":"
333: + endpoint.getServiceName().toString()
334: + " and operation " + operation);
335: ClientAuthContext authModule = (ClientAuthContext) mClientAuthContexts
336: .get(getKey(endpoint, operation));
337:
338: if (authModule != null) {
339: authModule.secureRequest(
340: getAuthParam(msgCtx, true), subj, options);
341: } else {
342: mLogger
343: .finest("No Client Auth Context defined for Endpoint "
344: + endpoint.getEndpointName()
345: + ":"
346: + endpoint.getServiceName()
347: .toString()
348: + " and operation " + operation);
349: }
350: }
351: } catch (Exception ex) {
352: ex.printStackTrace();
353: String errMsg = mTranslator
354: .getString(
355: LocalStringConstants.ERR_PROCESSING_OUTGOING_MESSAGE,
356: new Object[] {
357: endpoint.getEndpointName(),
358: endpoint.getServiceName()
359: .toString(),
360: ex.getMessage(), });
361: mLogger.severe(errMsg);
362:
363: throw new MessageHandlerException(errMsg, ex);
364: }
365: }
366:
367: /**
368: * Unregister an Endpoint deployment.
369: *
370: * @param endpoint is the Endpoint being undeployed
371: */
372: public void unregisterEndpointDeployment(Endpoint endpoint) {
373:
374: java.util.Iterator opItr = endpoint.getOperationNames();
375: while (opItr.hasNext()) {
376: String opName = (String) opItr.next();
377: if (endpoint.getRole() == javax.jbi.messaging.MessageExchange.Role.CONSUMER) {
378: mServerAuthContexts.remove(getKey(endpoint, opName));
379: mServerAuthContexts.remove(getKey(endpoint,
380: Constants.DEFAULT_OPERATION_NAME));
381: } else {
382: mClientAuthContexts.remove(getKey(endpoint, opName));
383: mClientAuthContexts.remove(getKey(endpoint,
384: Constants.DEFAULT_OPERATION_NAME));
385: }
386: }
387: }
388:
389: /**
390: * Register an endpoint deployment.
391: *
392: * @param endpoint is the Endpoint being deployed.
393: * @param epDeployConfig is the Endpoint Security Configuration.
394: * @throws Exception on Errors.
395: */
396: public void registerEndpointDeployment(final Endpoint endpoint,
397: final EndpointSecurityConfig epDeployConfig)
398: throws Exception {
399: try {
400: // -- Run in the Security Service Protection domain.
401: java.security.AccessController
402: .doPrivileged(new java.security.PrivilegedExceptionAction() {
403: /**
404: * @return null
405: * @throws MessageHandlerException on execution errors.
406: */
407: public Object run() throws Exception {
408: privRegisterEndpointDeployment(endpoint,
409: epDeployConfig);
410: return null;
411: }
412: });
413: } catch (java.security.PrivilegedActionException pex) {
414: throw (Exception) pex.getException();
415: }
416: }
417:
418: /**
419: * Register an endpoint deployment.
420: *
421: * @param endpoint is the Endpoint being deployed.
422: * @param epDeployConfig is the Endpoint Security Configuration.
423: * @throws Exception on Errors.
424: */
425: private void privRegisterEndpointDeployment(Endpoint endpoint,
426: EndpointSecurityConfig epDeployConfig) throws Exception {
427: // -- Create the CallbackHandler based on the deployment config
428: javax.security.auth.callback.CallbackHandler handler = createCallbackHandler(epDeployConfig
429: .getSecurityContext());
430:
431: // -- Get the AuthModule Factory
432: AuthConfig factory = AuthContextFactoryLocator
433: .getAuthContextFactory();
434:
435: // -- Create and cache the handler for each endpoint operation
436: java.util.Iterator opItr = endpoint.getOperationNames();
437: while (opItr.hasNext()) {
438: String opName = (String) opItr.next();
439:
440: MessageSecPolicy appPolicy = getMsgSecPolicy(endpoint,
441: epDeployConfig, opName);
442:
443: // -- Determine the Provider Id to be used, order of priority
444: // 1. Operation Level Provider Id
445: // 2. Endpoint Level Provider Id
446: // 3. Default Container Provider Id.
447: String providerId = (appPolicy.getMessageProviderId() == null ? epDeployConfig
448: .getSecurityContext().getMessageProviderId()
449: : appPolicy.getMessageProviderId());
450:
451: if (endpoint.getRole() == javax.jbi.messaging.MessageExchange.Role.CONSUMER) {
452:
453: mLogger
454: .finest("Registering a Server Auth Context for Endpoint "
455: + endpoint.getEndpointName()
456: + " in Service "
457: + endpoint.getServiceName().toString()
458: + " with provider id " + providerId);
459: mServerAuthContexts.put(getKey(endpoint, opName),
460: factory.getServerAuthContext(mAuthType,
461: providerId, appPolicy
462: .getRequestPolicy(), appPolicy
463: .getResponsePolicy(), handler));
464: } else {
465: mLogger
466: .finest("Registering a Client Auth Context for Endpoint "
467: + endpoint.getEndpointName()
468: + " in Service "
469: + endpoint.getServiceName().toString()
470: + " with provider id " + providerId);
471:
472: // -- There seems to be a bug in AS, AuthConfig does not return
473: // -- the default ClientProvider even when it has been configured
474: mClientAuthContexts.put(getKey(endpoint, opName),
475: factory.getClientAuthContext(mAuthType,
476: providerId, appPolicy
477: .getRequestPolicy(), appPolicy
478: .getResponsePolicy(), handler));
479: }
480:
481: }
482:
483: // -- Add the default operation
484: MessageSecPolicy appPolicy = getMsgSecPolicy(endpoint,
485: epDeployConfig, Constants.DEFAULT_OPERATION_NAME);
486:
487: // -- Determine the Provider Id to be used, order of priority
488: // 1. Operation Level Provider Id
489: // 2. Endpoint Level Provider Id
490: // 3. Default Container Provider Id.
491: String providerId = (appPolicy.getMessageProviderId() == null ? epDeployConfig
492: .getSecurityContext().getMessageProviderId()
493: : appPolicy.getMessageProviderId());
494:
495: if (endpoint.getRole() == javax.jbi.messaging.MessageExchange.Role.CONSUMER) {
496: mServerAuthContexts.put(getKey(endpoint,
497: Constants.DEFAULT_OPERATION_NAME), factory
498: .getServerAuthContext(mAuthType, providerId,
499: appPolicy.getRequestPolicy(), appPolicy
500: .getResponsePolicy(), handler));
501: } else {
502: mClientAuthContexts.put(getKey(endpoint,
503: Constants.DEFAULT_OPERATION_NAME), factory
504: .getClientAuthContext(mAuthType, providerId,
505: appPolicy.getRequestPolicy(), appPolicy
506: .getResponsePolicy(), handler));
507: }
508: }
509:
510: /**
511: * Get a Key based on operation and endpoint
512: * @return the Key generated from the Endpoint. The Key is of the
513: * form TargetNamespace:Service:Endpoint:Operation
514: * @param endpt is the Endpoint
515: * @param operation is the operation
516: */
517: private String getKey(Endpoint endpt, String operation) {
518: StringBuffer strBuffer = new StringBuffer();
519: String separator = ":";
520: strBuffer.append(endpt.getServiceName().getNamespaceURI());
521: strBuffer.append(separator);
522: strBuffer.append(endpt.getServiceName().getLocalPart().trim());
523: strBuffer.append(separator);
524: strBuffer.append(endpt.getEndpointName().trim());
525: strBuffer.append(separator);
526: strBuffer.append(operation);
527:
528: return strBuffer.toString();
529: }
530:
531: /**
532: * @param deplSecCtx is the deployment Security Context.
533: * @return the CallbackHandler instance. If the SecurityService has not been
534: * initialized this method returns null.
535: */
536: public javax.security.auth.callback.CallbackHandler createCallbackHandler(
537: com.sun.jbi.internal.security.config.SecurityContext deplSecCtx) {
538: if (com.sun.jbi.internal.security.SecurityService
539: .getSecurityConfiguration() != null) {
540:
541: // -- KeyManagement Environment
542: KeyStoreManager kmgr = com.sun.jbi.internal.security.SecurityService
543: .getKeyStoreManager(deplSecCtx
544: .getKeyStoreManagerName());
545: kmgr = ((kmgr == null) ? com.sun.jbi.internal.security.SecurityService
546: .getDefaultKeyStoreManager()
547: : kmgr);
548:
549: // -- UserDomain, Authenticator
550: UserDomain ud = com.sun.jbi.internal.security.SecurityService
551: .getUserDomain(deplSecCtx.getUserDomainName());
552:
553: ud = ((ud == null) ? com.sun.jbi.internal.security.SecurityService
554: .getDefaultUserDomain()
555: : ud);
556:
557: // -- create the Authenticator and pass it to the CallbackHandler
558: com.sun.jbi.internal.security.auth.Authenticator ator = com.sun.jbi.internal.security.auth.AuthenticatorFactory
559: .createAuthenticator(ud);
560:
561: return new com.sun.jbi.internal.security.callback.ProxyCallbackHandler(
562: kmgr, ator);
563:
564: }
565: return null;
566: }
567:
568: /**
569: * Determine Message Security Policy
570: *
571: * @param ep is the Endpoint whose security policy is to be determined.
572: * @param epConfig is the Endpoint deployment Security Configuration.
573: * @param opName is the operation name.
574: * @return the MessageSecPolicy for the Endpoint / operation
575: * @throws Exception on errors
576: */
577: private MessageSecPolicy getMsgSecPolicy(Endpoint ep,
578: EndpointSecurityConfig epConfig, String opName)
579: throws Exception {
580: EndpointInfo depEp = new EndpointInfoImpl(ep);
581:
582: if (epConfig.getEndpointInfo() == null) {
583: // -- This is a default configuration, not specific to any endpoint
584: // -- the message security policy is that of the container.
585: return epConfig.getDefaultMessagePolicy();
586: }
587:
588: if (!epConfig.getEndpointInfo().equals(depEp)) {
589: throw new Exception(mTranslator.getString(
590: LocalStringConstants.BC_ERR_INVALID_DEPL_CONFIG,
591:
592: "{"
593: + epConfig.getEndpointInfo()
594: .getTargetNamespace()
595: + "}"
596: + ":"
597: + epConfig.getEndpointInfo()
598: .getServiceName() + ":"
599: + epConfig.getEndpointInfo().getName(),
600:
601: "{" + depEp.getTargetNamespace() + "}" + ":"
602: + depEp.getServiceName() + ":"
603: + depEp.getName()));
604: }
605:
606: MessageSecPolicy resPolicy = epConfig.getMessagePolicy(opName);
607:
608: // -- Get the default Endpoint Policy if one is defined
609: if (resPolicy == null) {
610: resPolicy = epConfig
611: .getMessagePolicy(Constants.DEFAULT_OPERATION_NAME);
612: }
613:
614: // -- The Container Level Policy applies.
615: if (resPolicy == null) {
616: resPolicy = epConfig.getDefaultMessagePolicy();
617: }
618:
619: return resPolicy;
620: }
621:
622: /**
623: * Create a request AuthParam from the MessageContext.
624: *
625: * @param msgCtx is the MessageContext.
626: * @param isRequest indicates whether the auth param is for a request or response.
627: * @return the AuthParam
628: */
629: private AuthParam getAuthParam(MessageContext msgCtx,
630: boolean isRequest) {
631: if (mAuthType.equals("SOAP")) {
632: if (isRequest) {
633: return new SOAPAuthParam(
634: (javax.xml.soap.SOAPMessage) msgCtx
635: .getMessage(), null);
636: } else {
637: return new SOAPAuthParam(null,
638: (javax.xml.soap.SOAPMessage) msgCtx
639: .getMessage());
640: }
641: }
642:
643: // -- Shasta does not support any other Auth Type, so this statement is
644: // -- never reached.
645: return null;
646:
647: }
648:
649: /**
650: *
651: * @param authParam is the AuthParam
652: * @param msgCtx is the Message Context which is updated with the response message.
653: */
654: private void checkAuthParamForResponse(AuthParam authParam,
655: MessageContext msgCtx) {
656: if (authParam instanceof SOAPAuthParam) {
657: SOAPAuthParam soapParam = (SOAPAuthParam) authParam;
658:
659: if (soapParam.getResponse() != null) {
660: msgCtx.setResponseMessage(soapParam.getResponse());
661: }
662: }
663: }
664:
665: }
|