View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.wss4j.dom.callback;
21  
22  import java.util.Collections;
23  import java.util.List;
24  
25  import javax.xml.crypto.dom.DOMCryptoContext;
26  
27  import org.apache.wss4j.dom.WSConstants;
28  import org.apache.wss4j.common.ext.WSSecurityException;
29  import org.apache.wss4j.common.util.XMLUtils;
30  import org.apache.wss4j.dom.util.WSSecurityUtil;
31  import org.w3c.dom.Document;
32  import org.w3c.dom.Element;
33  
34  /**
35   * This class uses a DOM-based approach to locate Elements that are referenced via an Id.
36   */
37  public class DOMCallbackLookup implements CallbackLookup {
38  
39      private Document doc;
40  
41      public DOMCallbackLookup(Document doc) {
42          this.doc = doc;
43      }
44  
45      /**
46       * Get the DOM element that corresponds to the given id and ValueType reference. The Id can
47       * be a wsu:Id or else an Id attribute, or a SAML Id when the ValueType refers to a SAML
48       * Assertion.
49       *
50       * @param id The id of the element to locate
51       * @param valueType The ValueType attribute of the element to locate (can be null)
52       * @param checkMultipleElements If true then go through the entire tree and return
53       *        null if there are multiple elements with the same Id
54       * @return the located element
55       * @throws WSSecurityException
56       */
57      public Element getElement(
58          String id, String valueType, boolean checkMultipleElements
59      ) throws WSSecurityException {
60          return getAndRegisterElement(id, valueType, checkMultipleElements, null);
61      }
62  
63      /**
64       * Get the DOM element that corresponds to the given id and ValueType reference. The Id can
65       * be a wsu:Id or else an Id attribute, or a SAML Id when the ValueType refers to a SAML
66       * Assertion. The implementation is also responsible to register the retrieved Element on the
67       * DOMCryptoContext argument, so that the XML Signature implementation can find the Element.
68       *
69       * @param id The id of the element to locate
70       * @param valueType The ValueType attribute of the element to locate (can be null)
71       * @param checkMultipleElements If true then go through the entire tree and return
72       *        null if there are multiple elements with the same Id
73       * @param context The DOMCryptoContext to store the Element in
74       * @return the located element
75       * @throws WSSecurityException
76       */
77      public Element getAndRegisterElement(
78          String id, String valueType, boolean checkMultipleElements, DOMCryptoContext context
79      ) throws WSSecurityException {
80          String idToMatch = XMLUtils.getIDFromReference(id);
81  
82          //
83          // Try the SOAP Body first
84          //
85          Element bodyElement = getSOAPBody();
86          if (bodyElement != null) {
87              String cId = bodyElement.getAttributeNS(WSConstants.WSU_NS, "Id");
88              if (cId.equals(idToMatch)) {
89                  if (context != null) {
90                      context.setIdAttributeNS(bodyElement, WSConstants.WSU_NS, "Id");
91                  }
92                  return bodyElement;
93              }
94          }
95          // Otherwise do a general search
96          Element foundElement =
97              XMLUtils.findElementById(doc.getDocumentElement(), idToMatch, checkMultipleElements);
98          if (foundElement != null) {
99              if (context != null) {
100                 if (foundElement.hasAttributeNS(WSConstants.WSU_NS, "Id")
101                     && idToMatch.equals(foundElement.getAttributeNS(WSConstants.WSU_NS, "Id"))) {
102                     context.setIdAttributeNS(foundElement, WSConstants.WSU_NS, "Id");
103                 }
104                 if (foundElement.hasAttributeNS(null, "Id")
105                     && idToMatch.equals(foundElement.getAttributeNS(null, "Id"))) {
106                     context.setIdAttributeNS(foundElement, null, "Id");
107                 }
108             }
109             return foundElement;
110         }
111 
112         //
113         // Try to find a SAML Assertion Element if the ValueType corresponds to a SAML Assertion
114         // (or is empty)
115         //
116         if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(valueType)
117             || WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(valueType)
118             || valueType == null || valueType.length() == 0) {
119             foundElement =
120                 XMLUtils.findSAMLAssertionElementById(
121                     doc.getDocumentElement(), idToMatch
122                 );
123             if (foundElement != null) {
124                 if (context != null) {
125                     if (foundElement.hasAttributeNS(null, "ID")
126                         && idToMatch.equals(foundElement.getAttributeNS(null, "ID"))) {
127                         context.setIdAttributeNS(foundElement, null, "ID");
128                     }
129                     if (foundElement.hasAttributeNS(null, "AssertionID")
130                         && idToMatch.equals(foundElement.getAttributeNS(null, "AssertionID"))) {
131                         context.setIdAttributeNS(foundElement, null, "AssertionID");
132                     }
133                 }
134                 return foundElement;
135             }
136         }
137 
138         return null;
139     }
140 
141     /**
142      * Get the DOM element(s) that correspond to the given localname/namespace.
143      * @param localname The localname of the Element(s)
144      * @param namespace The namespace of the Element(s)
145      * @return the located element(s)
146      * @throws WSSecurityException
147      */
148     public List<Element> getElements(
149         String localname, String namespace
150     ) throws WSSecurityException {
151         //
152         // Try the SOAP Body first
153         //
154         Element bodyElement = getSOAPBody();
155         if (WSConstants.ELEM_BODY.equals(localname) && bodyElement.getNamespaceURI().equals(namespace)) {
156             return Collections.singletonList(bodyElement);
157         }
158         return XMLUtils.findElements(doc.getDocumentElement(), localname, namespace);
159     }
160 
161 
162     /**
163      * Get the SOAP Body
164      */
165     public Element getSOAPBody() {
166         return WSSecurityUtil.findBodyElement(doc);
167     }
168 }