/* * Copyright (C) 2007 - 2017 GeoSolutions S.A.S. * http://www.geo-solutions.it * * GPLv3 + Classpath exception * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.geoserver.geofence; import java.io.IOException; import java.net.InetAddress; import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.http.HttpServletRequest; import com.lowagie.text.Paragraph; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.CatalogInfo; import org.geoserver.catalog.CoverageInfo; import org.geoserver.catalog.FeatureTypeInfo; import org.geoserver.catalog.LayerGroupInfo; import org.geoserver.catalog.LayerInfo; import org.geoserver.catalog.Predicates; import org.geoserver.catalog.PublishedInfo; import org.geoserver.catalog.ResourceInfo; import org.geoserver.catalog.StoreInfo; import org.geoserver.catalog.StyleInfo; import org.geoserver.catalog.WMSLayerInfo; import org.geoserver.catalog.WorkspaceInfo; import org.geoserver.geofence.config.GeoFenceConfiguration; import org.geoserver.geofence.config.GeoFenceConfigurationManager; import org.geoserver.geofence.core.model.LayerAttribute; import org.geoserver.geofence.core.model.enums.AccessType; import org.geoserver.geofence.core.model.enums.GrantType; import org.geoserver.geofence.services.RuleReaderService; import org.geoserver.geofence.services.dto.AccessInfo; import org.geoserver.geofence.services.dto.RuleFilter; import org.geoserver.ows.Dispatcher; import org.geoserver.ows.DispatcherCallback; import org.geoserver.ows.LocalWorkspace; import org.geoserver.ows.Request; import org.geoserver.ows.Response; import org.geoserver.ows.util.KvpUtils; import org.geoserver.platform.Operation; import org.geoserver.platform.Service; import org.geoserver.platform.ServiceException; import org.geoserver.security.CatalogMode; import org.geoserver.security.CoverageAccessLimits; import org.geoserver.security.DataAccessLimits; import org.geoserver.security.LayerGroupAccessLimits; import org.geoserver.security.ResourceAccessManager; import org.geoserver.security.StyleAccessLimits; import org.geoserver.security.VectorAccessLimits; import org.geoserver.security.WMSAccessLimits; import org.geoserver.security.WorkspaceAccessLimits; import org.geoserver.security.impl.GeoServerRole; import org.geoserver.wms.*; import org.geoserver.wms.map.GetMapKvpRequestReader; import org.geotools.factory.CommonFactoryFinder; import org.geotools.filter.text.cql2.CQLException; import org.geotools.filter.text.ecql.ECQL; import org.geotools.geometry.jts.JTS; import org.geotools.referencing.CRS; import org.geotools.styling.Style; import org.geotools.util.Converters; import org.geotools.util.logging.Logging; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.expression.PropertyName; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.MultiPolygon; import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKTReader; /** * Makes GeoServer use the Geofence to assess data access rules * * @author Andrea Aime - GeoSolutions * @author Emanuele Tajariol- GeoSolutions */ public class GeofenceAccessManager implements ResourceAccessManager, DispatcherCallback { private static final Logger LOGGER = Logging.getLogger(GeofenceAccessManager.class); /** * The role given to the administrators */ static final String ROOT_ROLE = "ROLE_ADMINISTRATOR"; static final FilterFactory2 FF = CommonFactoryFinder.getFilterFactory2(null); enum PropertyAccessMode { READ, WRITE } static final CatalogMode DEFAULT_CATALOG_MODE = CatalogMode.HIDE; RuleReaderService rules; Catalog catalog; private final GeoFenceConfigurationManager configurationManager; // list of accepted roles, for the useRolesToFilter option // List<String> roles = new ArrayList<String>(); public GeofenceAccessManager(RuleReaderService rules, Catalog catalog, GeoFenceConfigurationManager configurationManager) { this.rules = rules; this.catalog = catalog; this.configurationManager = configurationManager; } boolean isAdmin(Authentication user) { if (user.getAuthorities() != null) { for (GrantedAuthority authority : user.getAuthorities()) { final String userRole = authority.getAuthority(); if (ROOT_ROLE.equals(userRole) || GeoServerRole.ADMIN_ROLE.getAuthority().equals(userRole) ) { return true; } } } return false; } @Override public WorkspaceAccessLimits getAccessLimits(Authentication user, WorkspaceInfo workspace) { LOGGER.log(Level.FINE, "Getting access limits for workspace {0}", workspace.getName()); if ((user != null) && !(user instanceof AnonymousAuthenticationToken)) { // shortcut, if the user is the admin, he can do everything if (isAdmin(user)) { LOGGER.log(Level.FINE, "Admin level access, returning " + "full rights for workspace {0}", workspace.getName()); return new WorkspaceAccessLimits(DEFAULT_CATALOG_MODE, true, true); } boolean canWrite = configurationManager.getConfiguration().isGrantWriteToWorkspacesToAuthenticatedUsers(); boolean canAdmin = isWorkspaceAdmin(user, workspace.getName()); return new WorkspaceAccessLimits(DEFAULT_CATALOG_MODE, true, canWrite, canAdmin); } // further logic disabled because of https://github.com/geosolutions-it/geofence/issues/6 return new WorkspaceAccessLimits(DEFAULT_CATALOG_MODE, true, false); } /** * We expect the user not to be null and not to be admin */ private boolean isWorkspaceAdmin(Authentication user, String workspaceName) { LOGGER.log(Level.FINE, "Getting admin auth for Workspace {0}", workspaceName); // get the request infos RuleFilter ruleFilter = new RuleFilter(RuleFilter.SpecialFilterType.ANY); ruleFilter.setInstance(configurationManager.getConfiguration().getInstanceName()); ruleFilter.setWorkspace(workspaceName); ruleFilter.setUser(user.getName()); String sourceAddress = retrieveCallerIpAddress(); if(sourceAddress != null) { ruleFilter.setSourceAddress(sourceAddress); } else { LOGGER.log(Level.WARNING, "No source IP address found"); ruleFilter.setSourceAddress(RuleFilter.SpecialFilterType.DEFAULT); } if(LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "AdminAuth filter: {0}", ruleFilter); } AccessInfo auth = rules.getAdminAuthorization(ruleFilter); LOGGER.log(Level.FINE, "Admin auth for User:{0} Workspace:{1}: {2}", new Object[]{user.getName(), workspaceName, auth.getAdminRights()}); return auth.getAdminRights(); } String getSourceAddress(HttpServletRequest http) { try { if (http == null) { LOGGER.log(Level.WARNING, "No HTTP connection available."); return null; } String forwardedFor = http.getHeader("X-Forwarded-For"); if (forwardedFor != null) { String[] ips = forwardedFor.split(", "); return InetAddress.getByName(ips[0]).getHostAddress(); } else { return http.getRemoteAddr(); } } catch (Exception e) { LOGGER.log(Level.INFO, "Failed to get remote address", e); return null; } } private String retrieveCallerIpAddress() { // is this an OWS request Request owsRequest = Dispatcher.REQUEST.get(); if(owsRequest != null ) { HttpServletRequest httpReq = owsRequest.getHttpRequest(); String sourceAddress = getSourceAddress(httpReq); if(sourceAddress == null) { LOGGER.log(Level.WARNING, "Could not retrieve source address from OWSRequest"); } return sourceAddress; } // try Spring try { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); String sourceAddress = getSourceAddress(request); if(sourceAddress == null) { LOGGER.log(Level.WARNING, "Could not retrieve source address with Spring Request"); } return sourceAddress; } catch (IllegalStateException ex) { LOGGER.log(Level.WARNING, "Error retrieving source address with Spring Request: " + ex.getMessage()); return null; } } // private WorkspaceAccessLimits buildAccessLimits(WorkspaceInfo workspace, AccessInfo rule) { // if (rule == null) { // return new WorkspaceAccessLimits(DEFAULT_CATALOG_MODE, true, true); // } else { // return new WorkspaceAccessLimits(DEFAULT_CATALOG_MODE, rule.getGrant() == GrantType.ALLOW, rule.getGrant() == GrantType.ALLOW); // } // } @Override public StyleAccessLimits getAccessLimits(Authentication user, StyleInfo style) { //return getAccessLimits(user, style.getResource()); LOGGER.fine("Not limiting styles"); return null; // TODO } @Override public LayerGroupAccessLimits getAccessLimits(Authentication user, LayerGroupInfo layerInfo) { //return getAccessLimits(user, layerInfo.getResource()); LOGGER.fine("Not limiting layergroups"); return null; // TODO } @Override public DataAccessLimits getAccessLimits(Authentication user, LayerInfo layer) { LOGGER.log(Level.FINE, "Getting access limits for Layer {0}", layer.getName()); return getAccessLimits(user, layer.getResource()); } @Override public DataAccessLimits getAccessLimits(Authentication user, ResourceInfo resource) { LOGGER.log(Level.FINE, "Getting access limits for Resource {0}", resource.getName()); // extract the user name String username = null; if ((user != null) && !(user instanceof AnonymousAuthenticationToken)) { // shortcut, if the user is the admin, he can do everything if (isAdmin(user)) { LOGGER.log(Level.FINE, "Admin level access, returning " + "full rights for layer {0}", resource.getPrefixedName()); return buildAccessLimits(resource, AccessInfo.ALLOW_ALL); } username = user.getName(); } // get info from the current request String service = null; String request = null; Request owsRequest = Dispatcher.REQUEST.get(); if (owsRequest != null) { service = owsRequest.getService(); request = owsRequest.getRequest(); } // get the resource info String layer = resource.getName(); StoreInfo store = resource.getStore(); WorkspaceInfo ws = store.getWorkspace(); String workspace = ws.getName(); // get the request infos RuleFilter ruleFilter = new RuleFilter(RuleFilter.SpecialFilterType.ANY); setRuleFilterUserOrRole(user, ruleFilter); ruleFilter.setInstance(configurationManager.getConfiguration().getInstanceName()); if (service != null) { if ("*".equals(service)) { ruleFilter.setService(RuleFilter.SpecialFilterType.ANY); } else { ruleFilter.setService(service); } } else { ruleFilter.setService(RuleFilter.SpecialFilterType.DEFAULT); } if (request != null) { if ("*".equals(request)) { ruleFilter.setRequest(RuleFilter.SpecialFilterType.ANY); } else { ruleFilter.setRequest(request); } } else { ruleFilter.setRequest(RuleFilter.SpecialFilterType.DEFAULT); } ruleFilter.setWorkspace(workspace); ruleFilter.setLayer(layer); String sourceAddress = retrieveCallerIpAddress(); if(sourceAddress != null) { ruleFilter.setSourceAddress(sourceAddress); } else { LOGGER.log(Level.WARNING, "No source IP address found"); ruleFilter.setSourceAddress(RuleFilter.SpecialFilterType.DEFAULT); } LOGGER.log(Level.FINE, "ResourceInfo filter: {0}", ruleFilter); AccessInfo rule = rules.getAccessInfo(ruleFilter); if (rule == null) { rule = AccessInfo.DENY_ALL; } DataAccessLimits limits = buildAccessLimits(resource, rule); LOGGER.log(Level.FINE, "Returning {0} for layer {1} and user {2}", new Object[] { limits, resource.getPrefixedName(), username }); return limits; } /** * @param user */ private void setRuleFilterUserOrRole(Authentication user, RuleFilter ruleFilter) { if (user != null) { GeoFenceConfiguration config = configurationManager.getConfiguration(); if (config.isUseRolesToFilter() && config.getRoles().size() > 0) { String role = "UNKNOWN"; for (GrantedAuthority authority : user.getAuthorities()) { if (config.getRoles().contains(authority.getAuthority())) { role = authority.getAuthority(); } } LOGGER.log(Level.FINE, "Setting role for filter: {0}", new Object[] { role }); ruleFilter.setRole(role); } else { String username = user.getName(); if (username == null) { ruleFilter.setUser(RuleFilter.SpecialFilterType.DEFAULT); } else { LOGGER.log(Level.FINE, "Setting user for filter: {0}", new Object[] { username }); ruleFilter.setUser(username); } } } else { ruleFilter.setUser(RuleFilter.SpecialFilterType.DEFAULT); } } /** * @param resource * @param rule * */ DataAccessLimits buildAccessLimits(ResourceInfo resource, AccessInfo rule) { // basic filter Filter readFilter = (rule.getGrant() == GrantType.ALLOW) ? Filter.INCLUDE : Filter.EXCLUDE; Filter writeFilter = (rule.getGrant() == GrantType.ALLOW) ? Filter.INCLUDE : Filter.EXCLUDE; try { if (rule.getCqlFilterRead() != null) { readFilter = ECQL.toFilter(rule.getCqlFilterRead()); } if (rule.getCqlFilterWrite() != null) { writeFilter = ECQL.toFilter(rule.getCqlFilterWrite()); } } catch (CQLException e) { throw new IllegalArgumentException("Invalid cql filter found: " + e.getMessage(), e); } // get the attributes List<PropertyName> readAttributes = toPropertyNames(rule.getAttributes(), PropertyAccessMode.READ); List<PropertyName> writeAttributes = toPropertyNames(rule.getAttributes(), PropertyAccessMode.WRITE); // reproject the area if necessary Geometry area = null; String areaWkt = rule.getAreaWkt(); if(areaWkt != null) { try { // Geometry area = rule.getArea(); WKTReader wktReader = new WKTReader(); area = wktReader.read(areaWkt); if (area != null) { // rule area is always expressed as 4326 CoordinateReferenceSystem geomCrs = CRS.decode("EPSG:4326"); CoordinateReferenceSystem resourceCrs = resource.getCRS(); if ((resourceCrs != null) && !CRS.equalsIgnoreMetadata(geomCrs, resourceCrs)) { MathTransform mt = CRS.findMathTransform(geomCrs, resourceCrs, true); area = JTS.transform(area, mt); } } } catch (ParseException e) { throw new RuntimeException("Failed to unmarshal the restricted area wkt", e); } catch (Exception e) { throw new RuntimeException("Failed to reproject the restricted area to the layer's native SRS", e); } } CatalogMode catalogMode = DEFAULT_CATALOG_MODE; if(rule.getCatalogMode() != null) { switch(rule.getCatalogMode()) { case CHALLENGE: catalogMode = CatalogMode.CHALLENGE; break; case HIDE: catalogMode = CatalogMode.HIDE; break; case MIXED: catalogMode = CatalogMode.MIXED; break; } } LOGGER.log(Level.FINE, "Returning mode {0} for resource {1}", new Object[] { catalogMode, resource }); if (resource instanceof FeatureTypeInfo) { // merge the area among the filters if (area != null) { Filter areaFilter = FF.intersects(FF.property(""), FF.literal(area)); readFilter = mergeFilter(readFilter, areaFilter); writeFilter = mergeFilter(writeFilter, areaFilter); } return new VectorAccessLimits(catalogMode, readAttributes, readFilter, writeAttributes, writeFilter); } else if (resource instanceof CoverageInfo) { MultiPolygon rasterFilter = buildRasterFilter(rule); return new CoverageAccessLimits(catalogMode, readFilter, rasterFilter, null); } else if (resource instanceof WMSLayerInfo) { MultiPolygon rasterFilter = buildRasterFilter(rule); return new WMSAccessLimits(catalogMode, readFilter, rasterFilter, true); } else { throw new IllegalArgumentException("Don't know how to handle resource " + resource); } } private MultiPolygon buildRasterFilter(AccessInfo rule) { MultiPolygon rasterFilter = null; if (rule.getAreaWkt() != null) { WKTReader reader = new WKTReader(); Geometry area = null; try { area = reader.read(rule.getAreaWkt()); } catch (ParseException e) { throw new RuntimeException("Failed to unmarshal the restricted area wkt", e); } rasterFilter = Converters.convert(area, MultiPolygon.class); if (rasterFilter == null) { throw new RuntimeException("Error applying security rules, cannot convert " + "the Geofence area restriction " + rule.getAreaWkt() + " to a multi-polygon"); } } return rasterFilter; } /** * Merges the two filters into one by AND * * @param filter * @param areaFilter * */ private Filter mergeFilter(Filter filter, Filter areaFilter) { if ((filter == null) || (filter == Filter.INCLUDE)) { return areaFilter; } else if (filter == Filter.EXCLUDE) { return filter; } else { return FF.and(filter, areaFilter); } } /** * Builds the equivalent {@link PropertyName} list for the specified access mode * * @param attributes * @param mode * */ private List<PropertyName> toPropertyNames(Set<LayerAttribute> attributes, PropertyAccessMode mode) { // handle simple case if (attributes == null || attributes.isEmpty()) { return null; } // filter and translate List<PropertyName> result = new ArrayList<PropertyName>(); for (LayerAttribute attribute : attributes) { if ((attribute.getAccess() == AccessType.READWRITE) || ((mode == PropertyAccessMode.READ) && (attribute.getAccess() == AccessType.READONLY))) { PropertyName property = FF.property(attribute.getName()); result.add(property); } } return result; } @Override public void finished(Request request) { // nothing to do } @Override public Request init(Request request) { return request; } @Override public Operation operationDispatched(Request gsRequest, Operation operation) { // service and request String service = gsRequest.getService(); String request = gsRequest.getRequest(); // get the user Authentication user = SecurityContextHolder.getContext().getAuthentication(); String username = null; if ((user != null) && !(user instanceof AnonymousAuthenticationToken)) { // shortcut, if the user is the admin, he can do everything if (isAdmin(user)) { LOGGER.log(Level.FINE, "Admin level access, not applying default style for this request"); return operation; } else { username = user.getName(); } } if ((request != null) && "WMS".equalsIgnoreCase(service) && ("GetMap".equalsIgnoreCase(request) || "GetFeatureInfo".equalsIgnoreCase(request))) { // extract the getmap part Object ro = operation.getParameters()[0]; GetMapRequest getMap; if (ro instanceof GetMapRequest) { getMap = (GetMapRequest) ro; } else if (ro instanceof GetFeatureInfoRequest) { getMap = ((GetFeatureInfoRequest) ro).getGetMapRequest(); } else { throw new ServiceException("Unrecognized request object: " + ro); } overrideGetMapRequest(gsRequest, service, request, user, getMap); } else if ((request != null) && "WMS".equalsIgnoreCase(service) && "GetLegendGraphic".equalsIgnoreCase(request)) { overrideGetLegendGraphicRequest(gsRequest, operation, service, request, user); } return operation; } void overrideGetLegendGraphicRequest(Request gsRequest, Operation operation, String service, String request, Authentication user) { // get the layer String layerName = (String) gsRequest.getKvp().get("LAYER"); List<LayerInfo> layers = new ArrayList<LayerInfo>(); LayerInfo candidateLayer = catalog.getLayerByName(layerName); if(candidateLayer == null) { if(layerName.indexOf(":") == -1) { // add namespace info to candidate layer group name if(LocalWorkspace.get() != null) { layerName = LocalWorkspace.get().getName() + ":" + layerName; } else if(catalog.getDefaultWorkspace() != null) { layerName = catalog.getDefaultWorkspace().getName() + ":" + layerName; } } LayerGroupInfo layerGroup = catalog.getLayerGroupByName(layerName); if(layerGroup != null) { for (PublishedInfo publishedInfo : layerGroup.getLayers()) { if(publishedInfo instanceof LayerInfo) { layers.add((LayerInfo)publishedInfo); } else { if(LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Skipping publishable " + publishedInfo); } } } } } else { layers.add(candidateLayer); } // get the request object GetLegendGraphicRequest getLegend = (GetLegendGraphicRequest) operation.getParameters()[0]; for(LayerInfo layer : layers) { ResourceInfo resource = layer.getResource(); // get the rule, it contains default and allowed styles RuleFilter ruleFilter = new RuleFilter(RuleFilter.SpecialFilterType.ANY); setRuleFilterUserOrRole(user, ruleFilter); ruleFilter.setInstance(configurationManager.getConfiguration().getInstanceName()); ruleFilter.setService(service); ruleFilter.setRequest(request); ruleFilter.setWorkspace(resource.getStore().getWorkspace().getName()); ruleFilter.setLayer(resource.getName()); LOGGER.log(Level.FINE, "Getting access limits for getLegendGraphic", ruleFilter); AccessInfo rule = rules.getAccessInfo(ruleFilter); // get the requested style String styleName = (String) gsRequest.getKvp().get("STYLE"); if (styleName == null) { if (rule.getDefaultStyle() != null) { try { StyleInfo si = catalog.getStyleByName(rule.getDefaultStyle()); if (si == null) { throw new ServiceException("Could not find default style suggested " + "by GeoRepository: " + rule.getDefaultStyle()); } getLegend.setStyle(si.getStyle()); } catch (IOException e) { throw new ServiceException("Unable to load the style suggested by GeoRepository: " + rule.getDefaultStyle(), e); } } } else { checkStyleAllowed(rule, styleName); } } } void overrideGetMapRequest(Request gsRequest, String service, String request, Authentication user, GetMapRequest getMap) { if (gsRequest.getKvp().get("layers") == null && gsRequest.getKvp().get("sld") == null && gsRequest.getKvp().get("sld_body") == null) { throw new ServiceException("GetMap POST requests are forbidden"); } // parse the styles param like the kvp parser would (since we have no way, // to know if a certain style was requested explicitly or defaulted, and // we need to tell apart the default case from the explicit request case List<String> styleNameList = getRequestedStyles(gsRequest, getMap); // apply the override/security check for each layer in the request List<MapLayerInfo> layers = getMap.getLayers(); for (int i = 0; i < layers.size(); i++) { MapLayerInfo layer = layers.get(i); ResourceInfo info = null; if(layer.getType() == MapLayerInfo.TYPE_VECTOR || layer.getType() == MapLayerInfo.TYPE_RASTER) { info = layer.getResource(); } else if(!configurationManager.getConfiguration().isAllowRemoteAndInlineLayers()) { throw new ServiceException("Remote layers are not allowed"); } // get the rule, it contains default and allowed styles RuleFilter ruleFilter = new RuleFilter(RuleFilter.SpecialFilterType.ANY); setRuleFilterUserOrRole(user, ruleFilter); ruleFilter.setInstance(configurationManager.getConfiguration().getInstanceName()); ruleFilter.setService(service); ruleFilter.setRequest(request); if(info != null) { ruleFilter.setWorkspace(info.getStore().getWorkspace().getName()); ruleFilter.setLayer(info.getName()); } else { ruleFilter.setWorkspace(RuleFilter.SpecialFilterType.ANY); ruleFilter.setLayer(RuleFilter.SpecialFilterType.ANY); } LOGGER.log(Level.FINE, "Getting access limits for getMap", ruleFilter); AccessInfo rule = rules.getAccessInfo(ruleFilter); // get the requested style name String styleName = styleNameList.get(i); // if default use geofence default if (styleName != null) { checkStyleAllowed(rule, styleName); } else if((rule.getDefaultStyle() != null)) { try { StyleInfo si = catalog.getStyleByName(rule.getDefaultStyle()); if (si == null) { throw new ServiceException("Could not find default style suggested " + "by Geofence: " + rule.getDefaultStyle()); } Style style = si.getStyle(); getMap.getStyles().set(i, style); } catch (IOException e) { throw new ServiceException("Unable to load the style suggested by Geofence: " + rule.getDefaultStyle(), e); } } } } private void checkStyleAllowed(AccessInfo rule, String styleName) { // otherwise check if the requested style is allowed Set<String> allowedStyles = new HashSet<String>(); if (rule.getDefaultStyle() != null) { allowedStyles.add(rule.getDefaultStyle()); } if (rule.getAllowedStyles() != null) { allowedStyles.addAll(rule.getAllowedStyles()); } if ((allowedStyles.size() > 0) && !allowedStyles.contains(styleName)) { throw new ServiceException("The '" + styleName + "' style is not available on this layer"); } } @Override public Filter getSecurityFilter(Authentication user, Class<? extends CatalogInfo> clazz) { return Predicates.acceptAll(); } @Override public Object operationExecuted(Request request, Operation operation, Object result) { return result; } @Override public Response responseDispatched(Request request, Operation operation, Object result, Response response) { return response; } @Override public Service serviceDispatched(Request request, Service service) throws ServiceException { return service; } /** * Returns a list that contains the request styles that will correspond to the GetMap.getLayers(). * Layer groups are expanded in layers and the associated styles are set to null (layers * groups can't use dynamic styles). */ private List<String> getRequestedStyles(Request gsRequest, GetMapRequest getMap) { List<String> requestedStyles = new ArrayList<>(); int styleIndex = 0; List<String> parsedStyles = parseStylesParameter(gsRequest); for(Object layer : parseLayersParameter(gsRequest, getMap)) { if (layer instanceof LayerGroupInfo) { // a LayerGroup don't have styles so we just add null for (int i = 0; i < ((LayerGroupInfo) layer).getLayers().size(); i++) { requestedStyles.add(null); } } else { // the layer is a LayerInfo or MapLayerInfo (if it is a remote layer) if(styleIndex >= parsedStyles.size()) { requestedStyles.add(null); } else { requestedStyles.add(parsedStyles.get(styleIndex)); } } styleIndex++; } return requestedStyles; } private List<Object> parseLayersParameter(Request gsRequest, GetMapRequest getMap) { String rawLayersParameter = (String) gsRequest.getRawKvp().get("LAYERS"); if (rawLayersParameter != null) { List<String> layersNames = KvpUtils.readFlat(rawLayersParameter); return new LayersParser().parseLayers(layersNames, getMap.getRemoteOwsURL(), getMap.getRemoteOwsType()); } return new ArrayList<>(); } private List<String> parseStylesParameter(Request gsRequest) { String rawStylesParameter = (String) gsRequest.getRawKvp().get("STYLES"); if (rawStylesParameter != null) { return KvpUtils.readFlat(rawStylesParameter); } return new ArrayList<>(); } /** * An helper that avoids duplicating the code to parse the layers parameter */ static final class LayersParser extends GetMapKvpRequestReader { public LayersParser() { super(WMS.get()); } public List parseLayers(List<String> requestedLayerNames, URL remoteOwsUrl, String remoteOwsType) { try { return super.parseLayers(requestedLayerNames, remoteOwsUrl, remoteOwsType); } catch (Exception exception) { throw new ServiceException("Error parsing requested layers.", exception); } } } }