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 }