Beispiel #1
0
def set_geofence_all(instance):
    """assign access permissions to all users

    This method is only relevant to Layer instances that have their
    underlying data managed by geoserver, meaning:

    * layers that are not associated with a Service
    * layers that are associated with a Service that is being CASCADED through
      geoserver

    """

    resource = instance.get_self_resource()
    logger.debug(f"Inside set_geofence_all for instance {instance}")
    workspace = get_layer_workspace(resource.layer)
    layer_name = resource.layer.name if resource.layer and hasattr(resource.layer, 'name') \
        else resource.layer.alternate.split(":")[0]
    logger.debug(f"going to work in workspace {workspace}")
    try:
        url = settings.OGC_SERVER['default']['LOCATION']
        user = settings.OGC_SERVER['default']['USER']
        passwd = settings.OGC_SERVER['default']['PASSWORD']

        # Create GeoFence Rules for ANONYMOUS to the Layer
        """
        curl -X POST -u admin:geoserver -H "Content-Type: text/xml" -d \
        "<Rule><workspace>geonode</workspace><layer>{layer}</layer><access>ALLOW</access></Rule>" \
        http://<host>:<port>/geoserver/rest/geofence/rules
        """
        headers = {'Content-type': 'application/xml'}
        payload = _get_geofence_payload(
            layer=resource.layer,
            layer_name=layer_name,
            workspace=workspace,
            access="ALLOW"
        )
        response = requests.post(
            f"{url}rest/geofence/rules",
            headers=headers,
            data=payload,
            auth=HTTPBasicAuth(user, passwd)
        )
        if response.status_code not in (200, 201):
            logger.debug(
                f"Response {response.status_code} : {response.text}")
            raise RuntimeError("Could not ADD GeoServer ANONYMOUS Rule "
                               f"for Layer {layer_name}")
    except Exception:
        tb = traceback.format_exc()
        logger.debug(tb)
    finally:
        if not getattr(settings, 'DELAYED_SECURITY_SIGNALS', False):
            set_geofence_invalidate_cache()
        else:
            resource.set_dirty_state()
Beispiel #2
0
def sync_geofence_with_guardian(layer, perms, user=None, group=None):
    """
    Sync Guardian permissions to GeoFence.
    """
    _layer_name = layer.name if layer and hasattr(
        layer, 'name') else layer.alternate.split(":")[0]
    _layer_workspace = get_layer_workspace(layer)
    # Create new rule-set
    gf_services = {}
    gf_services["*"] = 'download_resourcebase' in perms and \
        ('view_resourcebase' in perms or 'change_layer_style' in perms)
    gf_services[
        "WMS"] = 'view_resourcebase' in perms or 'change_layer_style' in perms
    gf_services[
        "GWC"] = 'view_resourcebase' in perms or 'change_layer_style' in perms
    gf_services["WFS"] = ('download_resourcebase' in perms or 'change_layer_data' in perms) \
        and layer.is_vector()
    gf_services["WCS"] = ('download_resourcebase' in perms or 'change_layer_data' in perms) \
        and not layer.is_vector()
    gf_services[
        "WPS"] = 'download_resourcebase' in perms or 'change_layer_data' in perms
    _user = None
    if user:
        _user = user if isinstance(user, string_types) else user.username
    _group = None
    if group:
        _group = group if isinstance(group, string_types) else group.name
    for service, allowed in gf_services.items():
        if allowed:
            if _user:
                logger.debug("Adding 'user' to geofence the rule: %s %s %s" %
                             (layer, service, _user))
                _update_geofence_rule(_layer_name,
                                      _layer_workspace,
                                      service,
                                      user=_user)
            elif not _group:
                logger.debug("Adding to geofence the rule: %s %s *" %
                             (layer, service))
                _update_geofence_rule(_layer_name, _layer_workspace, service)
            if _group:
                logger.debug("Adding 'group' to geofence the rule: %s %s %s" %
                             (layer, service, _group))
                _update_geofence_rule(_layer_name,
                                      _layer_workspace,
                                      service,
                                      group=_group)
    if not getattr(settings, 'DELAYED_SECURITY_SIGNALS', False):
        set_geofence_invalidate_cache()
    else:
        layer.set_dirty_state()
