Skip to content

Commit

Permalink
Adding EntityResolver support to WFS-NG
Browse files Browse the repository at this point in the history
  • Loading branch information
aaime committed Sep 27, 2016
1 parent 89c552e commit cfe895c
Show file tree
Hide file tree
Showing 21 changed files with 1,079 additions and 15 deletions.
@@ -0,0 +1,78 @@
/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2016, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.xml;

import java.io.IOException;
import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.geotools.util.logging.Logging;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.ext.EntityResolver2;


/**
* EntityResolver implementation to prevent usage of external entities.
*
* When parsing an XML entity, the empty InputSource returned by this resolver provokes
* throwing of a java.net.MalformedURLException, which can be handled appropriately.
*
* @author Davide Savazzi - geo-solutions.it
*/
public class NoExternalEntityResolver implements EntityResolver2, Serializable {

private static final long serialVersionUID = -8477717248646603150L;
public static final String ERROR_MESSAGE_BASE = "Entity resolution disallowed for ";
private static final Logger LOGGER = Logging.getLogger(NoExternalEntityResolver.class);
public static final NoExternalEntityResolver INSTANCE = new NoExternalEntityResolver();

protected NoExternalEntityResolver() {
// singleton
}

@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.finest("resolveEntity request: publicId=" + publicId + ", systemId=" + systemId);
}

// allow schema parsing for validation.
// http(s) - external schema reference
// jar - internal schema reference
// vfs - internal schema reference (JBOSS)
if (systemId != null && systemId.matches("(?i)(jar:file|http|vfs)[^?#;]*\\.xsd")) {
return null;
}

// do not allow external entities
throw new SAXException(ERROR_MESSAGE_BASE + systemId);
}

@Override
public InputSource getExternalSubset(String name, String baseURI)
throws SAXException, IOException {
return null;
}

@Override
public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId)
throws SAXException, IOException {
return resolveEntity(publicId, systemId);
}
}
Expand Up @@ -53,6 +53,7 @@
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.FeatureType;
import org.opengis.feature.type.Name;
import org.xml.sax.EntityResolver;

