001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the License). You may not use this file except in
005: * compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
009: * See the License for the specific language governing
010: * permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL
013: * Header Notice in each file and include the License file
014: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
015: * If applicable, add the following below the CDDL Header,
016: * with the fields enclosed by brackets [] replaced by
017: * you own identifying information:
018: * "Portions Copyrighted [year] [name of copyright owner]"
019: *
020: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
021: */
022:
023: package com.sun.xml.ws.security.opt.impl.message;
024:
025: import com.sun.xml.ws.security.opt.api.SecurityElementWriter;
026: import com.sun.xml.ws.security.opt.api.SecurityHeaderElement;
027: import com.sun.xml.wss.impl.c14n.StAXAttr;
028: import com.sun.xml.wss.impl.c14n.AttributeNS;
029: import com.sun.istack.NotNull;
030: import com.sun.istack.Nullable;
031: import com.sun.xml.bind.api.Bridge;
032: import com.sun.xml.bind.api.BridgeContext;
033: import com.sun.xml.ws.api.SOAPVersion;
034: import java.util.Vector;
035: import org.xml.sax.ContentHandler;
036: import org.xml.sax.ErrorHandler;
037: import org.xml.sax.SAXException;
038: import javax.xml.stream.XMLStreamConstants;
039: import javax.xml.bind.JAXBException;
040: import javax.xml.bind.Unmarshaller;
041: import javax.xml.namespace.QName;
042: import javax.xml.soap.SOAPException;
043: import javax.xml.soap.SOAPMessage;
044: import javax.xml.stream.XMLStreamException;
045: import javax.xml.stream.XMLStreamReader;
046: import javax.xml.stream.XMLStreamWriter;
047: import java.util.Set;
048:
049: import com.sun.xml.ws.api.addressing.AddressingVersion;
050: import com.sun.xml.ws.api.addressing.WSEndpointReference;
051:
052: /**
053: * Header represents any Header element that has its contents signed. This
054: * implementation can be used for encryption too.
055: *
056: *
057: * @author K.Venugopal@sun.com
058: */
059: public class Header implements com.sun.xml.ws.api.message.Header {
060:
061: private com.sun.xml.ws.api.message.Header wrappedHeader = null;
062: private SecurityHeaderElement she = null;
063:
064: private String localName;
065: private String uri;
066: private String prefix;
067: private Vector attrList = new Vector();
068: private Vector attrNSList = new Vector();
069: private boolean parsed = false;
070:
071: /**
072: *
073: * @param header represents the Header element whose content is either signed or encrypted
074: * @param she represents a SecurityHeaderElement wrapped over the content of header.
075: */
076: public Header(com.sun.xml.ws.api.message.Header header,
077: SecurityHeaderElement she) {
078: this .wrappedHeader = header;
079: this .she = she;
080: }
081:
082: /**
083: * Checks if this header is ignorable for us (IOW, make sure
084: * that this header has a problematic "mustUnderstand" header value
085: * that we have to reject.)
086: *
087: * <p>
088: * This method is used as a part of the
089: * <a href="HeaderList.html#MU">mustUnderstanx processing</a>.
090: * At the end of the processing, the JAX-WS identifies a list of {@link Header}s
091: * that were not understood. This method is invoked on those {@link Header}s,
092: * to verify that we don't need to report an error for it.
093: *
094: * <p>
095: * specifically, this method has to perform the following tasks:
096: *
097: * <ul>
098: * <li>If this header does not have <tt>mustUnderstand</tt> as "1" nor "true",
099: * then this method must return true.
100: * <li>Otherwise, check the role attribute (for SOAP 1.2) or the actor attribute (for SOAP 1.1).
101: * When those attributes are absent, the default values have to be assumed.
102: * See {@link #getRole(SOAPVersion)} for how the values are defaulted.
103: * Now, see if the {@code roles} set contains the value.
104: * If so, this method must return false (indicating that an error is in order.)
105: * <li>Otherwise return true (since we don't play the role this header is intended for.)
106: * </ul>
107: *
108: * @param soapVersion
109: * The caller specifies the SOAP version that the pipeline is working against.
110: * Often each {@link Header} implementation already knows the SOAP version
111: * anyway, but this allows some {@link Header}s to avoid keeping it.
112: * That's why this redundant parameter is passed in.
113: * @param roles
114: * The set of role values that the current JAX-WS pipeline is assuming.
115: * Note that SOAP 1.1 and SOAP 1.2 use different strings for the same role,
116: * and the caller is responsible for supplying a proper value depending on the
117: * active SOAP version in use.
118: *
119: * @return
120: * true if no error needs to be reported. False if an error needs to be raised.
121: * See the method javadoc for more discussion.
122: */
123: public boolean isIgnorable(@NotNull
124: SOAPVersion soapVersion, @NotNull
125: Set<String> roles) {
126: return this .wrappedHeader.isIgnorable(soapVersion, roles);
127: }
128:
129: /**
130: * Gets the value of the soap:role attribute (or soap:actor for SOAP 1.1).
131: *
132: * <p>
133: * If the attribute is omitted, the value defaults to {@link SOAPVersion#implicitRole}.
134: *
135: * @param soapVersion
136: * The caller specifies the SOAP version that the pipeline is working against.
137: * Often each {@link Header} implementation already knows the SOAP version
138: * anyway, but this allows some {@link Header}s to avoid keeping it.
139: * That's why this redundant parameter is passed in.
140: * @return
141: * never null. This string need not be interned.
142: */
143: public @NotNull
144: String getRole(@NotNull
145: SOAPVersion soapVersion) {
146: return this .wrappedHeader.getRole(soapVersion);
147: }
148:
149: /**
150: * True if this header is to be relayed if not processed.
151: * For SOAP 1.1 messages, this method always return false.
152: *
153: * <p>
154: * IOW, this method returns true if there's @soap:relay='true'
155: * is present.
156: *
157: * <h3>Implementation Note</h3>
158: * <p>
159: * The implementation needs to check for both "true" and "1",
160: * but because attribute values are normalized, it doesn't have
161: * to consider " true", " 1 ", and so on.
162: *
163: * @return
164: * false.
165: */
166: public boolean isRelay() {
167: return this .wrappedHeader.isRelay();
168: }
169:
170: /**
171: * Gets the namespace URI of this header element.
172: *
173: * @return
174: * this string must be interned.
175: */
176: public @NotNull
177: String getNamespaceURI() {
178: if (!parsed) {
179: try {
180: parse();
181: } catch (javax.xml.stream.XMLStreamException ex) {
182: ex.printStackTrace();
183: //log error;
184: }
185: }
186: return uri;
187: }
188:
189: /**
190: * Gets the local name of this header element.
191: *
192: * @return
193: * this string must be interned.
194: */
195: public @NotNull
196: String getLocalPart() {
197: if (!parsed) {
198: try {
199: parse();
200: } catch (javax.xml.stream.XMLStreamException ex) {
201: ex.printStackTrace();
202: //log error;
203: }
204: }
205: return localName;
206: }
207:
208: /**
209: * Gets the attribute value on the header element.
210: *
211: * @param nsUri
212: * The namespace URI of the attribute. Can be empty.
213: * @param localName
214: * The local name of the attribute.
215: *
216: * @return
217: * if the attribute is found, return the whitespace normalized value.
218: * (meaning no leading/trailing space, no consequtive whitespaces in-between.)
219: * Otherwise null. Note that the XML parsers are responsible for
220: * whitespace-normalizing attributes, so {@link Header} implementation
221: * doesn't have to do anything.
222: */
223: public @Nullable
224: String getAttribute(@NotNull
225: String nsUri, @NotNull
226: String localName) {
227: throw new UnsupportedOperationException();
228: }
229:
230: /**
231: * Gets the attribute value on the header element.
232: *
233: * <p>
234: * This is a convenience method that calls into {@link #getAttribute(String, String)}
235: *
236: * @param name
237: * Never null.
238: *
239: * @see #getAttribute(String, String)
240: */
241: public @Nullable
242: String getAttribute(@NotNull
243: QName name) {
244: throw new UnsupportedOperationException();
245: }
246:
247: /**
248: * Reads the header as a {@link XMLStreamReader}.
249: *
250: * <p>
251: * The returned parser points at the start element of this header.
252: * (IOW, {@link XMLStreamReader#getEventType()} would return
253: * {@link XMLStreamReader#START_ELEMENT}.
254: *
255: * <h3>Performance Expectation</h3>
256: * <p>
257: * For some {@link Header} implementations, this operation
258: * is a non-trivial operation. Therefore, use of this method
259: * is discouraged unless the caller is interested in reading
260: * the whole header.
261: *
262: * <p>
263: * Similarly, if the caller wants to use this method only to do
264: * the API conversion (such as simply firing SAX events from
265: * {@link XMLStreamReader}), then the JAX-WS team requests
266: * that you talk to us.
267: *
268: * <p>
269: * {@link Message}s that come from tranport usually provides
270: * a reasonably efficient implementation of this method.
271: *
272: * @return
273: * must not null.
274: */
275: public XMLStreamReader readHeader() throws XMLStreamException {
276: throw new UnsupportedOperationException();
277: //We should avoid such operations for Security operated headers.
278:
279: }
280:
281: /**
282: * Reads the header as a JAXB object by using the given unmarshaller.
283: */
284: public <T> T readAsJAXB(Unmarshaller unmarshaller)
285: throws JAXBException {
286: throw new UnsupportedOperationException();
287: }
288:
289: /**
290: * @deprecated
291: * Use {@link #readAsJAXB(Bridge)}. To be removed after JavaOne.
292: */
293: public <T> T readAsJAXB(Bridge<T> bridge, BridgeContext context)
294: throws JAXBException {
295: throw new UnsupportedOperationException();
296: }
297:
298: /**
299: * Reads the header as a JAXB object by using the given unmarshaller.
300: */
301: public <T> T readAsJAXB(Bridge<T> bridge) throws JAXBException {
302: throw new UnsupportedOperationException();
303: }
304:
305: /**
306: * Writes out the header.
307: *
308: * @throws XMLStreamException
309: * if the operation fails for some reason. This leaves the
310: * writer to an undefined state.
311: */
312: public void writeTo(XMLStreamWriter w) throws XMLStreamException {
313: if (!parsed) {
314: parse();
315: }
316: writeStartElement(w);
317: ((SecurityElementWriter) she).writeTo(w);
318: writeEndElement(w);
319: }
320:
321: /**
322: * Writes out the header to the given SOAPMessage.
323: *
324: * <p>
325: * Sometimes a {@link Message} needs to produce itself
326: * as {@link SOAPMessage}, in which case each header needs
327: * to turn itself into a header.
328: *
329: * @throws SOAPException
330: * if the operation fails for some reason. This leaves the
331: * writer to an undefined state.
332: */
333: public void writeTo(SOAPMessage saaj) throws SOAPException {
334: throw new UnsupportedOperationException(
335: "use writeTo(XMLStreamWriter w) ");
336: }
337:
338: /**
339: * Writes out the header as SAX events.
340: *
341: * <p>
342: * Sometimes a {@link Message} needs to produce SAX events,
343: * and this method is necessary for headers to participate to it.
344: *
345: * <p>
346: * A header is responsible for producing the SAX events for its part,
347: * including <tt>startPrefixMapping</tt> and <tt>endPrefixMapping</tt>,
348: * but not startDocument/endDocument.
349: *
350: * <p>
351: * Note that SAX contract requires that any error that does NOT originate
352: * from {@link ContentHandler} (meaning any parsing error and etc) must
353: * be first reported to {@link ErrorHandler}. If the SAX event production
354: * cannot be continued and the processing needs to abort, the code may
355: * then throw the same {@link SAXParseException} reported to {@link ErrorHandler}.
356: *
357: * @param contentHandler
358: * The {@link ContentHandler} that receives SAX events.
359: *
360: * @param errorHandler
361: * The {@link ErrorHandler} that receives parsing errors.
362: */
363: public void writeTo(ContentHandler contentHandler,
364: ErrorHandler errorHandler) throws SAXException {
365: throw new UnsupportedOperationException(
366: "use writeTo(XMLStreamWriter w) ");
367: }
368:
369: public String getStringContent() {
370: throw new UnsupportedOperationException();
371: }
372:
373: public @NotNull
374: WSEndpointReference readAsEPR(AddressingVersion expected)
375: throws XMLStreamException {
376: throw new UnsupportedOperationException();
377: }
378:
379: protected void parse() throws XMLStreamException {
380: XMLStreamReader reader = this .wrappedHeader.readHeader();
381: parsed = true;
382: boolean stop = false;
383: while (reader.hasNext()) {
384: int eventType = reader.next();
385: if (stop) {
386: return;
387: }
388: switch (eventType) {
389: case XMLStreamConstants.START_ELEMENT: {
390: localName = reader.getLocalName();
391: uri = reader.getNamespaceURI();
392: prefix = reader.getPrefix();
393: if (prefix == null)
394: prefix = "";
395: int count = reader.getAttributeCount();
396: for (int i = 0; i < count; i++) {
397: final String localName = reader
398: .getAttributeLocalName(i);
399: final String uri = reader.getAttributeNamespace(i);
400: String prefix = reader.getAttributePrefix(i);
401: if (prefix == null)
402: prefix = "";
403: final String value = reader.getAttributeValue(i);
404: StAXAttr attr = new StAXAttr();
405: attr.setLocalName(localName);
406: attr.setValue(value);
407: attr.setPrefix(prefix);
408: attr.setUri(uri);
409: attrList.add(attr);
410: }
411:
412: count = 0;
413: count = reader.getNamespaceCount();
414: for (int i = 0; i < count; i++) {
415: String prefix = reader.getNamespacePrefix(i);
416: if (prefix == null)
417: prefix = "";
418: final String uri = reader.getNamespaceURI(i);
419: AttributeNS attrNS = new AttributeNS();
420: attrNS.setPrefix(prefix);
421: attrNS.setUri(uri);
422: attrNSList.add(attrNS);
423: }
424: stop = true;
425: break;
426: }
427: case XMLStreamConstants.END_ELEMENT: {
428: stop = true;
429: break;
430: }
431: }
432:
433: }
434: }
435:
436: private void writeEndElement(XMLStreamWriter xsw)
437: throws XMLStreamException {
438: xsw.writeEndElement();
439: }
440:
441: private void writeStartElement(XMLStreamWriter xsw)
442: throws XMLStreamException {
443: xsw.writeStartElement(prefix, localName, uri);
444: for (int i = 0; i < attrNSList.size(); i++) {
445: AttributeNS attrNs = (AttributeNS) attrNSList.get(i);
446: xsw.writeNamespace(attrNs.getPrefix(), attrNs.getUri());
447: }
448: for (int i = 0; i < attrList.size(); i++) {
449: StAXAttr attr = (StAXAttr) attrList.get(i);
450: xsw.writeAttribute(attr.getPrefix(), attr.getUri(), attr
451: .getLocalName(), attr.getValue());
452: }
453: }
454: }
|