Beispiel #3
0
def purge_geofence_layer_rules(resource):
    """purge layer existing GeoFence Cache Rules"""
    # Scan GeoFence Rules associated to the Layer
    """
    curl -u admin:geoserver
    http://<host>:<port>/geoserver/rest/geofence/rules.json?workspace=geonode&layer={layer}
    """
    url = settings.OGC_SERVER['default']['LOCATION']
    user = settings.OGC_SERVER['default']['USER']
    passwd = settings.OGC_SERVER['default']['PASSWORD']
    headers = {'Content-type': 'application/json'}
    workspace = get_layer_workspace(resource.layer)
    layer_name = resource.layer.name if resource.layer and hasattr(resource.layer, 'name') \
        else resource.layer.alternate.split(":")[0]
    try:
        r = requests.get(
            f"{url}rest/geofence/rules.json?workspace={workspace}&layer={layer_name}",
            headers=headers,
            auth=HTTPBasicAuth(user, passwd),
            timeout=10,
            verify=False
        )
        if (r.status_code >= 200 and r.status_code < 300):
            gs_rules = r.json()
            r_ids = []
            if gs_rules and gs_rules['rules']:
                for r in gs_rules['rules']:
                    if r['layer'] and r['layer'] == layer_name:
                        r_ids.append(r['id'])

            # Delete GeoFence Rules associated to the Layer
            # curl -X DELETE -u admin:geoserver http://<host>:<port>/geoserver/rest/geofence/rules/id/{r_id}
            for r_id in r_ids:
                r = requests.delete(
                    f"{url}rest/geofence/rules/id/{str(r_id)}",
                    headers=headers,
                    auth=HTTPBasicAuth(user, passwd))
                if (r.status_code < 200 or r.status_code > 201):
                    msg = "Could not DELETE GeoServer Rule for Layer "
                    msg = msg + str(layer_name)
                    e = Exception(msg)
                    logger.debug(f"Response [{r.status_code}] : {r.text}")
                    raise e
    except Exception as e:
        logger.exception(e)
Beispiel #4
0
def purge_geofence_layer_rules(resource):
    """purge layer existing GeoFence Cache Rules"""
    # Scan GeoFence Rules associated to the Layer
    """
    curl -u admin:geoserver
    http://<host>:<port>/geoserver/rest/geofence/rules.json?workspace=geonode&layer={layer}
    """
    url = settings.OGC_SERVER['default']['LOCATION']
    user = settings.OGC_SERVER['default']['USER']
    passwd = settings.OGC_SERVER['default']['PASSWORD']
    headers = {'Content-type': 'application/json'}
    workspace = get_layer_workspace(resource.layer)
    r = requests.get("{}rest/geofence/rules.json?workspace={}&layer={}".format(
        url, workspace, resource.layer.name),
                     headers=headers,
                     auth=HTTPBasicAuth(user, passwd),
                     timeout=10,
                     verify=False)
    if (r.status_code >= 200 and r.status_code < 300):
        gs_rules = r.json()
        r_ids = []
        if gs_rules and gs_rules['rules']:
            for r in gs_rules['rules']:
                if r['layer'] and r['layer'] == resource.layer.name:
                    r_ids.append(r['id'])

        # Delete GeoFence Rules associated to the Layer
        # curl -X DELETE -u admin:geoserver http://<host>:<port>/geoserver/rest/geofence/rules/id/{r_id}
        for i, r_id in enumerate(r_ids):
            r = requests.delete(url + 'rest/geofence/rules/id/' + str(r_id),
                                headers=headers,
                                auth=HTTPBasicAuth(user, passwd))
            if (r.status_code < 200 or r.status_code > 201):
                msg = "Could not DELETE GeoServer Rule for Layer "
                msg = msg + str(resource.layer.name)
                e = Exception(msg)
                logger.debug("Response [{}] : {}".format(
                    r.status_code, r.text))
                raise e
