def check_geometry(_: Any, feature: Feature, obj: Any) -> None: # we need both the "original" and "new" geometry to be # within the restriction area geom_attr, srid = self._get_geom_col_info(layer) geom_attr = getattr(obj, geom_attr) geom = feature.geometry allowed = models.DBSession.query(func.count(RestrictionArea.id)) allowed = allowed.join(RestrictionArea.roles) allowed = allowed.join(RestrictionArea.layers) allowed = allowed.filter(RestrictionArea.readwrite.is_(True)) allowed = allowed.filter(Role.id.in_(get_roles_id(self.request))) allowed = allowed.filter(Layer.id == layer.id) allowed = allowed.filter( or_(RestrictionArea.area.is_(None), RestrictionArea.area.ST_Contains(geom_attr))) spatial_elt = None if geom and not isinstance(geom, geojson.geometry.Default): shape = asShape(geom) spatial_elt = from_shape(shape, srid=srid) allowed = allowed.filter( or_(RestrictionArea.area.is_(None), RestrictionArea.area.ST_Contains(spatial_elt))) if allowed.scalar() == 0: raise HTTPForbidden() # Check is geometry is valid if self._get_validation_setting(layer): self._validate_geometry(spatial_elt)
def read_one(self) -> Feature: from c2cgeoportal_commons.models.main import ( # pylint: disable=import-outside-toplevel Layer, RestrictionArea, Role, ) set_common_headers(self.request, "layers", Cache.NO) layer = self._get_layer_for_request() protocol = self._get_protocol_for_layer(layer) feature_id = self.request.matchdict.get("feature_id") feature = protocol.read(self.request, id=feature_id) if not isinstance(feature, Feature): return feature if layer.public: return feature if self.request.user is None: raise HTTPForbidden() geom = feature.geometry if not geom or isinstance(geom, geojson.geometry.Default): return feature shape = asShape(geom) srid = self._get_geom_col_info(layer)[1] spatial_elt = from_shape(shape, srid=srid) allowed = models.DBSession.query(func.count(RestrictionArea.id)) allowed = allowed.join(RestrictionArea.roles) allowed = allowed.join(RestrictionArea.layers) allowed = allowed.filter(Role.id.in_(get_roles_id(self.request))) allowed = allowed.filter(Layer.id == layer.id) allowed = allowed.filter( or_(RestrictionArea.area.is_(None), RestrictionArea.area.ST_Contains(spatial_elt))) if allowed.scalar() == 0: raise HTTPForbidden() return feature
def _themes(self, interface: str = "desktop", filter_themes: bool = True, min_levels: int = 1) -> Tuple[List[Dict[str, Any]], Set[str]]: """ This function returns theme information for the role identified by ``role_id``. """ self._load_tree_items() errors = set() layers = self._layers(interface) themes = models.DBSession.query(main.Theme) themes = themes.filter(main.Theme.public.is_(True)) auth_themes = models.DBSession.query(main.Theme) auth_themes = auth_themes.filter(main.Theme.public.is_(False)) auth_themes = auth_themes.join(main.Theme.restricted_roles) auth_themes = auth_themes.filter( main.Role.id.in_(get_roles_id(self.request))) themes = themes.union(auth_themes) themes = themes.order_by(main.Theme.ordering.asc()) if filter_themes and interface is not None: themes = themes.join(main.Theme.interfaces) themes = themes.filter(main.Interface.name == interface) export_themes = [] for theme in themes.all(): if re.search("[/?#]", theme.name): errors.add("The theme has an unsupported name '{}'.".format( theme.name)) continue children, children_errors = self._get_children( theme, layers, min_levels) errors |= children_errors # Test if the theme is visible for the current user if children: icon = (get_url2("The Theme '{}'".format(theme.name), theme.icon, self.request, errors) if theme.icon is not None and theme.icon else self.request.static_url( "/etc/geomapfish/static/images/blank.png")) theme_theme = { "id": theme.id, "name": theme.name, "icon": icon, "children": children, "functionalities": self._get_functionalities(theme), "metadata": self._get_metadatas(theme, errors), } export_themes.append(theme_theme) return export_themes, errors
def _get_layers_query(request: Request, what: DeclarativeMeta) -> Query: from c2cgeoportal_commons.models import DBSession, main # pylint: disable=import-outside-toplevel q = DBSession.query(what) q = q.join(main.Layer.restrictionareas) # pylint: disable=no-member q = q.join(main.RestrictionArea.roles) q = q.filter(main.Role.id.in_(get_roles_id(request))) return q
def security_cb(_: Any, obj: Any) -> None: geom_attr = getattr(obj, self._get_geom_col_info(layer)[0]) allowed = models.DBSession.query(func.count(RestrictionArea.id)) allowed = allowed.join(RestrictionArea.roles) allowed = allowed.join(RestrictionArea.layers) allowed = allowed.filter(RestrictionArea.readwrite.is_(True)) allowed = allowed.filter(Role.id.in_(get_roles_id(self.request))) allowed = allowed.filter(Layer.id == layer.id) allowed = allowed.filter( or_(RestrictionArea.area.is_(None), RestrictionArea.area.ST_Contains(geom_attr))) if allowed.scalar() == 0: raise HTTPForbidden()
def _fill_editable(self, layer_theme, layer): errors = set() try: if self.request.user: count = (models.DBSession.query(main.RestrictionArea).join( main.RestrictionArea.roles).filter( main.Role.id.in_(get_roles_id(self.request))).filter( main.RestrictionArea.layers.any( main.Layer.id == layer.id)).filter( main.RestrictionArea.readwrite.is_( True)).count()) if count > 0: layer_theme["edit_columns"] = get_layer_metadatas(layer) layer_theme["editable"] = True except Exception as exception: LOG.exception(str(exception)) errors.add(str(exception)) return errors
def _proto_read(self, layer: "main.Layer") -> FeatureCollection: """ Read features for the layer based on the self.request. """ from c2cgeoportal_commons.models.main import ( # pylint: disable=import-outside-toplevel Layer, RestrictionArea, Role, ) proto = self._get_protocol_for_layer(layer) if layer.public: return proto.read(self.request) user = self.request.user if user is None: raise HTTPForbidden() cls = proto.mapped_class geom_attr = proto.geom_attr ras = models.DBSession.query(RestrictionArea.area, RestrictionArea.area.ST_SRID()) ras = ras.join(RestrictionArea.roles) ras = ras.join(RestrictionArea.layers) ras = ras.filter(Role.id.in_(get_roles_id(self.request))) ras = ras.filter(Layer.id == layer.id) collect_ra = [] use_srid = -1 for ra, srid in ras.all(): if ra is None: return proto.read(self.request) use_srid = srid collect_ra.append(to_shape(ra)) if not collect_ra: raise HTTPForbidden() filter1_ = create_filter(self.request, cls, geom_attr) ra = cascaded_union(collect_ra) filter2_ = ga_func.ST_Contains(from_shape(ra, use_srid), getattr(cls, geom_attr)) filter_ = filter2_ if filter1_ is None else and_(filter1_, filter2_) feature = proto.read(self.request, filter=filter_) if isinstance(feature, HTTPException): raise feature # pylint: disable=raising-non-exception return feature
def check_geometry(_: Any, feature: Feature, obj: Any) -> None: del obj # unused geom = feature.geometry if geom and not isinstance(geom, geojson.geometry.Default): shape = asShape(geom) srid = self._get_geom_col_info(layer)[1] spatial_elt = from_shape(shape, srid=srid) allowed = models.DBSession.query(func.count( RestrictionArea.id)) allowed = allowed.join(RestrictionArea.roles) allowed = allowed.join(RestrictionArea.layers) allowed = allowed.filter(RestrictionArea.readwrite.is_(True)) allowed = allowed.filter( Role.id.in_(get_roles_id(self.request))) allowed = allowed.filter(Layer.id == layer.id) allowed = allowed.filter( or_(RestrictionArea.area.is_(None), RestrictionArea.area.ST_Contains(spatial_elt))) if allowed.scalar() == 0: raise HTTPForbidden() # Check if geometry is valid if self._get_validation_setting(layer): self._validate_geometry(spatial_elt)
def proxy(self) -> Response: if self.user is None and "authentication_required" in self.request.params: LOG.debug("proxy() detected authentication_required") raise HTTPUnauthorized(headers={"WWW-Authenticate": 'Basic realm="Access to restricted layers"'}) # We have a user logged in. We need to set group_id and possible layer_name in the params. We set # layer_name when either QUERY_PARAMS or LAYERS is set in the WMS params, i.e. for GetMap and # GetFeatureInfo requests. For GetLegendGraphic requests we do not send layer_name, but MapServer # should not use the DATA string for GetLegendGraphic. if self.ogc_server.auth == main.OGCSERVER_AUTH_STANDARD: self.params["role_ids"] = ",".join([str(e) for e in get_roles_id(self.request)]) # In some application we want to display the features owned by a user than we need his id. self.params["user_id"] = self.user.id if self.user is not None else "-1" # pragma: no cover # Do not allows direct variable substitution for k in list(self.params.keys()): if k[:2].capitalize() == "S_": LOG.warning("Direct substitution not allowed (%s=%s).", k, self.params[k]) del self.params[k] # add functionalities params self.params.update(get_mapserver_substitution_params(self.request)) # get method method = self.request.method # we want the browser to cache GetLegendGraphic and # DescribeFeatureType requests use_cache = False if method == "GET": # For GET requests, params are added only if the self.request # parameter is actually provided. if "request" not in self.lower_params: self.params = {} # pragma: no cover else: if self.ogc_server.type != main.OGCSERVER_TYPE_QGISSERVER or "user_id" not in self.params: use_cache = self.lower_params["request"] in ("getlegendgraphic",) # no user_id and role_id or cached queries if use_cache and "user_id" in self.params: del self.params["user_id"] if use_cache and "role_ids" in self.params: del self.params["role_ids"] if "service" in self.lower_params and self.lower_params["service"] == "wfs": _url = self._get_wfs_url() else: _url = self._get_wms_url() else: # POST means WFS _url = self._get_wfs_url() cache_control = PRIVATE_CACHE if method == "GET" and "service" in self.lower_params and self.lower_params["service"] == "wms": if self.lower_params.get("request") in ("getmap", "getfeatureinfo"): cache_control = NO_CACHE elif self.lower_params.get("request") == "getlegendgraphic": cache_control = PUBLIC_CACHE elif method == "GET" and "service" in self.lower_params and self.lower_params["service"] == "wfs": if self.lower_params.get("request") == "getfeature": cache_control = NO_CACHE elif method != "GET": cache_control = NO_CACHE headers = self._get_headers() # Add headers for Geoserver if self.ogc_server.auth == main.OGCSERVER_AUTH_GEOSERVER: headers["sec-username"] = self.user.username headers["sec-roles"] = ";".join(get_roles_name(self.request)) response = self._proxy_callback( cache_control, url=_url, params=self.params, cache=use_cache, headers=headers, body=self.request.body, ) if ( self.lower_params.get("request") == "getmap" and not response.content_type.startswith("image/") and response.status_code < 400 ): response.status_code = 400 return response