View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /**
6    * Licensed to the Apache Software Foundation (ASF) under one
7    * or more contributor license agreements. See the NOTICE file
8    * distributed with this work for additional information
9    * regarding copyright ownership. The ASF licenses this file
10   * to you under the Apache License, Version 2.0 (the
11   * "License"); you may not use this file except in compliance
12   * with the License. You may obtain a copy of the License at
13   *
14   * http://www.apache.org/licenses/LICENSE-2.0
15   *
16   * Unless required by applicable law or agreed to in writing,
17   * software distributed under the License is distributed on an
18   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19   * KIND, either express or implied. See the License for the
20   * specific language governing permissions and limitations
21   * under the License.
22   */
23  package com.sun.org.apache.xml.internal.security.utils.resolver.implementations;
24  
25  import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
26  import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
27  import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverContext;
28  import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException;
29  import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverSpi;
30  import org.w3c.dom.Document;
31  import org.w3c.dom.Element;
32  import org.w3c.dom.Node;
33  
34  /**
35   * Handles barename XPointer Reference URIs.
36   * <BR />
37   * To retain comments while selecting an element by an identifier ID,
38   * use the following full XPointer: URI='#xpointer(id('ID'))'.
39   * <BR />
40   * To retain comments while selecting the entire document,
41   * use the following full XPointer: URI='#xpointer(/)'.
42   * This XPointer contains a simple XPath expression that includes
43   * the root node, which the second to last step above replaces with all
44   * nodes of the parse tree (all descendants, plus all attributes,
45   * plus all namespaces nodes).
46   *
47   * @author $Author: coheigea $
48   */
49  public class ResolverXPointer extends ResourceResolverSpi {
50  
51      /** {@link org.apache.commons.logging} logging facility */
52      private static java.util.logging.Logger log =
53          java.util.logging.Logger.getLogger(ResolverXPointer.class.getName());
54  
55      private static final String XP = "#xpointer(id(";
56      private static final int XP_LENGTH = XP.length();
57  
58      @Override
59      public boolean engineIsThreadSafe() {
60          return true;
61      }
62  
63      /**
64       * @inheritDoc
65       */
66      @Override
67      public XMLSignatureInput engineResolveURI(ResourceResolverContext context)
68          throws ResourceResolverException {
69  
70          Node resultNode = null;
71          Document doc = context.attr.getOwnerElement().getOwnerDocument();
72  
73          if (isXPointerSlash(context.uriToResolve)) {
74              resultNode = doc;
75          } else if (isXPointerId(context.uriToResolve)) {
76              String id = getXPointerId(context.uriToResolve);
77              resultNode = doc.getElementById(id);
78  
79              if (context.secureValidation) {
80                  Element start = context.attr.getOwnerDocument().getDocumentElement();
81                  if (!XMLUtils.protectAgainstWrappingAttack(start, id)) {
82                      Object exArgs[] = { id };
83                      throw new ResourceResolverException(
84                          "signature.Verification.MultipleIDs", exArgs, context.attr, context.baseUri
85                      );
86                  }
87              }
88  
89              if (resultNode == null) {
90                  Object exArgs[] = { id };
91  
92                  throw new ResourceResolverException(
93                      "signature.Verification.MissingID", exArgs, context.attr, context.baseUri
94                  );
95              }
96          }
97  
98          XMLSignatureInput result = new XMLSignatureInput(resultNode);
99  
100         result.setMIMEType("text/xml");
101         if (context.baseUri != null && context.baseUri.length() > 0) {
102             result.setSourceURI(context.baseUri.concat(context.uriToResolve));
103         } else {
104             result.setSourceURI(context.uriToResolve);
105         }
106 
107         return result;
108     }
109 
110     /**
111      * @inheritDoc
112      */
113     public boolean engineCanResolveURI(ResourceResolverContext context) {
114         if (context.uriToResolve == null) {
115             return false;
116         }
117         if (isXPointerSlash(context.uriToResolve) || isXPointerId(context.uriToResolve)) {
118             return true;
119         }
120 
121         return false;
122     }
123 
124     /**
125      * Method isXPointerSlash
126      *
127      * @param uri
128      * @return true if begins with xpointer
129      */
130     private static boolean isXPointerSlash(String uri) {
131         if (uri.equals("#xpointer(/)")) {
132             return true;
133         }
134 
135         return false;
136     }
137 
138     /**
139      * Method isXPointerId
140      *
141      * @param uri
142      * @return whether it has an xpointer id
143      */
144     private static boolean isXPointerId(String uri) {
145         if (uri.startsWith(XP) && uri.endsWith("))")) {
146             String idPlusDelim = uri.substring(XP_LENGTH, uri.length() - 2);
147 
148             int idLen = idPlusDelim.length() -1;
149             if (((idPlusDelim.charAt(0) == '"') && (idPlusDelim.charAt(idLen) == '"'))
150                 || ((idPlusDelim.charAt(0) == '\'') && (idPlusDelim.charAt(idLen) == '\''))) {
151                 if (log.isLoggable(java.util.logging.Level.FINE)) {
152                     log.log(java.util.logging.Level.FINE, "Id = " + idPlusDelim.substring(1, idLen));
153                 }
154                 return true;
155             }
156         }
157 
158         return false;
159     }
160 
161     /**
162      * Method getXPointerId
163      *
164      * @param uri
165      * @return xpointerId to search.
166      */
167     private static String getXPointerId(String uri) {
168         if (uri.startsWith(XP) && uri.endsWith("))")) {
169             String idPlusDelim = uri.substring(XP_LENGTH,uri.length() - 2);
170 
171             int idLen = idPlusDelim.length() -1;
172             if (((idPlusDelim.charAt(0) == '"') && (idPlusDelim.charAt(idLen) == '"'))
173                 || ((idPlusDelim.charAt(0) == '\'') && (idPlusDelim.charAt(idLen) == '\''))) {
174                 return idPlusDelim.substring(1, idLen);
175             }
176         }
177 
178         return null;
179     }
180 }