001: /*
002: * XWSSServerPipe.java
003: *
004: * Created on October 26, 2006, 12:54 PM
005: *
006: * To change this template, choose Tools | Template Manager
007: * and open the template in the editor.
008: */
009:
010: package com.sun.xml.xwss;
011:
012: import com.sun.xml.ws.api.SOAPVersion;
013: import com.sun.xml.ws.api.message.Message;
014: import com.sun.xml.ws.api.message.Messages;
015: import com.sun.xml.ws.api.message.Packet;
016: import com.sun.xml.ws.api.model.wsdl.WSDLPort;
017: import com.sun.xml.ws.api.pipe.Pipe;
018: import com.sun.xml.ws.api.pipe.PipeCloner;
019: import com.sun.xml.ws.api.server.Container;
020: import com.sun.xml.ws.api.server.WSEndpoint;
021:
022: import com.sun.xml.wss.impl.SecurityRecipient;
023: import com.sun.xml.wss.ProcessingContext;
024: import com.sun.xml.wss.XWSSecurityException;
025: import com.sun.xml.wss.impl.MessageConstants;
026: import com.sun.xml.wss.impl.PolicyTypeUtil;
027: import com.sun.xml.wss.impl.PolicyViolationException;
028: import com.sun.xml.wss.impl.ProcessingContextImpl;
029: import com.sun.xml.wss.impl.SecurableSoapMessage;
030: import com.sun.xml.wss.impl.SecurityAnnotator;
031: import com.sun.xml.wss.impl.WssSoapFaultException;
032:
033: import com.sun.xml.wss.impl.config.ApplicationSecurityConfiguration;
034: import com.sun.xml.wss.impl.config.DeclarativeSecurityConfiguration;
035: import com.sun.xml.wss.impl.configuration.StaticApplicationContext;
036: import com.sun.xml.wss.impl.misc.SecurityUtil;
037: import com.sun.xml.wss.impl.policy.SecurityPolicy;
038:
039: import java.io.InputStream;
040: import java.net.URL;
041: import javax.servlet.ServletContext;
042:
043: import javax.xml.namespace.QName;
044: import javax.xml.soap.MessageFactory;
045: import javax.xml.soap.Name;
046: import org.w3c.dom.Node;
047: import javax.xml.soap.SOAPBody;
048: import javax.xml.soap.SOAPConstants;
049: import javax.xml.soap.SOAPException;
050: import javax.xml.soap.SOAPFactory;
051: import javax.xml.soap.SOAPFault;
052: import javax.xml.soap.SOAPMessage;
053: import javax.xml.ws.WebServiceException;
054: import javax.xml.ws.soap.SOAPFaultException;
055: import org.w3c.dom.NodeList;
056:
057: /**
058: * This pipe is used to handle XWSS 2.0 Style Message Security using
059: * Security Configuration files
060: * @author kumar.jayanti
061: */
062: public class XWSSServerPipe implements Pipe {
063:
064: protected Pipe nextPipe;
065: private WSEndpoint endPoint;
066: private WSDLPort port;
067:
068: private SecurityConfiguration config = null;
069:
070: protected SOAPFactory soapFactory = null;
071: protected MessageFactory messageFactory = null;
072: protected SOAPVersion soapVersion = null;
073: protected boolean isSOAP12 = false;
074:
075: protected static final String FAILURE = "com.sun.xml.ws.shd.failure";
076:
077: protected static final String TRUE = "true";
078: protected static final String FALSE = "false";
079: protected static final String CONTEXT_WSDL_OPERATION = "com.sun.xml.ws.wsdl.operation";
080: private static final String SERVLET_CONTEXT_CLASSNAME = "javax.servlet.ServletContext";
081:
082: /** Creates a new instance of XWSSServerPipe */
083: public XWSSServerPipe(WSEndpoint epoint, WSDLPort prt, Pipe nextP) {
084: endPoint = epoint;
085: port = prt;
086: nextPipe = nextP;
087: try {
088: config = new SecurityConfiguration(getServerConfig());
089: } catch (XWSSecurityException ex) {
090: throw new WebServiceException(ex);
091: }
092: soapVersion = endPoint.getBinding().getSOAPVersion();
093: isSOAP12 = (soapVersion == SOAPVersion.SOAP_12) ? true : false;
094: soapFactory = soapVersion.saajSoapFactory;
095: messageFactory = soapVersion.saajMessageFactory;
096: }
097:
098: public XWSSServerPipe(XWSSServerPipe that) {
099:
100: this .nextPipe = that.nextPipe;
101: this .endPoint = that.endPoint;
102: this .port = that.port;
103:
104: this .soapFactory = that.soapFactory;
105: this .messageFactory = that.messageFactory;
106: this .soapVersion = that.soapVersion;
107: this .isSOAP12 = that.isSOAP12;
108: this .config = that.config;
109: }
110:
111: public Packet process(Packet packet) {
112: try {
113: Packet ret = validateRequest(packet);
114: if (TRUE.equals(ret.invocationProperties.get(FAILURE))) {
115: return ret;
116: }
117: ret = nextPipe.process(ret);
118: //could be oneway
119: if (ret.getMessage() == null) {
120: return ret;
121: }
122: return secureResponse(ret);
123:
124: } catch (Exception e) {
125: throw new WebServiceException(e);
126: }
127: }
128:
129: public void preDestroy() {
130: }
131:
132: public Pipe copy(PipeCloner pipeCloner) {
133: Pipe clonedNextPipe = null;
134: if (nextPipe != null) {
135: clonedNextPipe = pipeCloner.copy(nextPipe);
136: }
137: Pipe copied = new XWSSServerPipe(this );
138: ((XWSSServerPipe) copied).setNextPipe(clonedNextPipe);
139: pipeCloner.add(this , copied);
140: return copied;
141: }
142:
143: public void setNextPipe(Pipe pipe) {
144: nextPipe = pipe;
145: }
146:
147: private InputStream getServerConfigStream() {
148: QName serviceQName = endPoint.getServiceName();
149: String serviceName = serviceQName.getLocalPart();
150:
151: String serverConfig = "/WEB-INF/" + serviceName + "_"
152: + "security_config.xml";
153: ServletContext context = endPoint.getContainer().getSPI(
154: ServletContext.class);
155: if (context == null) {
156: return null;
157: }
158: InputStream in = context.getResourceAsStream(serverConfig);
159:
160: if (in == null) {
161: serverConfig = "/WEB-INF/" + "server" + "_"
162: + "security_config.xml";
163: in = context.getResourceAsStream(serverConfig);
164: }
165:
166: return in;
167: }
168:
169: private URL getServerConfig() {
170: QName serviceQName = endPoint.getServiceName();
171: String serviceName = serviceQName.getLocalPart();
172:
173: Container container = endPoint.getContainer();
174:
175: Object ctxt = null;
176: if (container != null) {
177: try {
178: final Class<?> contextClass = Class
179: .forName(SERVLET_CONTEXT_CLASSNAME);
180: ctxt = container.getSPI(contextClass);
181: } catch (ClassNotFoundException e) {
182: //log here at FINE Level : that the ServletContext was not found
183: }
184: }
185: String serverName = "server";
186: URL url = null;
187: if (ctxt != null) {
188: String serverConfig = "/WEB-INF/" + serverName + "_"
189: + "security_config.xml";
190: url = SecurityUtil.loadFromContext(serverConfig, ctxt);
191: if (url == null) {
192: serverConfig = "/WEB-INF/" + serviceName + "_"
193: + "security_config.xml";
194: url = SecurityUtil.loadFromContext(serverConfig, ctxt);
195: }
196:
197: if (url != null) {
198: return url;
199: }
200: } else {
201: //this could be an EJB or JDK6 endpoint
202: //so let us try to locate the config from META-INF classpath
203: String serverConfig = "META-INF/" + serverName + "_"
204: + "security_config.xml";
205: url = SecurityUtil.loadFromClasspath(serverConfig);
206: if (url == null) {
207: serverConfig = "META-INF/" + serviceName + "_"
208: + "security_config.xml";
209: url = SecurityUtil.loadFromClasspath(serverConfig);
210: }
211:
212: if (url != null) {
213: return url;
214: }
215: }
216: return null;
217: }
218:
219: private static final String ENCRYPTED_BODY_QNAME = "{"
220: + MessageConstants.XENC_NS + "}"
221: + MessageConstants.ENCRYPTED_DATA_LNAME;
222:
223: // server side incoming request handling hook
224: public Packet validateRequest(Packet packet) throws Exception {
225:
226: if (config == null) {
227: return packet;
228: }
229:
230: ProcessingContext context = null;
231: SOAPMessage message = packet.getMessage().readAsSOAPMessage();
232: try {
233:
234: StaticApplicationContext sContext = new StaticApplicationContext(
235: getPolicyContext(packet));
236:
237: context = new ProcessingContextImpl(
238: packet.invocationProperties);
239:
240: context.setSOAPMessage(message);
241:
242: String operation = getOperationName(message);
243:
244: ApplicationSecurityConfiguration _sConfig = config
245: .getSecurityConfiguration();
246:
247: if (operation.equals(ENCRYPTED_BODY_QNAME)
248: && _sConfig.hasOperationPolicies()) {
249: // get enclosing port level configuration
250: if (MessageConstants.debug) {
251: System.out.println("context in plugin= "
252: + sContext.toString());
253: }
254: ApplicationSecurityConfiguration appconfig = (ApplicationSecurityConfiguration) _sConfig
255: .getSecurityPolicies(sContext).next();
256:
257: if (appconfig != null) {
258: context.setPolicyContext(sContext);
259: context.setSecurityPolicy(appconfig);
260: } else {
261: ApplicationSecurityConfiguration config0 = (ApplicationSecurityConfiguration) _sConfig
262: .getAllTopLevelApplicationSecurityConfigurations()
263: .iterator().next();
264:
265: //sContext.setPortIdentifier ("");
266: context.setPolicyContext(sContext);
267: context.setSecurityPolicy(config0);
268: }
269: } else {
270: sContext.setOperationIdentifier(operation);
271: packet.invocationProperties.put(CONTEXT_WSDL_OPERATION,
272: operation);
273: SecurityPolicy policy = _sConfig
274: .getSecurityConfiguration(sContext);
275:
276: context.setPolicyContext(sContext);
277:
278: if (PolicyTypeUtil
279: .declarativeSecurityConfiguration(policy)) {
280: context
281: .setSecurityPolicy(((DeclarativeSecurityConfiguration) policy)
282: .receiverSettings());
283: } else {
284: context.setSecurityPolicy(policy);
285: }
286: }
287:
288: context.setSecurityEnvironment(config
289: .getSecurityEnvironment());
290: context.isInboundMessage(true);
291:
292: if (_sConfig.retainSecurityHeader()) {
293: context.retainSecurityHeader(true);
294: }
295:
296: SecurityRecipient.validateMessage(context);
297: String operationName = getOperationName(message);
298:
299: packet.invocationProperties.put(CONTEXT_WSDL_OPERATION,
300: operationName);
301: packet
302: .setMessage(Messages.create(context
303: .getSOAPMessage()));
304: /* TODO, how to change this
305: if (packet.invocationProperties.get("javax.security.auth.Subject") != null) {
306: packet.invocationProperties.("javax.security.auth.Subject",MessageContext.Scope.APPLICATION);
307: }*/
308: return packet;
309:
310: } catch (com.sun.xml.wss.impl.WssSoapFaultException soapFaultException) {
311:
312: packet.invocationProperties.put(FAILURE, TRUE);
313: addFault(soapFaultException, message, isSOAP12);
314: packet.setMessage(Messages.create(message));
315: return packet;
316:
317: } catch (com.sun.xml.wss.XWSSecurityException xwse) {
318: QName qname = null;
319:
320: if (xwse.getCause() instanceof PolicyViolationException)
321: qname = MessageConstants.WSSE_RECEIVER_POLICY_VIOLATION;
322: else
323: qname = MessageConstants.WSSE_FAILED_AUTHENTICATION;
324:
325: com.sun.xml.wss.impl.WssSoapFaultException wsfe = SecurableSoapMessage
326: .newSOAPFaultException(qname, xwse.getMessage(),
327: xwse);
328:
329: packet.invocationProperties.put(FAILURE, TRUE);
330: addFault(wsfe, message, isSOAP12);
331: packet.setMessage(Messages.create(message));
332:
333: return packet;
334: }
335:
336: }
337:
338: // server side response writing hook
339: public Packet secureResponse(Packet packet) throws Exception {
340:
341: if (config == null) {
342: return packet;
343: }
344: try {
345: ProcessingContext context = new ProcessingContextImpl(
346: packet.invocationProperties);
347:
348: String operation = (String) packet.invocationProperties
349: .get(CONTEXT_WSDL_OPERATION);
350: StaticApplicationContext sContext = new StaticApplicationContext(
351: getPolicyContext(packet));
352: sContext.setOperationIdentifier(operation);
353:
354: ApplicationSecurityConfiguration _sConfig = config
355: .getSecurityConfiguration();
356:
357: SecurityPolicy policy = _sConfig
358: .getSecurityConfiguration(sContext);
359: context.setPolicyContext(sContext);
360:
361: if (PolicyTypeUtil.declarativeSecurityConfiguration(policy)) {
362: context
363: .setSecurityPolicy(((DeclarativeSecurityConfiguration) policy)
364: .senderSettings());
365: } else {
366: context.setSecurityPolicy(policy);
367: }
368:
369: context.setSecurityEnvironment(config
370: .getSecurityEnvironment());
371: context.isInboundMessage(false);
372: context.setSOAPMessage(packet.getMessage()
373: .readAsSOAPMessage());
374: SecurityAnnotator.secureMessage(context);
375: packet
376: .setMessage(Messages.create(context
377: .getSOAPMessage()));
378: return packet;
379: } catch (com.sun.xml.wss.impl.WssSoapFaultException soapFaultException) {
380: Message msg = Messages
381: .create(getSOAPFault(soapFaultException));
382: packet.setMessage(msg);
383: return packet;
384: } catch (com.sun.xml.wss.XWSSecurityException xwse) {
385: com.sun.xml.wss.impl.WssSoapFaultException wsfe = SecurableSoapMessage
386: .newSOAPFaultException(
387: MessageConstants.WSSE_INTERNAL_SERVER_ERROR,
388: xwse.getMessage(), xwse);
389: Message msg = Messages.create(getSOAPFault(wsfe));
390: packet.setMessage(msg);
391: return packet;
392: }
393: }
394:
395: private StaticApplicationContext getPolicyContext(Packet packet) {
396: // assumed to contain single nested container
397: ApplicationSecurityConfiguration appconfig = config
398: .getSecurityConfiguration();
399:
400: StaticApplicationContext iContext = (StaticApplicationContext) appconfig
401: .getAllContexts().next();
402: StaticApplicationContext sContext = new StaticApplicationContext(
403: iContext);
404:
405: QName portQname = null;
406: if (port != null) {
407: portQname = port.getName();
408: }
409: String prt = null;
410:
411: if (portQname == null) {
412: prt = "";
413: } else {
414: prt = portQname.toString();
415: }
416:
417: sContext.setPortIdentifier(prt);
418: return sContext;
419: }
420:
421: public void addFault(
422: com.sun.xml.wss.impl.WssSoapFaultException sfe,
423: SOAPMessage soapMessage, boolean isSOAP12)
424: throws SOAPException {
425: SOAPBody body = soapMessage.getSOAPBody();
426: body.removeContents();
427: soapMessage.removeAllAttachments();
428: QName faultCode = sfe.getFaultCode();
429: Name faultCodeName = null;
430:
431: if (faultCode == null) {
432: faultCode = new QName(SOAPConstants.URI_NS_SOAP_ENVELOPE,
433: "Client");
434: }
435: if (isSOAP12) {
436: SOAPFault fault = body.addFault(
437: SOAPConstants.SOAP_SENDER_FAULT, sfe.getMessage());
438: fault.appendFaultSubcode(faultCode);
439: } else {
440: body.addFault(faultCode, sfe.getMessage());
441: }
442: NodeList list = soapMessage.getSOAPPart().getEnvelope()
443: .getElementsByTagNameNS(MessageConstants.WSSE_NS,
444: MessageConstants.WSSE_SECURITY_LNAME);
445: if (list.getLength() > 0) {
446: Node node = list.item(0);
447: node.getParentNode().removeChild(node);
448: }
449: }
450:
451: protected SOAPFault getSOAPFault(WssSoapFaultException sfe) {
452:
453: SOAPFault fault = null;
454: try {
455: if (isSOAP12) {
456: fault = soapFactory.createFault(sfe.getFaultString(),
457: SOAPConstants.SOAP_SENDER_FAULT);
458: fault.appendFaultSubcode(sfe.getFaultCode());
459: } else {
460: fault = soapFactory.createFault(sfe.getFaultString(),
461: sfe.getFaultCode());
462: }
463: } catch (Exception e) {
464: throw new RuntimeException(
465: "Security Pipe: Internal Error while trying to create a SOAPFault");
466: }
467: return fault;
468: }
469:
470: public SOAPFaultException getSOAPFaultException(
471: WssSoapFaultException sfe, boolean isSOAP12) {
472:
473: SOAPFault fault = null;
474: try {
475: if (isSOAP12) {
476: fault = soapFactory.createFault(sfe.getFaultString(),
477: SOAPConstants.SOAP_SENDER_FAULT);
478:
479: fault.appendFaultSubcode(sfe.getFaultCode());
480: } else {
481: fault = soapFactory.createFault(sfe.getFaultString(),
482: sfe.getFaultCode());
483: }
484: } catch (Exception e) {
485: throw new RuntimeException(
486: this
487: + ": Internal Error while trying to create a SOAPFault");
488: }
489: return new SOAPFaultException(fault);
490: }
491:
492: private String getOperationName(SOAPMessage message)
493: throws Exception {
494: Node node = null;
495: String key = null;
496: SOAPBody body = null;
497:
498: if (message != null)
499: body = message.getSOAPBody();
500: else
501: throw new XWSSecurityException(
502: "SOAPMessage in message context is null");
503:
504: if (body != null)
505: node = body.getFirstChild();
506: else
507: throw new XWSSecurityException(
508: "No body element identifying an operation is found");
509:
510: StringBuffer tmp = new StringBuffer("");
511: String operation = "";
512:
513: for (; node != null; node = node.getNextSibling())
514: tmp.append("{" + node.getNamespaceURI() + "}"
515: + node.getLocalName() + ":");
516: operation = tmp.toString();
517: if (operation.length() > 0) {
518: return operation.substring(0, operation.length() - 1);
519: } else {
520: return operation;
521: }
522: }
523:
524: }
|