Beispiel #5
0
def sync_geofence_with_guardian(layer,
                                perms,
                                user=None,
                                group=None,
                                group_perms=None):
    """
    Sync Guardian permissions to GeoFence.
    """
    _layer_name = layer.name if layer and hasattr(
        layer, 'name') else layer.alternate.split(":")[0]
    _layer_workspace = get_layer_workspace(layer)
    # Create new rule-set
    gf_services = {}
    gf_services[
        "WMS"] = 'view_resourcebase' in perms or 'change_layer_style' in perms
    gf_services[
        "GWC"] = 'view_resourcebase' in perms or 'change_layer_style' in perms
    gf_services["WFS"] = ('download_resourcebase' in perms or 'change_layer_data' in perms) \
        and layer.is_vector()
    gf_services["WCS"] = ('download_resourcebase' in perms or 'change_layer_data' in perms) \
        and not layer.is_vector()
    gf_services[
        "WPS"] = 'download_resourcebase' in perms or 'change_layer_data' in perms
    gf_services["*"] = 'download_resourcebase' in perms and \
        ('view_resourcebase' in perms or 'change_layer_style' in perms)

    gf_requests = {}
    if 'change_layer_data' not in perms:
        _skip_perm = False
        if user and group_perms:
            if isinstance(user, string_types):
                user = get_user_model().objects.get(username=user)
            user_groups = list(user.groups.all().values_list('name',
                                                             flat=True))
            for _group, _perm in group_perms.items():
                if 'change_layer_data' in _perm and _group in user_groups:
                    _skip_perm = True
                    break
        if not _skip_perm:
            gf_requests["WFS"] = {
                "TRANSACTION": False,
                "LOCKFEATURE": False,
                "GETFEATUREWITHLOCK": False
            }
    _user = None
    _group = None
    _disable_layer_cache = False
    users_geolimits = None
    groups_geolimits = None
    anonymous_geolimits = None

    if user:
        _user = user if isinstance(user, string_types) else user.username
        users_geolimits = layer.users_geolimits.filter(
            user=get_user_model().objects.get(username=_user))
        gf_services["*"] = users_geolimits.count(
        ) > 0 if not gf_services["*"] else gf_services["*"]
        _disable_layer_cache = users_geolimits.count() > 0

    if group:
        _group = group if isinstance(group, string_types) else group.name
        if GroupProfile.objects.filter(group__name=_group).count() == 1:
            groups_geolimits = layer.groups_geolimits.filter(
                group=GroupProfile.objects.get(group__name=_group))
            gf_services["*"] = groups_geolimits.count(
            ) > 0 if not gf_services["*"] else gf_services["*"]
            _disable_layer_cache = groups_geolimits.count() > 0

    if not user and not group:
        anonymous_geolimits = layer.users_geolimits.filter(
            user=get_anonymous_user())
        gf_services["*"] = anonymous_geolimits.count(
        ) > 0 if not gf_services["*"] else gf_services["*"]
        _disable_layer_cache = anonymous_geolimits.count() > 0

    if _disable_layer_cache:
        # delete_layer_cache('{}:{}'.format(_layer_workspace, _layer_name))
        filters = None
        formats = None
        # Re-order dictionary
        # - if geo-limits have been defined for this user/group, the "*" rule must be the first one
        gf_services_limits_first = {"*": gf_services.pop('*')}
        gf_services_limits_first.update(gf_services)
        gf_services = gf_services_limits_first
    else:
        filters = [{"styleParameterFilter": {"STYLES": ""}}]
        formats = [
            'application/json;type=utfgrid', 'image/png', 'image/vnd.jpeg-png',
            'image/jpeg', 'image/gif', 'image/png8'
        ]
    toggle_layer_cache('{}:{}'.format(_layer_workspace, _layer_name),
                       enable=True,
                       filters=filters,
                       formats=formats)

    for service, allowed in gf_services.items():
        if allowed:
            if _user:
                logger.debug("Adding 'user' to geofence the rule: %s %s %s" %
                             (layer, service, _user))
                _wkt = None
                if users_geolimits and users_geolimits.count():
                    _wkt = users_geolimits.last().wkt
                if service in gf_requests:
                    for request, enabled in gf_requests[service].items():
                        _update_geofence_rule(layer,
                                              _layer_name,
                                              _layer_workspace,
                                              service,
                                              request=request,
                                              user=_user,
                                              allow=enabled)
                _update_geofence_rule(layer,
                                      _layer_name,
                                      _layer_workspace,
                                      service,
                                      user=_user,
                                      geo_limit=_wkt)
            elif not _group:
                logger.debug("Adding to geofence the rule: %s %s *" %
                             (layer, service))
                _wkt = None
                if anonymous_geolimits and anonymous_geolimits.count():
                    _wkt = anonymous_geolimits.last().wkt
                if service in gf_requests:
                    for request, enabled in gf_requests[service].items():
                        _update_geofence_rule(layer,
                                              _layer_name,
                                              _layer_workspace,
                                              service,
                                              request=request,
                                              user=_user,
                                              allow=enabled)
                _update_geofence_rule(layer,
                                      _layer_name,
                                      _layer_workspace,
                                      service,
                                      geo_limit=_wkt)
                if service in gf_requests:
                    for request, enabled in gf_requests[service].items():
                        _update_geofence_rule(layer,
                                              _layer_name,
                                              _layer_workspace,
                                              service,
                                              request=request,
                                              user=_user,
                                              allow=enabled)
            if _group:
                logger.debug("Adding 'group' to geofence the rule: %s %s %s" %
                             (layer, service, _group))
                _wkt = None
                if groups_geolimits and groups_geolimits.count():
                    _wkt = groups_geolimits.last().wkt
                if service in gf_requests:
                    for request, enabled in gf_requests[service].items():
                        _update_geofence_rule(layer,
                                              _layer_name,
                                              _layer_workspace,
                                              service,
                                              request=request,
                                              group=_group,
                                              allow=enabled)
                _update_geofence_rule(layer,
                                      _layer_name,
                                      _layer_workspace,
                                      service,
                                      group=_group,
                                      geo_limit=_wkt)
                if service in gf_requests:
                    for request, enabled in gf_requests[service].items():
                        _update_geofence_rule(layer,
                                              _layer_name,
                                              _layer_workspace,
                                              service,
                                              request=request,
                                              group=_group,
                                              allow=enabled)
    if not getattr(settings, 'DELAYED_SECURITY_SIGNALS', False):
        set_geofence_invalidate_cache()
    else:
        layer.set_dirty_state()
