1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Copyright 2005 The Apache Software Foundation. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 package com.sun.org.apache.xerces.internal.jaxp.validation; 21 22 import java.io.IOException; 23 import java.io.InputStream; 24 import java.io.Reader; 25 26 import javax.xml.XMLConstants; 27 import javax.xml.stream.XMLEventReader; 28 import javax.xml.transform.Source; 29 import javax.xml.transform.dom.DOMSource; 30 import javax.xml.transform.sax.SAXSource; 31 import javax.xml.transform.stax.StAXSource; 32 import javax.xml.transform.stream.StreamSource; 33 import javax.xml.validation.Schema; 34 import javax.xml.validation.SchemaFactory; 35 import jdk.xml.internal.JdkXmlFeatures; 36 import jdk.xml.internal.JdkXmlUtils; 37 38 import com.sun.org.apache.xerces.internal.impl.Constants; 39 import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader; 40 import com.sun.org.apache.xerces.internal.util.DOMEntityResolverWrapper; 41 import com.sun.org.apache.xerces.internal.util.DOMInputSource; 42 import com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper; 43 import com.sun.org.apache.xerces.internal.util.SAXInputSource; 44 import com.sun.org.apache.xerces.internal.util.SAXMessageFormatter; 45 import com.sun.org.apache.xerces.internal.util.StAXInputSource; 46 import com.sun.org.apache.xerces.internal.util.Status; 47 import com.sun.org.apache.xerces.internal.util.XMLGrammarPoolImpl; 48 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager; 49 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager; 50 import com.sun.org.apache.xerces.internal.xni.XNIException; 51 import com.sun.org.apache.xerces.internal.xni.grammars.Grammar; 52 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription; 53 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool; 54 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 55 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource; 56 import org.w3c.dom.Node; 57 import org.w3c.dom.ls.LSResourceResolver; 58 import org.xml.sax.ErrorHandler; 59 import org.xml.sax.InputSource; 60 import org.xml.sax.SAXException; 61 import org.xml.sax.SAXNotRecognizedException; 62 import org.xml.sax.SAXNotSupportedException; 63 import org.xml.sax.SAXParseException; 64 65 /** 66 * {@link SchemaFactory} for XML Schema. 67 * 68 * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) 69 */ 70 public final class XMLSchemaFactory extends SchemaFactory { 71 72 // property identifiers 73 74 /** Feature identifier: schema full checking. */ 75 private static final String SCHEMA_FULL_CHECKING = 76 Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING; 77 78 /** Property identifier: grammar pool. */ 79 private static final String XMLGRAMMAR_POOL = 80 Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; 81 82 /** Property identifier: XMLSecurityManager. */ 83 private static final String SECURITY_MANAGER = 84 Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; 85 86 /** Property identifier: Security property manager. */ 87 private static final String XML_SECURITY_PROPERTY_MANAGER = 88 Constants.XML_SECURITY_PROPERTY_MANAGER; 89 90 91 // 92 // Data 93 // 94 95 /** The XMLSchemaLoader */ 96 private final XMLSchemaLoader fXMLSchemaLoader = new XMLSchemaLoader(); 97 98 /** User-specified ErrorHandler; can be null. */ 99 private ErrorHandler fErrorHandler; 100 101 /** The LSResrouceResolver */ 102 private LSResourceResolver fLSResourceResolver; 103 104 /** The DOMEntityResolverWrapper */ 105 private final DOMEntityResolverWrapper fDOMEntityResolverWrapper; 106 107 /** The ErrorHandlerWrapper */ 108 private ErrorHandlerWrapper fErrorHandlerWrapper; 109 110 /** The SecurityManager. */ 111 private XMLSecurityManager fSecurityManager; 112 113 /** The Security property manager. */ 114 private XMLSecurityPropertyManager fSecurityPropertyMgr; 115 116 /** The container for the real grammar pool. */ 117 private XMLGrammarPoolWrapper fXMLGrammarPoolWrapper; 118 119 private final JdkXmlFeatures fXmlFeatures; 120 /** 121 * Indicates whether 3rd party parser may be used to override the system-default 122 * Note the default value (false) is the safe option. 123 * Note same as the old property useServicesMechanism 124 */ 125 private final boolean fOverrideDefaultParser; 126 127 128 public XMLSchemaFactory() { 129 fErrorHandlerWrapper = new ErrorHandlerWrapper(DraconianErrorHandler.getInstance()); 130 fDOMEntityResolverWrapper = new DOMEntityResolverWrapper(); 131 fXMLGrammarPoolWrapper = new XMLGrammarPoolWrapper(); 132 fXMLSchemaLoader.setFeature(SCHEMA_FULL_CHECKING, true); 133 fXMLSchemaLoader.setProperty(XMLGRAMMAR_POOL, fXMLGrammarPoolWrapper); 134 fXMLSchemaLoader.setEntityResolver(fDOMEntityResolverWrapper); 135 fXMLSchemaLoader.setErrorHandler(fErrorHandlerWrapper); 136 137 // Enable secure processing feature by default 138 fSecurityManager = new XMLSecurityManager(true); 139 fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager); 140 141 fSecurityPropertyMgr = new XMLSecurityPropertyManager(); 142 fXMLSchemaLoader.setProperty(XML_SECURITY_PROPERTY_MANAGER, 143 fSecurityPropertyMgr); 144 fXmlFeatures = new JdkXmlFeatures(fSecurityManager.isSecureProcessing()); 145 fOverrideDefaultParser = fXmlFeatures.getFeature( 146 JdkXmlFeatures.XmlFeature.JDK_OVERRIDE_PARSER); 147 fXMLSchemaLoader.setFeature(JdkXmlUtils.OVERRIDE_PARSER, fOverrideDefaultParser); 148 } 149 150 /** 151 * <p>Is specified schema supported by this <code>SchemaFactory</code>?</p> 152 * 153 * @param schemaLanguage Specifies the schema language which the returned <code>SchemaFactory</code> will understand. 154 * <code>schemaLanguage</code> must specify a <a href="#schemaLanguage">valid</a> schema language. 155 * 156 * @return <code>true</code> if <code>SchemaFactory</code> supports <code>schemaLanguage</code>, else <code>false</code>. 157 * 158 * @throws NullPointerException If <code>schemaLanguage</code> is <code>null</code>. 159 * @throws IllegalArgumentException If <code>schemaLanguage.length() == 0</code> 160 * or <code>schemaLanguage</code> does not specify a <a href="#schemaLanguage">valid</a> schema language. 161 */ 162 public boolean isSchemaLanguageSupported(String schemaLanguage) { 163 if (schemaLanguage == null) { 164 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 165 "SchemaLanguageNull", null)); 166 } 167 if (schemaLanguage.length() == 0) { 168 throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 169 "SchemaLanguageLengthZero", null)); 170 } 171 // only W3C XML Schema 1.0 is supported 172 return schemaLanguage.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI); 173 } 174 175 public LSResourceResolver getResourceResolver() { 176 return fLSResourceResolver; 177 } 178 179 public void setResourceResolver(LSResourceResolver resourceResolver) { 180 fLSResourceResolver = resourceResolver; 181 fDOMEntityResolverWrapper.setEntityResolver(resourceResolver); 182 fXMLSchemaLoader.setEntityResolver(fDOMEntityResolverWrapper); 183 } 184 185 public ErrorHandler getErrorHandler() { 186 return fErrorHandler; 187 } 188 189 public void setErrorHandler(ErrorHandler errorHandler) { 190 fErrorHandler = errorHandler; 191 fErrorHandlerWrapper.setErrorHandler(errorHandler != null ? errorHandler : DraconianErrorHandler.getInstance()); 192 fXMLSchemaLoader.setErrorHandler(fErrorHandlerWrapper); 193 } 194 195 public Schema newSchema( Source[] schemas ) throws SAXException { 196 197 // this will let the loader store parsed Grammars into the pool. 198 XMLGrammarPoolImplExtension pool = new XMLGrammarPoolImplExtension(); 199 fXMLGrammarPoolWrapper.setGrammarPool(pool); 200 201 XMLInputSource[] xmlInputSources = new XMLInputSource[schemas.length]; 202 InputStream inputStream; 203 Reader reader; 204 for( int i=0; i<schemas.length; i++ ) { 205 Source source = schemas[i]; 206 if (source instanceof StreamSource) { 207 StreamSource streamSource = (StreamSource) source; 208 String publicId = streamSource.getPublicId(); 209 String systemId = streamSource.getSystemId(); 210 inputStream = streamSource.getInputStream(); 211 reader = streamSource.getReader(); 212 xmlInputSources[i] = new XMLInputSource(publicId, systemId, null); 213 xmlInputSources[i].setByteStream(inputStream); 214 xmlInputSources[i].setCharacterStream(reader); 215 } 216 else if (source instanceof SAXSource) { 217 SAXSource saxSource = (SAXSource) source; 218 InputSource inputSource = saxSource.getInputSource(); 219 if (inputSource == null) { 220 throw new SAXException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 221 "SAXSourceNullInputSource", null)); 222 } 223 xmlInputSources[i] = new SAXInputSource(saxSource.getXMLReader(), inputSource); 224 } 225 else if (source instanceof DOMSource) { 226 DOMSource domSource = (DOMSource) source; 227 Node node = domSource.getNode(); 228 String systemID = domSource.getSystemId(); 229 xmlInputSources[i] = new DOMInputSource(node, systemID); 230 } 231 else if (source instanceof StAXSource) { 232 StAXSource staxSource = (StAXSource) source; 233 XMLEventReader eventReader = staxSource.getXMLEventReader(); 234 if (eventReader != null) { 235 xmlInputSources[i] = new StAXInputSource(eventReader); 236 } 237 else { 238 xmlInputSources[i] = new StAXInputSource(staxSource.getXMLStreamReader()); 239 } 240 } 241 else if (source == null) { 242 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 243 "SchemaSourceArrayMemberNull", null)); 244 } 245 else { 246 throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 247 "SchemaFactorySourceUnrecognized", 248 new Object [] {source.getClass().getName()})); 249 } 250 } 251 252 try { 253 fXMLSchemaLoader.loadGrammar(xmlInputSources); 254 } 255 catch (XNIException e) { 256 // this should have been reported to users already. 257 throw Util.toSAXException(e); 258 } 259 catch (IOException e) { 260 // this hasn't been reported, so do so now. 261 SAXParseException se = new SAXParseException(e.getMessage(),null,e); 262 fErrorHandler.error(se); 263 throw se; // and we must throw it. 264 } 265 266 // Clear reference to grammar pool. 267 fXMLGrammarPoolWrapper.setGrammarPool(null); 268 269 // Select Schema implementation based on grammar count. 270 final int grammarCount = pool.getGrammarCount(); 271 AbstractXMLSchema schema = null; 272 if (grammarCount > 1) { 273 schema = new XMLSchema(new ReadOnlyGrammarPool(pool)); 274 } 275 else if (grammarCount == 1) { 276 Grammar[] grammars = pool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_SCHEMA); 277 schema = new SimpleXMLSchema(grammars[0]); 278 } 279 else { 280 schema = new EmptyXMLSchema(); 281 } 282 propagateFeatures(schema); 283 propagateProperties(schema); 284 return schema; 285 } 286 287 public Schema newSchema() throws SAXException { 288 // Use a Schema that uses the system id as the equality source. 289 AbstractXMLSchema schema = new WeakReferenceXMLSchema(); 290 propagateFeatures(schema); 291 propagateProperties(schema); 292 return schema; 293 } 294 295 public boolean getFeature(String name) 296 throws SAXNotRecognizedException, SAXNotSupportedException { 297 if (name == null) { 298 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 299 "FeatureNameNull", null)); 300 } 301 if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { 302 return (fSecurityManager != null && fSecurityManager.isSecureProcessing()); 303 } 304 try { 305 return fXMLSchemaLoader.getFeature(name); 306 } 307 catch (XMLConfigurationException e) { 308 String identifier = e.getIdentifier(); 309 if (e.getType() == Status.NOT_RECOGNIZED) { 310 throw new SAXNotRecognizedException( 311 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 312 "feature-not-recognized", new Object [] {identifier})); 313 } 314 else { 315 throw new SAXNotSupportedException( 316 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 317 "feature-not-supported", new Object [] {identifier})); 318 } 319 } 320 } 321 322 public Object getProperty(String name) 323 throws SAXNotRecognizedException, SAXNotSupportedException { 324 if (name == null) { 325 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 326 "ProperyNameNull", null)); 327 } 328 if (name.equals(SECURITY_MANAGER)) { 329 return fSecurityManager; 330 } 331 else if (name.equals(XMLGRAMMAR_POOL)) { 332 throw new SAXNotSupportedException( 333 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 334 "property-not-supported", new Object [] {name})); 335 } 336 /** Check to see if the property is managed by the JdkXmlFeatues **/ 337 int index = fXmlFeatures.getIndex(name); 338 if (index > -1) { 339 return fXmlFeatures.getFeature(index); 340 } 341 try { 342 return fXMLSchemaLoader.getProperty(name); 343 } 344 catch (XMLConfigurationException e) { 345 String identifier = e.getIdentifier(); 346 if (e.getType() == Status.NOT_RECOGNIZED) { 347 throw new SAXNotRecognizedException( 348 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 349 "property-not-recognized", new Object [] {identifier})); 350 } 351 else { 352 throw new SAXNotSupportedException( 353 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 354 "property-not-supported", new Object [] {identifier})); 355 } 356 } 357 } 358 359 public void setFeature(String name, boolean value) 360 throws SAXNotRecognizedException, SAXNotSupportedException { 361 if (name == null) { 362 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 363 "FeatureNameNull", null)); 364 } 365 if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { 366 if (System.getSecurityManager() != null && (!value)) { 367 throw new SAXNotSupportedException( 368 SAXMessageFormatter.formatMessage(null, 369 "jaxp-secureprocessing-feature", null)); 370 } 371 372 fSecurityManager.setSecureProcessing(value); 373 if (value) { 374 if (Constants.IS_JDK8_OR_ABOVE) { 375 fSecurityPropertyMgr.setValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD, 376 XMLSecurityPropertyManager.State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP); 377 fSecurityPropertyMgr.setValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_SCHEMA, 378 XMLSecurityPropertyManager.State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP); 379 } 380 } 381 382 fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager); 383 return; 384 } else if (name.equals(Constants.ORACLE_FEATURE_SERVICE_MECHANISM)) { 385 //in secure mode, let useServicesMechanism be determined by the constructor 386 if (System.getSecurityManager() != null) 387 return; 388 } 389 390 if ((fXmlFeatures != null) && 391 fXmlFeatures.setFeature(name, JdkXmlFeatures.State.APIPROPERTY, value)) { 392 if (name.equals(JdkXmlUtils.OVERRIDE_PARSER) 393 || name.equals(Constants.ORACLE_FEATURE_SERVICE_MECHANISM)) { 394 fXMLSchemaLoader.setFeature(name, value); 395 } 396 return; 397 } 398 try { 399 fXMLSchemaLoader.setFeature(name, value); 400 } 401 catch (XMLConfigurationException e) { 402 String identifier = e.getIdentifier(); 403 if (e.getType() == Status.NOT_RECOGNIZED) { 404 throw new SAXNotRecognizedException( 405 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 406 "feature-not-recognized", new Object [] {identifier})); 407 } 408 else { 409 throw new SAXNotSupportedException( 410 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 411 "feature-not-supported", new Object [] {identifier})); 412 } 413 } 414 } 415 416 public void setProperty(String name, Object object) 417 throws SAXNotRecognizedException, SAXNotSupportedException { 418 if (name == null) { 419 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 420 "ProperyNameNull", null)); 421 } 422 if (name.equals(SECURITY_MANAGER)) { 423 fSecurityManager = XMLSecurityManager.convert(object, fSecurityManager); 424 fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager); 425 return; 426 } else if (name.equals(Constants.XML_SECURITY_PROPERTY_MANAGER)) { 427 if (object == null) { 428 fSecurityPropertyMgr = new XMLSecurityPropertyManager(); 429 } else { 430 fSecurityPropertyMgr = (XMLSecurityPropertyManager)object; 431 } 432 fXMLSchemaLoader.setProperty(Constants.XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr); 433 return; 434 } 435 else if (name.equals(XMLGRAMMAR_POOL)) { 436 throw new SAXNotSupportedException( 437 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 438 "property-not-supported", new Object [] {name})); 439 } 440 try { 441 //check if the property is managed by security manager 442 if (fSecurityManager == null || 443 !fSecurityManager.setLimit(name, XMLSecurityManager.State.APIPROPERTY, object)) { 444 //check if the property is managed by security property manager 445 if (fSecurityPropertyMgr == null || 446 !fSecurityPropertyMgr.setValue(name, XMLSecurityPropertyManager.State.APIPROPERTY, object)) { 447 //fall back to the existing property manager 448 fXMLSchemaLoader.setProperty(name, object); 449 } 450 } 451 } 452 catch (XMLConfigurationException e) { 453 String identifier = e.getIdentifier(); 454 if (e.getType() == Status.NOT_RECOGNIZED) { 455 throw new SAXNotRecognizedException( 456 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 457 "property-not-recognized", new Object [] {identifier})); 458 } 459 else { 460 throw new SAXNotSupportedException( 461 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 462 "property-not-supported", new Object [] {identifier})); 463 } 464 } 465 } 466 467 private void propagateFeatures(AbstractXMLSchema schema) { 468 schema.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, 469 (fSecurityManager != null && fSecurityManager.isSecureProcessing())); 470 schema.setFeature(JdkXmlUtils.OVERRIDE_PARSER, fOverrideDefaultParser); 471 String[] features = fXMLSchemaLoader.getRecognizedFeatures(); 472 for (int i = 0; i < features.length; ++i) { 473 boolean state = fXMLSchemaLoader.getFeature(features[i]); 474 schema.setFeature(features[i], state); 475 } 476 } 477 478 private void propagateProperties(AbstractXMLSchema schema) { 479 String[] properties = fXMLSchemaLoader.getRecognizedProperties(); 480 for (int i = 0; i < properties.length; ++i) { 481 Object state = fXMLSchemaLoader.getProperty(properties[i]); 482 schema.setProperty(properties[i], state); 483 } 484 } 485 486 487 /** 488 * Extension of XMLGrammarPoolImpl which exposes the number of 489 * grammars stored in the grammar pool. 490 */ 491 static class XMLGrammarPoolImplExtension extends XMLGrammarPoolImpl { 492 493 /** Constructs a grammar pool with a default number of buckets. */ 494 public XMLGrammarPoolImplExtension() { 495 super(); 496 } 497 498 /** Constructs a grammar pool with a specified number of buckets. */ 499 public XMLGrammarPoolImplExtension(int initialCapacity) { 500 super(initialCapacity); 501 } 502 503 /** Returns the number of grammars contained in this pool. */ 504 int getGrammarCount() { 505 return fGrammarCount; 506 } 507 508 } // XMLSchemaFactory.XMLGrammarPoolImplExtension 509 510 /** 511 * A grammar pool which wraps another. 512 */ 513 static class XMLGrammarPoolWrapper implements XMLGrammarPool { 514 515 private XMLGrammarPool fGrammarPool; 516 517 /* 518 * XMLGrammarPool methods 519 */ 520 521 public Grammar[] retrieveInitialGrammarSet(String grammarType) { 522 return fGrammarPool.retrieveInitialGrammarSet(grammarType); 523 } 524 525 public void cacheGrammars(String grammarType, Grammar[] grammars) { 526 fGrammarPool.cacheGrammars(grammarType, grammars); 527 } 528 529 public Grammar retrieveGrammar(XMLGrammarDescription desc) { 530 return fGrammarPool.retrieveGrammar(desc); 531 } 532 533 public void lockPool() { 534 fGrammarPool.lockPool(); 535 } 536 537 public void unlockPool() { 538 fGrammarPool.unlockPool(); 539 } 540 541 public void clear() { 542 fGrammarPool.clear(); 543 } 544 545 /* 546 * Other methods 547 */ 548 549 void setGrammarPool(XMLGrammarPool grammarPool) { 550 fGrammarPool = grammarPool; 551 } 552 553 XMLGrammarPool getGrammarPool() { 554 return fGrammarPool; 555 } 556 557 } // XMLSchemaFactory.XMLGrammarPoolWrapper 558 559 } // XMLSchemaFactory