1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaxws_classes/com/sun/xml/internal/ws/addressing/WsaTube.java Wed Apr 27 01:27:09 2016 +0800 1.3 @@ -0,0 +1,405 @@ 1.4 +/* 1.5 + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.xml.internal.ws.addressing; 1.30 + 1.31 +import com.sun.istack.internal.NotNull; 1.32 +import com.sun.xml.internal.ws.addressing.model.InvalidAddressingHeaderException; 1.33 +import com.sun.xml.internal.ws.addressing.model.MissingAddressingHeaderException; 1.34 +import com.sun.xml.internal.ws.api.SOAPVersion; 1.35 +import com.sun.xml.internal.ws.api.WSBinding; 1.36 +import com.sun.xml.internal.ws.api.addressing.AddressingVersion; 1.37 +import com.sun.xml.internal.ws.api.message.AddressingUtils; 1.38 +import com.sun.xml.internal.ws.api.message.Header; 1.39 +import com.sun.xml.internal.ws.api.message.Message; 1.40 +import com.sun.xml.internal.ws.api.message.Messages; 1.41 +import com.sun.xml.internal.ws.api.message.Packet; 1.42 +import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation; 1.43 +import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; 1.44 +import com.sun.xml.internal.ws.api.pipe.NextAction; 1.45 +import com.sun.xml.internal.ws.api.pipe.Tube; 1.46 +import com.sun.xml.internal.ws.api.pipe.TubeCloner; 1.47 +import com.sun.xml.internal.ws.api.pipe.helper.AbstractFilterTubeImpl; 1.48 +import com.sun.xml.internal.ws.developer.MemberSubmissionAddressingFeature; 1.49 +import com.sun.xml.internal.ws.message.FaultDetailHeader; 1.50 +import com.sun.xml.internal.ws.resources.AddressingMessages; 1.51 + 1.52 +import javax.xml.namespace.QName; 1.53 +import javax.xml.soap.SOAPFault; 1.54 +import javax.xml.stream.XMLStreamException; 1.55 +import javax.xml.ws.WebServiceException; 1.56 +import javax.xml.ws.soap.AddressingFeature; 1.57 +import javax.xml.ws.soap.SOAPBinding; 1.58 +import java.util.Iterator; 1.59 +import java.util.logging.Logger; 1.60 +import java.util.logging.Level; 1.61 + 1.62 +/** 1.63 + * WS-Addressing processing code shared between client and server. 1.64 + * 1.65 + * <p> 1.66 + * This tube is used only when WS-Addressing is enabled. 1.67 + * 1.68 + * @author Rama Pulavarthi 1.69 + * @author Arun Gupta 1.70 + */ 1.71 +abstract class WsaTube extends AbstractFilterTubeImpl { 1.72 + /** 1.73 + * Port that we are processing. 1.74 + */ 1.75 + protected final @NotNull WSDLPort wsdlPort; 1.76 + protected final WSBinding binding; 1.77 + final WsaTubeHelper helper; 1.78 + protected final @NotNull AddressingVersion addressingVersion; 1.79 + protected final SOAPVersion soapVersion; 1.80 + 1.81 + /** 1.82 + * True if the addressing headers are mandatory. 1.83 + */ 1.84 + private final boolean addressingRequired; 1.85 + 1.86 + public WsaTube(WSDLPort wsdlPort, WSBinding binding, Tube next) { 1.87 + super(next); 1.88 + this.wsdlPort = wsdlPort; 1.89 + this.binding = binding; 1.90 + addKnownHeadersToBinding(binding); 1.91 + addressingVersion = binding.getAddressingVersion(); 1.92 + soapVersion = binding.getSOAPVersion(); 1.93 + helper = getTubeHelper(); 1.94 + addressingRequired = AddressingVersion.isRequired(binding); 1.95 + } 1.96 + 1.97 + public WsaTube(WsaTube that, TubeCloner cloner) { 1.98 + super(that, cloner); 1.99 + this.wsdlPort = that.wsdlPort; 1.100 + this.binding = that.binding; 1.101 + this.helper = that.helper; 1.102 + addressingVersion = that.addressingVersion; 1.103 + soapVersion = that.soapVersion; 1.104 + addressingRequired = that.addressingRequired; 1.105 + } 1.106 + 1.107 + private void addKnownHeadersToBinding(WSBinding binding) { 1.108 + for (AddressingVersion addrVersion: AddressingVersion.values()) { 1.109 + binding.addKnownHeader(addrVersion.actionTag); 1.110 + binding.addKnownHeader(addrVersion.faultDetailTag); 1.111 + binding.addKnownHeader(addrVersion.faultToTag); 1.112 + binding.addKnownHeader(addrVersion.fromTag); 1.113 + binding.addKnownHeader(addrVersion.messageIDTag); 1.114 + binding.addKnownHeader(addrVersion.relatesToTag); 1.115 + binding.addKnownHeader(addrVersion.replyToTag); 1.116 + binding.addKnownHeader(addrVersion.toTag); 1.117 + } 1.118 + } 1.119 + 1.120 + @Override 1.121 + public @NotNull NextAction processException(Throwable t) { 1.122 + return super.processException(t); 1.123 + } 1.124 + 1.125 + protected WsaTubeHelper getTubeHelper() { 1.126 + if(binding.isFeatureEnabled(AddressingFeature.class)) { 1.127 + return new WsaTubeHelperImpl(wsdlPort, null, binding); 1.128 + } else if(binding.isFeatureEnabled(MemberSubmissionAddressingFeature.class)) { 1.129 + //seiModel is null as it is not needed. 1.130 + return new com.sun.xml.internal.ws.addressing.v200408.WsaTubeHelperImpl(wsdlPort, null, binding); 1.131 + } else { 1.132 + // Addressing is not enabled, WsaTube should not be included in the pipeline 1.133 + throw new WebServiceException(AddressingMessages.ADDRESSING_NOT_ENABLED(this.getClass().getSimpleName())); 1.134 + } 1.135 + } 1.136 + 1.137 + /** 1.138 + * Validates the inbound message. If an error is found, create 1.139 + * a fault message and returns that. Otherwise 1.140 + * it will pass through the parameter 'packet' object to the return value. 1.141 + */ 1.142 + protected Packet validateInboundHeaders(Packet packet) { 1.143 + SOAPFault soapFault; 1.144 + FaultDetailHeader s11FaultDetailHeader; 1.145 + 1.146 + try { 1.147 + checkMessageAddressingProperties(packet); 1.148 + return packet; 1.149 + } catch (InvalidAddressingHeaderException e) { 1.150 + LOGGER.log(Level.WARNING, 1.151 + addressingVersion.getInvalidMapText()+", Problem header:" + e.getProblemHeader()+ ", Reason: "+ e.getSubsubcode(),e); 1.152 + soapFault = helper.createInvalidAddressingHeaderFault(e, addressingVersion); 1.153 + s11FaultDetailHeader = new FaultDetailHeader(addressingVersion, addressingVersion.problemHeaderQNameTag.getLocalPart(), e.getProblemHeader()); 1.154 + } catch (MissingAddressingHeaderException e) { 1.155 + LOGGER.log(Level.WARNING,addressingVersion.getMapRequiredText()+", Problem header:"+ e.getMissingHeaderQName(),e); 1.156 + soapFault = helper.newMapRequiredFault(e); 1.157 + s11FaultDetailHeader = new FaultDetailHeader(addressingVersion, addressingVersion.problemHeaderQNameTag.getLocalPart(), e.getMissingHeaderQName()); 1.158 + } 1.159 + 1.160 + if (soapFault != null) { 1.161 + // WS-A fault processing for one-way methods 1.162 + if ((wsdlPort !=null) && packet.getMessage().isOneWay(wsdlPort)) { 1.163 + return packet.createServerResponse(null, wsdlPort, null, binding); 1.164 + } 1.165 + 1.166 + Message m = Messages.create(soapFault); 1.167 + if (soapVersion == SOAPVersion.SOAP_11) { 1.168 + m.getHeaders().add(s11FaultDetailHeader); 1.169 + } 1.170 + 1.171 + return packet.createServerResponse(m, wsdlPort, null, binding); 1.172 + } 1.173 + 1.174 + return packet; 1.175 + } 1.176 + 1.177 + /** 1.178 + * This method checks all the WS-Addressing headers are valid and as per the spec definded rules. 1.179 + * Mainly it checks the cardinality of the WSA headers and checks that mandatory headers exist. 1.180 + * It also checks if the SOAPAction is equal to wsa:Action value when non-empty. 1.181 + * 1.182 + * Override this method if you need to additional checking of headers other than just existence of the headers. 1.183 + * For ex: On server-side, check Anonymous and Non-Anonymous semantics in addition to checking cardinality. 1.184 + * 1.185 + * Override checkMandatoryHeaders(Packet p) to have different validation rules for different versions 1.186 + * 1.187 + * @param packet 1.188 + */ 1.189 + protected void checkMessageAddressingProperties(Packet packet) { 1.190 + checkCardinality(packet); 1.191 + } 1.192 + 1.193 + final boolean isAddressingEngagedOrRequired(Packet packet, WSBinding binding) { 1.194 + if (AddressingVersion.isRequired(binding)) 1.195 + return true; 1.196 + 1.197 + if (packet == null) 1.198 + return false; 1.199 + 1.200 + if (packet.getMessage() == null) 1.201 + return false; 1.202 + 1.203 + if (packet.getMessage().getHeaders() != null) 1.204 + return false; 1.205 + 1.206 + String action = AddressingUtils.getAction( 1.207 + packet.getMessage().getHeaders(), 1.208 + addressingVersion, soapVersion); 1.209 + if (action == null) 1.210 + return true; 1.211 + 1.212 + return true; 1.213 + } 1.214 + 1.215 + /** 1.216 + * Checks the cardinality of WS-Addressing headers on an inbound {@link Packet}. This method 1.217 + * checks for the cardinality if WS-Addressing is engaged (detected by the presence of wsa:Action 1.218 + * header) or wsdl:required=true. 1.219 + * 1.220 + * @param packet The inbound packet. 1.221 + * @throws WebServiceException if: 1.222 + * <ul> 1.223 + * <li>there is an error reading ReplyTo or FaultTo</li> 1.224 + * <li>WS-Addressing is required and {@link Message} within <code>packet</code> is null</li> 1.225 + * <li>WS-Addressing is required and no headers are found in the {@link Message}</li> 1.226 + * <li>an uknown WS-Addressing header is present</li> 1.227 + * </ul> 1.228 + */ 1.229 + protected void checkCardinality(Packet packet) { 1.230 + Message message = packet.getMessage(); 1.231 + if (message == null) { 1.232 + if (addressingRequired) 1.233 + throw new WebServiceException(AddressingMessages.NULL_MESSAGE()); 1.234 + else 1.235 + return; 1.236 + } 1.237 + 1.238 + Iterator<Header> hIter = message.getHeaders().getHeaders(addressingVersion.nsUri, true); 1.239 + 1.240 + if (!hIter.hasNext()) { 1.241 + // no WS-A headers are found 1.242 + if (addressingRequired) 1.243 + // if WS-A is required, then throw an exception looking for wsa:Action header 1.244 + throw new MissingAddressingHeaderException(addressingVersion.actionTag,packet); 1.245 + else 1.246 + // else no need to process 1.247 + return; 1.248 + } 1.249 + 1.250 + boolean foundFrom = false; 1.251 + boolean foundTo = false; 1.252 + boolean foundReplyTo = false; 1.253 + boolean foundFaultTo = false; 1.254 + boolean foundAction = false; 1.255 + boolean foundMessageId = false; 1.256 + boolean foundRelatesTo = false; 1.257 + QName duplicateHeader = null; 1.258 + 1.259 + while (hIter.hasNext()) { 1.260 + Header h = hIter.next(); 1.261 + 1.262 + // check if the Header is in current role 1.263 + if (!isInCurrentRole(h, binding)) { 1.264 + continue; 1.265 + } 1.266 + 1.267 + String local = h.getLocalPart(); 1.268 + if (local.equals(addressingVersion.fromTag.getLocalPart())) { 1.269 + if (foundFrom) { 1.270 + duplicateHeader = addressingVersion.fromTag; 1.271 + break; 1.272 + } 1.273 + foundFrom = true; 1.274 + } else if (local.equals(addressingVersion.toTag.getLocalPart())) { 1.275 + if (foundTo) { 1.276 + duplicateHeader = addressingVersion.toTag; 1.277 + break; 1.278 + } 1.279 + foundTo = true; 1.280 + } else if (local.equals(addressingVersion.replyToTag.getLocalPart())) { 1.281 + if (foundReplyTo) { 1.282 + duplicateHeader = addressingVersion.replyToTag; 1.283 + break; 1.284 + } 1.285 + foundReplyTo = true; 1.286 + try { // verify that the header is in a good shape 1.287 + h.readAsEPR(addressingVersion); 1.288 + } catch (XMLStreamException e) { 1.289 + throw new WebServiceException(AddressingMessages.REPLY_TO_CANNOT_PARSE(), e); 1.290 + } 1.291 + } else if (local.equals(addressingVersion.faultToTag.getLocalPart())) { 1.292 + if (foundFaultTo) { 1.293 + duplicateHeader = addressingVersion.faultToTag; 1.294 + break; 1.295 + } 1.296 + foundFaultTo = true; 1.297 + try { // verify that the header is in a good shape 1.298 + h.readAsEPR(addressingVersion); 1.299 + } catch (XMLStreamException e) { 1.300 + throw new WebServiceException(AddressingMessages.FAULT_TO_CANNOT_PARSE(), e); 1.301 + } 1.302 + } else if (local.equals(addressingVersion.actionTag.getLocalPart())) { 1.303 + if (foundAction) { 1.304 + duplicateHeader = addressingVersion.actionTag; 1.305 + break; 1.306 + } 1.307 + foundAction = true; 1.308 + } else if (local.equals(addressingVersion.messageIDTag.getLocalPart())) { 1.309 + if (foundMessageId) { 1.310 + duplicateHeader = addressingVersion.messageIDTag; 1.311 + break; 1.312 + } 1.313 + foundMessageId = true; 1.314 + } else if (local.equals(addressingVersion.relatesToTag.getLocalPart())) { 1.315 + foundRelatesTo = true; 1.316 + } else if (local.equals(addressingVersion.faultDetailTag.getLocalPart())) { 1.317 + // TODO: should anything be done here ? 1.318 + // TODO: fault detail element - only for SOAP 1.1 1.319 + } else { 1.320 + System.err.println(AddressingMessages.UNKNOWN_WSA_HEADER()); 1.321 + } 1.322 + } 1.323 + 1.324 + // check for invalid cardinality first before checking for mandatory headers 1.325 + if (duplicateHeader != null) { 1.326 + throw new InvalidAddressingHeaderException(duplicateHeader, addressingVersion.invalidCardinalityTag); 1.327 + } 1.328 + 1.329 + // WS-A is engaged if wsa:Action header is found 1.330 + boolean engaged = foundAction; 1.331 + 1.332 + // check for mandatory set of headers only if: 1.333 + // 1. WS-A is engaged or 1.334 + // 2. wsdl:required=true 1.335 + // Both wsa:Action and wsa:To MUST be present on request (for oneway MEP) and 1.336 + // response messages (for oneway and request/response MEP only) 1.337 + if (engaged || addressingRequired) { 1.338 + // Check for mandatory headers always (even for Protocol messages). 1.339 + // If it breaks any interop scenarios, Remove the comments. 1.340 + /* 1.341 + WSDLBoundOperation wbo = getWSDLBoundOperation(packet); 1.342 + // no need to check for for non-application messages 1.343 + if (wbo == null) 1.344 + return; 1.345 + */ 1.346 + checkMandatoryHeaders(packet, foundAction, foundTo, foundReplyTo, 1.347 + foundFaultTo, foundMessageId, foundRelatesTo); 1.348 + } 1.349 + } 1.350 + 1.351 + final boolean isInCurrentRole(Header header, WSBinding binding) { 1.352 + // TODO: binding will be null for protocol messages 1.353 + // TODO: returning true assumes that protocol messages are 1.354 + // TODO: always in current role, this may not to be fixed. 1.355 + if (binding == null) 1.356 + return true; 1.357 + return ((SOAPBinding)binding).getRoles().contains(header.getRole(soapVersion)); 1.358 + 1.359 + } 1.360 + 1.361 + protected final WSDLBoundOperation getWSDLBoundOperation(Packet packet) { 1.362 + //we can find Req/Response or Oneway only with WSDLModel 1.363 + if(wsdlPort == null) 1.364 + return null; 1.365 + QName opName = packet.getWSDLOperation(); 1.366 + if(opName != null) 1.367 + return wsdlPort.getBinding().get(opName); 1.368 + return null; 1.369 + } 1.370 + 1.371 + protected void validateSOAPAction(Packet packet) { 1.372 + String gotA = AddressingUtils.getAction( 1.373 + packet.getMessage().getHeaders(), 1.374 + addressingVersion, soapVersion); 1.375 + if (gotA == null) 1.376 + throw new WebServiceException(AddressingMessages.VALIDATION_SERVER_NULL_ACTION()); 1.377 + if(packet.soapAction != null && !packet.soapAction.equals("\"\"") && !packet.soapAction.equals("\""+gotA+"\"")) { 1.378 + throw new InvalidAddressingHeaderException(addressingVersion.actionTag, addressingVersion.actionMismatchTag); 1.379 + } 1.380 + } 1.381 + 1.382 + protected abstract void validateAction(Packet packet); 1.383 + 1.384 + /** 1.385 + * This should be called only when Addressing is engaged. 1.386 + * 1.387 + * Checks only for presence of wsa:Action and validates that wsa:Action 1.388 + * equals SOAPAction header when non-empty 1.389 + * Should be overridden if other wsa headers need to be checked based on version. 1.390 + * 1.391 + * @param packet 1.392 + * @param foundAction 1.393 + * @param foundTo 1.394 + * @param foundReplyTo 1.395 + * @param foundFaultTo 1.396 + * @param foundMessageId 1.397 + * @param foundRelatesTo 1.398 + */ 1.399 + protected void checkMandatoryHeaders( 1.400 + Packet packet, boolean foundAction, boolean foundTo, boolean foundReplyTo, 1.401 + boolean foundFaultTo, boolean foundMessageId, boolean foundRelatesTo) { 1.402 + // if no wsa:Action header is found 1.403 + if (!foundAction) 1.404 + throw new MissingAddressingHeaderException(addressingVersion.actionTag,packet); 1.405 + validateSOAPAction(packet); 1.406 + } 1.407 + private static final Logger LOGGER = Logger.getLogger(WsaTube.class.getName()); 1.408 +}