Beispiel #6
0
def _layers_locations(
    instance: Union[Layer, Map], compute_bbox: bool = False, target_crs: str = "EPSG:3857"
) -> Tuple[List[List], List]:
    """
    Function returning a list mapping instance's layers to their locations, enabling to construct a minimum
    number of  WMS request for multiple layers of the same OGC source (ensuring layers order for Maps)

    :param instance: instance of Layer or Map models
    :param compute_bbox: flag determining whether a BBOX containing the instance should be computed,
                         based on instance's layers
    :param target_crs: valid only when compute_bbox is True - CRS of the returned BBOX
    :return: a tuple with a list, which maps layers to their locations in a correct layers order
             e.g.
                [
                    ["http://localhost:8080/geoserver/": ["geonode:layer1", "geonode:layer2]]
                ]
             and a list optionally consisting of 5 elements containing west, east, south, north
             instance's boundaries and CRS
    """
    ogc_server_settings = OGC_Servers_Handler(settings.OGC_SERVER)["default"]

    locations = []
    bbox = []

    if isinstance(instance, Layer):

        # for local layers
        if instance.remote_service is None:
            locations.append([ogc_server_settings.LOCATION, [instance.alternate]])
        # for remote layers
        else:
            locations.append([instance.remote_service.service_url, [instance.alternate]])

        if compute_bbox:
            # handle exceeding the area of use of the default thumb's CRS
            if (
                    instance.bbox[-1].upper() != 'EPSG:3857'
                    and target_crs.upper() == 'EPSG:3857'
                    and utils.exceeds_epsg3857_area_of_use(instance.bbox)
            ):
                bbox = utils.transform_bbox(utils.crop_to_3857_area_of_use(instance.bbox), target_crs.lower())
            else:
                bbox = utils.transform_bbox(instance.bbox, target_crs.lower())

    elif isinstance(instance, Map):

        map_layers = instance.layers.copy()
        # ensure correct order of layers in the map (higher stack_order are printed on top of lower)
        map_layers.sort(key=lambda l: l.stack_order)

        for map_layer in map_layers:

            if not map_layer.visibility:
                logger.debug("Skipping not visible layer in the thumbnail generation.")
                continue

            if not map_layer.local and not map_layer.ows_url:
                logger.warning(
                    "Incorrectly defined remote layer encountered (no OWS URL defined)."
                    "Skipping it in the thumbnail generation."
                )
                continue

            name = get_layer_name(map_layer)
            store = map_layer.store
            workspace = get_layer_workspace(map_layer)

            if store and Layer.objects.filter(store=store, workspace=workspace, name=name).count() > 0:
                layer = Layer.objects.filter(store=store, workspace=workspace, name=name).first()

            elif workspace and Layer.objects.filter(workspace=workspace, name=name).count() > 0:
                layer = Layer.objects.filter(workspace=workspace, name=name).first()

            elif Layer.objects.filter(alternate=map_layer.name).count() > 0:
                layer = Layer.objects.filter(alternate=map_layer.name).first()

            else:
                logger.warning(f"Layer for MapLayer {name} was not found. Skipping it in the thumbnail.")
                continue

            if layer.storetype in ['tileStore', 'remote']:
                # limit number of locations, ensuring layer order
                if len(locations) and locations[-1][0] == layer.remote_service.service_url:
                    # if previous layer's location is the same as the current one - append current layer there
                    locations[-1][1].append(layer.alternate)
                else:
                    locations.append([layer.remote_service.service_url, [layer.alternate]])
            else:
                # limit number of locations, ensuring layer order
                if len(locations) and locations[-1][0] == settings.OGC_SERVER["default"]["LOCATION"]:
                    # if previous layer's location is the same as the current one - append current layer there
                    locations[-1][1].append(layer.alternate)
                else:
                    locations.append([settings.OGC_SERVER["default"]["LOCATION"], [layer.alternate]])

            if compute_bbox:
                # handle exceeding the area of use of the default thumb's CRS
                if (
                        layer.bbox[-1].upper() != 'EPSG:3857'
                        and target_crs.upper() == 'EPSG:3857'
                        and utils.exceeds_epsg3857_area_of_use(layer.bbox)
                ):
                    layer_bbox = utils.transform_bbox(utils.crop_to_3857_area_of_use(layer.bbox), target_crs.lower())
                else:
                    layer_bbox = utils.transform_bbox(layer.bbox, target_crs.lower())

                if not bbox:
                    bbox = layer_bbox
                else:
                    # layer's BBOX: (left, right, bottom, top)
                    bbox = [
                        min(bbox[0], layer_bbox[0]),
                        max(bbox[1], layer_bbox[1]),
                        min(bbox[2], layer_bbox[2]),
                        max(bbox[3], layer_bbox[3]),
                    ]

    if bbox and len(bbox) < 5:
        bbox = list(bbox) + [target_crs]  # convert bbox to list, if it's tuple

    return locations, bbox
