public void checkPermission( ExtractorLayerRequest request, String secureHost, String username, String roles) throws IOException { URL capabilitiesURL = request.capabilitiesURL("WFS", "1.0.0"); final HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); httpClientBuilder.setUserAgent(this.userAgent); HttpClientContext localContext = HttpClientContext.create(); final HttpHost httpHost = new HttpHost( capabilitiesURL.getHost(), capabilitiesURL.getPort(), capabilitiesURL.getProtocol()); HttpGet get = new HttpGet(capabilitiesURL.toExternalForm()); if (username != null && (secureHost.equalsIgnoreCase(request._url.getHost()) || "127.0.0.1".equalsIgnoreCase(request._url.getHost()) || "localhost".equalsIgnoreCase(request._url.getHost()))) { LOG.debug( "WfsExtractor.checkPermission - Secured Server: adding username header and role headers to request for checkPermission"); addImpersonateUserHeaders(username, roles, get); enablePreemptiveBasicAuth( capabilitiesURL, httpClientBuilder, localContext, httpHost, _adminUsername, _adminPassword); } else { // use a user agent that does *not* trigger basic auth on remote server httpClientBuilder.setUserAgent("Apache-HttpClient"); LOG.debug("WfsExtractor.checkPermission - Non Secured Server"); } final CloseableHttpClient httpclient = httpClientBuilder.build(); String capabilities = FileUtils.asString( httpclient.execute(httpHost, get, localContext).getEntity().getContent()); Pattern regex = Pattern.compile( "(?m)<FeatureType[^>]*>(\\\\n|\\s)*<Name>\\s*(\\w*:)?" + Pattern.quote(request._layerName) + "\\s*</Name>"); boolean permitted = regex.matcher(capabilities).find(); if (!permitted) { throw new SecurityException( "User does not have sufficient privileges to access the Layer: " + request._layerName + ". \n\nCapabilities: " + capabilities); } }
/* This method is default for testing purposes */ Query createQuery(ExtractorLayerRequest request, FeatureType schema) throws IOException, TransformException, FactoryException { switch (request._owsType) { case WFS: // bbox may not be in the same projection as the data so it sometimes necessary to reproject // the request BBOX ReferencedEnvelope bbox = request._bbox; if (schema.getCoordinateReferenceSystem() != null) { bbox = request._bbox.transform(schema.getCoordinateReferenceSystem(), true, 10); } FilterFactory2 filterFactory = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints()); String propertyName = schema.getGeometryDescriptor().getLocalName(); PropertyName geomProperty = filterFactory.property(propertyName); Geometry bboxGeom = new GeometryFactory().toGeometry(bbox); String epsgCode = "EPSG:" + CRS.lookupEpsgCode(bbox.getCoordinateReferenceSystem(), false); bboxGeom.setUserData(epsgCode); Literal geometry = filterFactory.literal(bboxGeom); Intersects filter = filterFactory.intersects(geomProperty, geometry); List<String> properties = new ArrayList<String>(); for (PropertyDescriptor desc : schema.getDescriptors()) { if (desc instanceof GeometryDescriptor && desc != schema.getGeometryDescriptor()) { // shapefiles can only have one geometry so skip any // geometry descriptor that is not the default continue; } else { properties.add(desc.getName().getLocalPart()); } } String[] propArray = properties.toArray(new String[properties.size()]); Query query = new Query(request.getWFSName(), filter, propArray); query.setCoordinateSystemReproject(request._projection); return query; default: return null; } }
/** * Extract the data as defined in the request object. * * @return the directory that contains the extracted file */ public File extract(ExtractorLayerRequest request) throws IOException, TransformException, FactoryException { if (request._owsType != OWSType.WFS) { throw new IllegalArgumentException(request._owsType + "must be WFS for the WfsExtractor"); } Map<String, Serializable> params = new HashMap<String, Serializable>(); params.put(WFSDataStoreFactory.URL.key, request.capabilitiesURL("WFS", "1.0.0")); params.put(WFSDataStoreFactory.LENIENT.key, true); params.put(WFSDataStoreFactory.PROTOCOL.key, true); params.put(WFSDataStoreFactory.TIMEOUT.key, Integer.valueOf(60000)); params.put(WFSDataStoreFactory.MAXFEATURES.key, Integer.valueOf(0)); // HACK I want unrestricted access to layers. // Security check takes place in ExtractorThread if (_secureHost.equalsIgnoreCase(request._url.getHost()) || "127.0.0.1".equalsIgnoreCase(request._url.getHost()) || "localhost".equalsIgnoreCase(request._url.getHost())) { LOG.debug( "WfsExtractor.extract - Secured Server: Adding extractionUserName to connection params"); if (_adminUsername != null) params.put(WFSDataStoreFactory.USERNAME.key, _adminUsername); if (_adminPassword != null) params.put(WFSDataStoreFactory.PASSWORD.key, _adminPassword); } else { LOG.debug("WfsExtractor.extract - Non Secured Server"); } DataStore sourceDs = DataStoreFinder.getDataStore(params); // WFS-ng: we need to convert the schema name String typeName = request.getWFSName(); SimpleFeatureType sourceSchema = null; // prefixed typeName if (typeName.contains(":")) { typeName = typeName.replaceFirst(":", "_"); sourceSchema = sourceDs.getSchema(typeName); } // Not prefixed one (mapserver ?) else { // Recreating the datastore forcing wfs 1.1.0, so that (presuming // the remote server is actually powered by MapServer), we would // have a typename prefixed with the same convention as before. params.put(WFSDataStoreFactory.URL.key, request.capabilitiesURL("WFS", "1.1.0")); // params.put(WFSDataStoreFactory.WFS_STRATEGY.key, "mapserver"); sourceDs = DataStoreFinder.getDataStore(params); String[] typeNames = sourceDs.getTypeNames(); for (String s : typeNames) { if (s.contains(typeName)) { typeName = s; sourceSchema = sourceDs.getSchema(s); // replace the expected typename in the request break; } } if (sourceSchema == null) { throw new IOException("Unable to find the remote layer " + typeName); } } Query query = createQuery(request, sourceSchema); SimpleFeatureCollection features = sourceDs.getFeatureSource(typeName).getFeatures(query); ProgressListener progressListener = new NullProgressListener() { @Override public void exceptionOccurred(Throwable exception) { throw new RuntimeException(exception); } }; File basedir = request.createContainingDir(_basedir); basedir.mkdirs(); FeatureWriterStrategy featuresWriter; BBoxWriter bboxWriter; LOG.debug("Number of features returned : " + features.size()); if ("shp".equalsIgnoreCase(request._format)) { featuresWriter = new ShpFeatureWriter(progressListener, sourceSchema, basedir, features); bboxWriter = new BBoxWriter( request._bbox, basedir, OGRFeatureWriter.FileFormat.shp, request._projection, progressListener); } else if ("mif".equalsIgnoreCase(request._format)) { // featuresWriter = new MifFeatureWriter(progressListener, sourceSchema, basedir, features); featuresWriter = new OGRFeatureWriter( progressListener, sourceSchema, basedir, OGRFeatureWriter.FileFormat.mif, features); bboxWriter = new BBoxWriter( request._bbox, basedir, OGRFeatureWriter.FileFormat.mif, request._projection, progressListener); } else if ("tab".equalsIgnoreCase(request._format)) { featuresWriter = new OGRFeatureWriter( progressListener, sourceSchema, basedir, OGRFeatureWriter.FileFormat.tab, features); bboxWriter = new BBoxWriter( request._bbox, basedir, OGRFeatureWriter.FileFormat.tab, request._projection, progressListener); } else if ("kml".equalsIgnoreCase(request._format)) { featuresWriter = new OGRFeatureWriter( progressListener, sourceSchema, basedir, OGRFeatureWriter.FileFormat.kml, features); bboxWriter = new BBoxWriter( request._bbox, basedir, OGRFeatureWriter.FileFormat.kml, request._projection, progressListener); } else { throw new IllegalArgumentException(request._format + " is not a recognized vector format"); } // generates the feature files and bbox file featuresWriter.generateFiles(); bboxWriter.generateFiles(); return basedir; }