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()
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()
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)
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
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()
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
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 })
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()
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()
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)