Beispiel #7
0
def layer_style_manage(request, layername):
    layer = _resolve_layer(request, layername, 'layers.change_layer_style',
                           _PERMISSION_MSG_MODIFY)

    if request.method == 'GET':
        try:
            cat = gs_catalog

            # First update the layer style info from GS to GeoNode's DB
            try:
                set_styles(layer, cat)
            except AttributeError:
                logger.warn(
                    'Unable to set the default style.  Ensure Geoserver is running and that this layer exists.'
                )

            gs_styles = []
            # Temporary Hack to remove GeoServer temp styles from the list
            Style.objects.filter(
                name__iregex=r'\w{8}-\w{4}-\w{4}-\w{4}-\w{12}_(ms)_\d{13}'
            ).delete()
            for style in Style.objects.values('name', 'sld_title'):
                gs_styles.append((style['name'], style['sld_title']))
            current_layer_styles = layer.styles.all()
            layer_styles = []
            for style in current_layer_styles:
                sld_title = style.name
                try:
                    if style.sld_title:
                        sld_title = style.sld_title
                except Exception:
                    tb = traceback.format_exc()
                    logger.debug(tb)
                layer_styles.append((style.name, sld_title))

            # Render the form
            def_sld_name = None  # noqa
            def_sld_title = None  # noqa
            default_style = None
            if layer.default_style:
                def_sld_name = layer.default_style.name  # noqa
                def_sld_title = layer.default_style.name  # noqa
                try:
                    if layer.default_style.sld_title:
                        def_sld_title = layer.default_style.sld_title
                except Exception:
                    tb = traceback.format_exc()
                    logger.debug(tb)
                default_style = (def_sld_name, def_sld_title)

            return render(request,
                          'layers/layer_style_manage.html',
                          context={
                              "layer": layer,
                              "gs_styles": gs_styles,
                              "layer_styles": layer_styles,
                              "layer_style_names":
                              [s[0] for s in layer_styles],
                              "default_style": default_style
                          })
        except (FailedRequestError, EnvironmentError):
            tb = traceback.format_exc()
            logger.debug(tb)
            msg = (
                f'Could not connect to geoserver at "{ogc_server_settings.LOCATION}"'
                f'to manage style information for layer "{layer.name}"')
            logger.debug(msg)
            # If geoserver is not online, return an error
            return render(request,
                          'layers/layer_style_manage.html',
                          context={
                              "layer": layer,
                              "error": msg
                          })
    elif request.method in ('POST', 'PUT', 'DELETE'):
        try:
            workspace = get_layer_workspace(
                layer) or settings.DEFAULT_WORKSPACE
            selected_styles = request.POST.getlist('style-select')
            default_style = request.POST['default_style']

            # Save to GeoServer
            cat = gs_catalog
            try:
                gs_layer = cat.get_layer(layer.name)
            except Exception:
                gs_layer = None

            if not gs_layer:
                gs_layer = cat.get_layer(layer.alternate)

            if gs_layer:
                _default_style = cat.get_style(default_style) or \
                    cat.get_style(default_style, workspace=workspace)
                if _default_style:
                    gs_layer.default_style = _default_style
                elif cat.get_style(default_style,
                                   workspace=settings.DEFAULT_WORKSPACE):
                    gs_layer.default_style = cat.get_style(
                        default_style, workspace=settings.DEFAULT_WORKSPACE)
                styles = []
                for style in selected_styles:
                    _gs_sld = cat.get_style(style) or cat.get_style(
                        style, workspace=workspace)
                    if _gs_sld:
                        styles.append(_gs_sld)
                    elif cat.get_style(style,
                                       workspace=settings.DEFAULT_WORKSPACE):
                        styles.append(
                            cat.get_style(
                                style, workspace=settings.DEFAULT_WORKSPACE))
                    else:
                        Style.objects.filter(name=style).delete()
                gs_layer.styles = styles
                cat.save(gs_layer)

            # Save to Django
            set_styles(layer, cat)

            # Invalidate GeoWebCache for the updated resource
            try:
                _stylefilterparams_geowebcache_layer(layer.alternate)
                _invalidate_geowebcache_layer(layer.alternate)
            except Exception:
                pass

            return HttpResponseRedirect(
                reverse('layer_detail', args=(layer.service_typename, )))
        except (FailedRequestError, EnvironmentError, MultiValueDictKeyError):
            tb = traceback.format_exc()
            logger.debug(tb)
            msg = (f'Error Saving Styles for Layer "{layer.name}"')
            logger.warn(msg)
            return render(request,
                          'layers/layer_style_manage.html',
                          context={
                              "layer": layer,
                              "error": msg
                          })