import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.impl.PackedCoordinateSequenceFactory;
Expand All @@ -73,7 +74,7 @@ public class WFSDataStore extends ContentDataStore {

protected Map<String, String> configuredStoredQueries =
new ConcurrentHashMap<String, String>();

public WFSDataStore(final WFSClient client) {
this.client = client;
this.names = new ConcurrentHashMap<Name, QName>();
Expand All @@ -94,7 +95,7 @@ public WFSDataStore(final WFSClient client) {
public WFSServiceInfo getInfo() {
return client.getInfo();
}

@Override
protected WFSContentState createContentState(ContentEntry entry) {
return new WFSContentState(entry);
Expand Down
Expand Up @@ -42,9 +42,11 @@
import org.geotools.ows.ServiceException;
import org.geotools.util.KVP;
import org.geotools.util.SimpleInternationalString;
import org.geotools.xml.NoExternalEntityResolver;
import org.geotools.xml.XMLHandlerHints;
import org.opengis.feature.Feature;
import org.opengis.feature.type.FeatureType;
import org.xml.sax.EntityResolver;

/**
* The factory responsible for creating WFSDataAccess objects based on their capabilities and the configuration file used. This file is included as a
Expand Down Expand Up @@ -119,7 +121,7 @@ public T lookUp(final Map params) throws IOException {
}

/** Access with {@link WFSDataStoreFactory#getParametersInfo() */
private static final WFSFactoryParam<?>[] parametersInfo = new WFSFactoryParam[19];
private static final WFSFactoryParam<?>[] parametersInfo = new WFSFactoryParam[20];

private static final int GMLComplianceLevel = 2;

Expand Down Expand Up @@ -412,6 +414,18 @@ public T lookUp(final Map params) throws IOException {
parametersInfo[18] = GML_COMPATIBLE_TYPENAMES = new WFSFactoryParam<Boolean>(name,
Boolean.class, title, description, false);
}

/**
* Optional {@link EntityResolver} used to expand XML entities during parses
*/
public static final WFSFactoryParam<EntityResolver> ENTITY_RESOLVER;
static {
String name = "WFSDataStoreFactory:ENTITY_RESOLVER";
String title = "EntityResolver";
String description = "Sets the entity resolver used to expand XML entities";
parametersInfo[19] = ENTITY_RESOLVER = new WFSFactoryParam<EntityResolver>(name,
EntityResolver.class, title, description, NoExternalEntityResolver.INSTANCE, Parameter.LEVEL, "program");
}


/**
Expand Down
Expand Up @@ -18,12 +18,15 @@

import java.io.IOException;
import java.net.URL;
import java.util.Map;

import org.geotools.data.ows.AbstractGetCapabilitiesRequest;
import org.geotools.data.ows.HTTPResponse;
import org.geotools.data.ows.Request;
import org.geotools.data.ows.Response;
import org.geotools.ows.ServiceException;
import org.geotools.xml.XMLHandlerHints;
import org.xml.sax.EntityResolver;

public class GetCapabilitiesRequest extends AbstractGetCapabilitiesRequest {

Expand All @@ -48,7 +51,12 @@ protected void initVersion() {

@Override
public Response createResponse(HTTPResponse response) throws ServiceException, IOException {
return new GetCapabilitiesResponse(response);
Map<String, Object> hints = getRequestHints();
EntityResolver resolver = null;
if(hints != null) {
resolver = (EntityResolver) hints.get(XMLHandlerHints.ENTITY_RESOLVER);
}
return new GetCapabilitiesResponse(response, resolver);
}

}
Expand Up @@ -45,12 +45,17 @@
import org.geotools.xml.Configuration;
import org.geotools.xml.DOMParser;
import org.w3c.dom.Document;
import org.xml.sax.EntityResolver;

public class GetCapabilitiesResponse extends org.geotools.data.ows.GetCapabilitiesResponse {

private WFSGetCapabilities capabilities;

public GetCapabilitiesResponse(HTTPResponse response) throws IOException, ServiceException {

// public GetCapabilitiesResponse(HTTPResponse response) throws IOException, ServiceException {
// this(response, null);
// }

public GetCapabilitiesResponse(HTTPResponse response, EntityResolver entityResolver) throws IOException, ServiceException {
super(response);
MODULE.finer("Parsing GetCapabilities response");
try {
Expand All @@ -74,6 +79,9 @@ public GetCapabilitiesResponse(HTTPResponse response) throws IOException, Servic
builderFactory.setNamespaceAware(true);
builderFactory.setValidating(false);
DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
if(entityResolver != null) {
documentBuilder.setEntityResolver(entityResolver);
}
rawDocument = documentBuilder.parse(new ByteArrayInputStream(rawResponse));
} catch (Exception e) {
throw new IOException("Error parsing capabilities document: " + e.getMessage(), e);
Expand Down
Expand Up @@ -20,6 +20,7 @@

import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand All @@ -44,6 +45,7 @@
import org.geotools.ows.ServiceException;
import org.geotools.util.Version;
import org.geotools.util.logging.Logging;
import org.geotools.xml.XMLHandlerHints;
import org.opengis.filter.Filter;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.w3c.dom.Document;
Expand All @@ -65,7 +67,7 @@ public WFSClient(URL capabilitiesURL, HTTPClient httpClient, WFSConfig config)
public WFSClient(URL capabilitiesURL, HTTPClient httpClient, WFSConfig config,
WFSGetCapabilities capabilities) throws IOException, ServiceException {

super(capabilitiesURL, httpClient, capabilities);
super(capabilitiesURL, httpClient, capabilities, Collections.singletonMap(XMLHandlerHints.ENTITY_RESOLVER, config.getEntityResolver()));
this.config = config;
super.specification = determineCorrectStrategy();
((WFSStrategy) specification).setCapabilities(super.capabilities);
Expand Down
Expand Up @@ -32,6 +32,7 @@
import static org.geotools.data.wfs.WFSDataStoreFactory.AXIS_ORDER;
import static org.geotools.data.wfs.WFSDataStoreFactory.AXIS_ORDER_FILTER;
import static org.geotools.data.wfs.WFSDataStoreFactory.GML_COMPATIBLE_TYPENAMES;
import static org.geotools.data.wfs.WFSDataStoreFactory.ENTITY_RESOLVER;

import java.io.IOException;
import java.nio.charset.Charset;
Expand All @@ -46,6 +47,7 @@
import org.geotools.referencing.CRS;
import org.opengis.feature.type.Name;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.xml.sax.EntityResolver;

/**
* @see WFSStrategy#setConfig(WFSConfig)
Expand Down Expand Up @@ -85,6 +87,8 @@ public class WFSConfig {
protected String axisOrderFilter;

protected boolean gmlCompatibleTypenames;

protected EntityResolver entityResolver;

public static enum PreferredHttpMethod {
AUTO, HTTP_GET, HTTP_POST
Expand All @@ -106,6 +110,7 @@ public WFSConfig() {
filterCompliance = (Integer) FILTER_COMPLIANCE.getDefaultValue();
namespaceOverride = (String) NAMESPACE.getDefaultValue();
gmlCompatibleTypenames = (Boolean) GML_COMPATIBLE_TYPENAMES.getDefaultValue();
entityResolver = (EntityResolver) ENTITY_RESOLVER.getDefaultValue();
}

public static WFSConfig fromParams(Map<?, ?> params) throws IOException {
Expand Down Expand Up @@ -142,7 +147,8 @@ public static WFSConfig fromParams(Map<?, ?> params) throws IOException {

config.gmlCompatibleTypenames = GML_COMPATIBLE_TYPENAMES.lookUp(params) == null ?
(Boolean) GML_COMPATIBLE_TYPENAMES.getDefaultValue() : GML_COMPATIBLE_TYPENAMES.lookUp(params);

config.entityResolver = ENTITY_RESOLVER.lookUp(params);

return config;
}

Expand Down Expand Up @@ -265,6 +271,14 @@ public String getAxisOrderFilter() {
public boolean isGmlCompatibleTypenames() {
return gmlCompatibleTypenames;
}

/**
* Returns the entity resolved to be used for XML parses
* @return
*/
public EntityResolver getEntityResolver() {
return entityResolver;
}

/**
* Checks if axis flipping is needed comparing axis order requested for the DataStore with query crs.
Expand Down Expand Up @@ -303,4 +317,5 @@ public String localTypeName(QName remoteTypeName) {
}
return localTypeName;
}

}
Expand Up @@ -43,6 +43,7 @@
import org.geotools.data.wfs.internal.WFSResponseFactory;
import org.geotools.ows.ServiceException;
import org.geotools.xml.Parser;
import org.xml.sax.EntityResolver;

/**
* An abstract WFS response parser factory for GetFeature requests in GML output formats.
Expand Down Expand Up @@ -172,6 +173,10 @@ public WFSResponse createResponse(WFSRequest request, HTTPResponse response) thr
*/
public WFSException parseException(WFSRequest originatingRequest, InputStream inputStream) throws WFSException {
Parser parser = new Parser(originatingRequest.getStrategy().getWfsConfiguration());
EntityResolver resolver = originatingRequest.getStrategy().getConfig().getEntityResolver();
if(resolver != null) {
parser.setEntityResolver(resolver);
}
Object parsed;
try {
parsed = parser.parse(inputStream);
Expand Down
Expand Up @@ -39,6 +39,7 @@
import org.geotools.xml.Configuration;
import org.geotools.xml.Parser;
import org.opengis.filter.identity.FeatureId;
import org.xml.sax.EntityResolver;
import org.xml.sax.SAXException;

public class TransactionResponseImpl extends WFSResponse implements TransactionResponse {
Expand All @@ -63,6 +64,10 @@ public TransactionResponseImpl(WFSRequest originatingRequest, HTTPResponse respo
WFSStrategy strategy = originatingRequest.getStrategy();
Configuration wfsConfiguration = strategy.getWfsConfiguration();
Parser parser = new Parser(wfsConfiguration);
EntityResolver resolver = strategy.getConfig().getEntityResolver();
if(resolver != null) {
parser.setEntityResolver(resolver);
}
InputStream input = response.getResponseStream();
parsed = parser.parse(input);
} catch (SAXException e) {
Expand Down
Expand Up @@ -39,6 +39,7 @@
import org.geotools.xml.Configuration;
import org.geotools.xml.Parser;
import org.opengis.filter.identity.FeatureId;
import org.xml.sax.EntityResolver;
import org.xml.sax.SAXException;

public class TransactionResponseImpl extends WFSResponse implements TransactionResponse {
Expand All @@ -63,6 +64,10 @@ public TransactionResponseImpl(WFSRequest originatingRequest, HTTPResponse respo
WFSStrategy strategy = originatingRequest.getStrategy();
Configuration wfsConfiguration = strategy.getWfsConfiguration();
Parser parser = new Parser(wfsConfiguration);
EntityResolver resolver = strategy.getConfig().getEntityResolver();
if(resolver != null) {
parser.setEntityResolver(resolver);
}
InputStream input = response.getResponseStream();
parsed = parser.parse(input);
} catch (SAXException e) {
Expand Down

0 comments on commit cfe895c

Please sign in to comment.