Example #1
0
        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)
Example #2
0
    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
Example #3
0
    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
Example #4
0
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
Example #5
0
 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()
Example #6
0
 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
Example #7
0
    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
Example #8
0
        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)
Example #9
0
    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