Beispiel #8
0
def sync_geofence_with_guardian(layer, perms, user=None, group=None):
    """
    Sync Guardian permissions to GeoFence.
    """
    _layer_name = layer.name if layer and hasattr(layer, 'name') else layer.alternate.split(":")[0]
    _layer_workspace = get_layer_workspace(layer)
    # Create new rule-set
    gf_services = {}
    gf_services["*"] = 'download_resourcebase' in perms and \
        ('view_resourcebase' in perms or 'change_layer_style' in perms)
    gf_services["WMS"] = 'view_resourcebase' in perms or 'change_layer_style' in perms
    gf_services["GWC"] = 'view_resourcebase' in perms or 'change_layer_style' in perms
    gf_services["WFS"] = ('download_resourcebase' in perms or 'change_layer_data' in perms) \
        and layer.is_vector()
    gf_services["WCS"] = ('download_resourcebase' in perms or 'change_layer_data' in perms) \
        and not layer.is_vector()
    gf_services["WPS"] = 'download_resourcebase' in perms or 'change_layer_data' in perms

    _user = None
    _group = None
    _disable_layer_cache = False
    users_geolimits = None
    groups_geolimits = None
    anonymous_geolimits = None

    if user:
        _user = user if isinstance(user, string_types) else user.username
        users_geolimits = layer.users_geolimits.filter(user=get_user_model().objects.get(username=_user))
        gf_services["*"] = users_geolimits.count() > 0 if not gf_services["*"] else gf_services["*"]
        _disable_layer_cache = users_geolimits.count() > 0

    if group:
        _group = group if isinstance(group, string_types) else group.name
        if GroupProfile.objects.filter(group__name=_group).count() == 1:
            groups_geolimits = layer.groups_geolimits.filter(group=GroupProfile.objects.get(group__name=_group))
            gf_services["*"] = groups_geolimits.count() > 0 if not gf_services["*"] else gf_services["*"]
            _disable_layer_cache = groups_geolimits.count() > 0

    if not user and not group:
        anonymous_geolimits = layer.users_geolimits.filter(user=get_anonymous_user())
        gf_services["*"] = anonymous_geolimits.count() > 0 if not gf_services["*"] else gf_services["*"]
        _disable_layer_cache = anonymous_geolimits.count() > 0

    if _disable_layer_cache:
        # delete_layer_cache('{}:{}'.format(_layer_workspace, _layer_name))
        filters = None
        formats = None
    else:
        filters = [{
            "styleParameterFilter": {
                "STYLES": ""
            }
        }]
        formats = [
            'application/json;type=utfgrid',
            'image/png',
            'image/vnd.jpeg-png',
            'image/jpeg',
            'image/gif',
            'image/png8'
        ]
    toggle_layer_cache('{}:{}'.format(_layer_workspace, _layer_name), enable=True, filters=filters, formats=formats)

    for service, allowed in gf_services.items():
        if allowed:
            if _user:
                logger.debug("Adding 'user' to geofence the rule: %s %s %s" % (layer, service, _user))
                _wkt = None
                if users_geolimits and users_geolimits.count():
                    _wkt = users_geolimits.last().wkt
                _update_geofence_rule(layer, _layer_name, _layer_workspace, service, user=_user, geo_limit=_wkt)
            elif not _group:
                logger.debug("Adding to geofence the rule: %s %s *" % (layer, service))
                _wkt = None
                if anonymous_geolimits and anonymous_geolimits.count():
                    _wkt = anonymous_geolimits.last().wkt
                _update_geofence_rule(layer, _layer_name, _layer_workspace, service, geo_limit=_wkt)
            if _group:
                logger.debug("Adding 'group' to geofence the rule: %s %s %s" % (layer, service, _group))
                _wkt = None
                if groups_geolimits and groups_geolimits.count():
                    _wkt = groups_geolimits.last().wkt
                _update_geofence_rule(layer, _layer_name, _layer_workspace, service, group=_group, geo_limit=_wkt)
    if not getattr(settings, 'DELAYED_SECURITY_SIGNALS', False):
        set_geofence_invalidate_cache()
    else:
        layer.set_dirty_state()
Beispiel #9
0
def sync_geofence_with_guardian(layer,
                                perms,
                                user=None,
                                group=None,
                                group_perms=None):
    """
    Sync Guardian permissions to GeoFence.
    """
    _layer_name = layer.name if layer and hasattr(
        layer, 'name') else layer.alternate.split(":")[0]
    _layer_workspace = get_layer_workspace(layer)
    # Create new rule-set
    gf_services = _get_gf_services(layer, perms)

    gf_requests = {}
    if 'change_layer_data' not in perms:
        _skip_perm = False
        if user and group_perms:
            if isinstance(user, str):
                user = get_user_model().objects.get(username=user)
            user_groups = list(user.groups.all().values_list('name',
                                                             flat=True))
            for _group, _perm in group_perms.items():
                if 'change_layer_data' in _perm and _group in user_groups:
                    _skip_perm = True
                    break
        if not _skip_perm:
            gf_requests["WFS"] = {
                "TRANSACTION": False,
                "LOCKFEATURE": False,
                "GETFEATUREWITHLOCK": False
            }
    _user = None
    _group = None
    users_geolimits = None
    groups_geolimits = None
    anonymous_geolimits = None
    _group, _user, _disable_cache, users_geolimits, groups_geolimits, anonymous_geolimits = get_user_geolimits(
        layer, user, group, gf_services)

    if _disable_cache:
        gf_services_limits_first = {"*": gf_services.pop('*')}
        gf_services_limits_first.update(gf_services)
        gf_services = gf_services_limits_first

    for service, allowed in gf_services.items():
        if layer and _layer_name and allowed:
            if _user:
                logger.debug(
                    f"Adding 'user' to geofence the rule: {layer} {service} {_user}"
                )
                _wkt = None
                if users_geolimits and users_geolimits.count():
                    _wkt = users_geolimits.last().wkt
                if service in gf_requests:
                    for request, enabled in gf_requests[service].items():
                        _update_geofence_rule(layer,
                                              _layer_name,
                                              _layer_workspace,
                                              service,
                                              request=request,
                                              user=_user,
                                              allow=enabled)
                _update_geofence_rule(layer,
                                      _layer_name,
                                      _layer_workspace,
                                      service,
                                      user=_user,
                                      geo_limit=_wkt)
            elif not _group:
                logger.debug(
                    f"Adding to geofence the rule: {layer} {service} *")
                _wkt = None
                if anonymous_geolimits and anonymous_geolimits.count():
                    _wkt = anonymous_geolimits.last().wkt
                if service in gf_requests:
                    for request, enabled in gf_requests[service].items():
                        _update_geofence_rule(layer,
                                              _layer_name,
                                              _layer_workspace,
                                              service,
                                              request=request,
                                              user=_user,
                                              allow=enabled)
                _update_geofence_rule(layer,
                                      _layer_name,
                                      _layer_workspace,
                                      service,
                                      geo_limit=_wkt)
                if service in gf_requests:
                    for request, enabled in gf_requests[service].items():
                        _update_geofence_rule(layer,
                                              _layer_name,
                                              _layer_workspace,
                                              service,
                                              request=request,
                                              user=_user,
                                              allow=enabled)
            if _group:
                logger.debug(
                    f"Adding 'group' to geofence the rule: {layer} {service} {_group}"
                )
                _wkt = None
                if groups_geolimits and groups_geolimits.count():
                    _wkt = groups_geolimits.last().wkt
                if service in gf_requests:
                    for request, enabled in gf_requests[service].items():
                        _update_geofence_rule(layer,
                                              _layer_name,
                                              _layer_workspace,
                                              service,
                                              request=request,
                                              group=_group,
                                              allow=enabled)
                _update_geofence_rule(layer,
                                      _layer_name,
                                      _layer_workspace,
                                      service,
                                      group=_group,
                                      geo_limit=_wkt)
                if service in gf_requests:
                    for request, enabled in gf_requests[service].items():
                        _update_geofence_rule(layer,
                                              _layer_name,
                                              _layer_workspace,
                                              service,
                                              request=request,
                                              group=_group,
                                              allow=enabled)
    if not getattr(settings, 'DELAYED_SECURITY_SIGNALS', False):
        set_geofence_invalidate_cache()
    else:
        layer.set_dirty_state()
Beispiel #10
0
    def set_permissions(self, perm_spec, created=False):
        """
        Sets an object's the permission levels based on the perm_spec JSON.

        the mapping looks like:
        {
            'users': {
                'AnonymousUser': ['view'],
                <username>: ['perm1','perm2','perm3'],
                <username2>: ['perm1','perm2','perm3']
                ...
            }
            'groups': [
                <groupname>: ['perm1','perm2','perm3'],
                <groupname2>: ['perm1','perm2','perm3'],
                ...
                ]
        }
        """
        geofence_uow = GeofenceLayerRulesUnitOfWork(
            GeofenceLayerAdapter(self.get_self_resource()))
        try:
            with geofence_uow:
                with transaction.atomic():
                    remove_object_permissions(self,
                                              purge=False,
                                              geofence_uow=geofence_uow)

                    # default permissions for resource owner
                    set_owner_permissions(self)

                    # Anonymous User group
                    if 'users' in perm_spec and (
                            "AnonymousUser" in perm_spec['users']
                            or get_anonymous_user() in perm_spec['users']):
                        anonymous_user = "******" if "AnonymousUser" in perm_spec[
                            'users'] else get_anonymous_user()
                        anonymous_group = Group.objects.get(name='anonymous')
                        for perm in perm_spec['users'][anonymous_user]:
                            if self.polymorphic_ctype.name == 'layer' and perm in (
                                    'change_layer_data',
                                    'change_layer_style',
                                    'add_layer',
                                    'change_layer',
                                    'delete_layer',
                            ):
                                assign_perm(perm, anonymous_group, self.layer)
                            else:
                                assign_perm(perm, anonymous_group,
                                            self.get_self_resource())

                    # All the other users
                    if 'users' in perm_spec and len(perm_spec['users']) > 0:
                        for user, perms in perm_spec['users'].items():
                            _user = get_user_model().objects.get(username=user)
                            if _user != self.owner and user != "AnonymousUser" and user != get_anonymous_user(
                            ):
                                for perm in perms:
                                    if self.polymorphic_ctype.name == 'layer' and perm in (
                                            'change_layer_data',
                                            'change_layer_style',
                                            'add_layer',
                                            'change_layer',
                                            'delete_layer',
                                    ):
                                        assign_perm(perm, _user, self.layer)
                                    else:
                                        assign_perm(perm, _user,
                                                    self.get_self_resource())

                    # All the other groups
                    if 'groups' in perm_spec and len(perm_spec['groups']) > 0:
                        for group, perms in perm_spec['groups'].items():
                            _group = Group.objects.get(name=group)
                            for perm in perms:
                                if self.polymorphic_ctype.name == 'layer' and perm in (
                                        'change_layer_data',
                                        'change_layer_style',
                                        'add_layer',
                                        'change_layer',
                                        'delete_layer',
                                ):
                                    assign_perm(perm, _group, self.layer)
                                else:
                                    assign_perm(perm, _group,
                                                self.get_self_resource())

                    # AnonymousUser
                    if 'users' in perm_spec and len(perm_spec['users']) > 0:
                        if "AnonymousUser" in perm_spec[
                                'users'] or get_anonymous_user(
                                ) in perm_spec['users']:
                            _user = get_anonymous_user()
                            anonymous_user = "******" if "AnonymousUser" in perm_spec[
                                'users'] else get_anonymous_user()
                            perms = perm_spec['users'][anonymous_user]
                            for perm in perms:
                                if self.polymorphic_ctype.name == 'layer' and perm in (
                                        'change_layer_data',
                                        'change_layer_style',
                                        'add_layer',
                                        'change_layer',
                                        'delete_layer',
                                ):
                                    assign_perm(perm, _user, self.layer)
                                else:
                                    assign_perm(perm, _user,
                                                self.get_self_resource())

                # Fixup GIS Backend Security Rules Accordingly
                if self.polymorphic_ctype.name == 'layer':
                    if settings.OGC_SERVER['default'].get(
                            "GEOFENCE_SECURITY_ENABLED", False):
                        if not getattr(settings, 'DELAYED_SECURITY_SIGNALS',
                                       False):

                            geofence_uow.purge_rules()

                            _disable_cache = []

                            # Owner
                            perms = [
                                "view_resourcebase", "change_layer_data",
                                "change_layer_style", "change_resourcebase",
                                "change_resourcebase_permissions",
                                "download_resourcebase"
                            ]
                            sync_geofence_with_guardian(
                                self.layer,
                                perms,
                                user=self.owner,
                                geofence_uow=geofence_uow)
                            gf_services = _get_gf_services(self.layer, perms)
                            _, _, _disable_layer_cache, _, _, _ = get_user_geolimits(
                                self.layer, self.owner, None, gf_services)
                            _disable_cache.append(_disable_layer_cache)

                            # All the other users
                            if 'users' in perm_spec and len(
                                    perm_spec['users']) > 0:
                                for user, perms in perm_spec['users'].items():
                                    _user = get_user_model().objects.get(
                                        username=user)
                                    group_perms = None
                                    if 'groups' in perm_spec and len(
                                            perm_spec['groups']) > 0:
                                        group_perms = perm_spec['groups']
                                    sync_geofence_with_guardian(
                                        self.layer,
                                        perms,
                                        user=_user,
                                        group_perms=group_perms,
                                        geofence_uow=geofence_uow)
                                    gf_services = _get_gf_services(
                                        self.layer, perms)
                                    _group = list(group_perms.keys()
                                                  )[0] if group_perms else None
                                    _, _, _disable_layer_cache, _, _, _ = get_user_geolimits(
                                        self.layer, _user, _group, gf_services)
                                    _disable_cache.append(_disable_layer_cache)

                            # All the other groups
                            if 'groups' in perm_spec and len(
                                    perm_spec['groups']) > 0:
                                for group, perms in perm_spec['groups'].items(
                                ):
                                    _group = Group.objects.get(name=group)
                                    if _group and _group.name and _group.name == 'anonymous':
                                        _group = None
                                    sync_geofence_with_guardian(
                                        self.layer,
                                        perms,
                                        group=_group,
                                        geofence_uow=geofence_uow)
                                    gf_services = _get_gf_services(
                                        self.layer, perms)
                                    _, _, _disable_layer_cache, _, _, _ = get_user_geolimits(
                                        self.layer, None, _group, gf_services)
                                    _disable_cache.append(_disable_layer_cache)

                            # AnonymousUser
                            if 'users' in perm_spec and len(
                                    perm_spec['users']) > 0:
                                if "AnonymousUser" in perm_spec[
                                        'users'] or get_anonymous_user(
                                        ) in perm_spec['users']:
                                    _user = get_anonymous_user()
                                    anonymous_user = "******" if "AnonymousUser" in perm_spec[
                                        'users'] else get_anonymous_user()
                                    perms = perm_spec['users'][anonymous_user]
                                    sync_geofence_with_guardian(
                                        self.layer,
                                        perms,
                                        geofence_uow=geofence_uow)
                                    gf_services = _get_gf_services(
                                        self.layer, perms)
                                    _, _, _disable_layer_cache, _, _, _ = get_user_geolimits(
                                        self.layer, _user, None, gf_services)
                                    _disable_cache.append(_disable_layer_cache)

                            # Force GeoFence rules cache invalidation
                            geofence_uow.set_invalidate_cache()

                            # Invalidate GWC Cache if Geo-limits have been activated
                            if _disable_cache:
                                if any(_disable_cache):
                                    filters = None
                                    formats = None
                                else:
                                    filters = [{
                                        "styleParameterFilter": {
                                            "STYLES": ""
                                        }
                                    }]
                                    formats = [
                                        'application/json;type=utfgrid',
                                        'image/gif', 'image/jpeg', 'image/png',
                                        'image/png8', 'image/vnd.jpeg-png',
                                        'image/vnd.jpeg-png8'
                                    ]
                                _layer_workspace = get_layer_workspace(
                                    self.layer)
                                toggle_layer_cache(
                                    f'{_layer_workspace}:{self.layer.name}',
                                    enable=True,
                                    filters=filters,
                                    formats=formats,
                                    geofence_uow=geofence_uow)
                        else:
                            self.set_dirty_state()
        except Exception as e:
            geofence_uow.rollback()
            raise GeoNodeException(e)