From 99c548e8636a31fc70b2a3f2dad8a74b48f350bb Mon Sep 17 00:00:00 2001 From: afabiani Date: Wed, 8 May 2019 16:49:25 +0200 Subject: [PATCH 01/21] - [Minor fix] Proxy will attach access_token only if remote netloc matches the local one --- geonode/proxy/views.py | 32 ++++++++++--------- geonode/static/geonode/js/upload/LayerInfo.js | 2 +- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/geonode/proxy/views.py b/geonode/proxy/views.py index 8135d06de70..68533056d72 100644 --- a/geonode/proxy/views.py +++ b/geonode/proxy/views.py @@ -92,25 +92,27 @@ def get_headers(request, url, raw_url): headers["Content-Type"] = request.META["CONTENT_TYPE"] access_token = None - # we give precedence to obtained from Aithorization headers - if 'HTTP_AUTHORIZATION' in request.META: - auth_header = request.META.get( - 'HTTP_AUTHORIZATION', - request.META.get('HTTP_AUTHORIZATION2')) - if auth_header: - access_token = get_token_from_auth_header(auth_header) - # otherwise we check if a session is active - elif request and request.user.is_authenticated: - access_token = get_token_object_from_session(request.session) - - # we extend the token in case the session is active but the token expired - if access_token and access_token.is_expired(): - extend_token(access_token) + + site_url = urlsplit(settings.SITEURL) + if site_url.netloc == url.netloc: + # we give precedence to obtained from Aithorization headers + if 'HTTP_AUTHORIZATION' in request.META: + auth_header = request.META.get( + 'HTTP_AUTHORIZATION', + request.META.get('HTTP_AUTHORIZATION2')) + if auth_header: + access_token = get_token_from_auth_header(auth_header) + # otherwise we check if a session is active + elif request and request.user.is_authenticated: + access_token = get_token_object_from_session(request.session) + + # we extend the token in case the session is active but the token expired + if access_token and access_token.is_expired(): + extend_token(access_token) if access_token: headers['Authorization'] = 'Bearer %s' % access_token - site_url = urlsplit(settings.SITEURL) pragma = "no-cache" referer = request.META[ "HTTP_REFERER"] if "HTTP_REFERER" in request.META else \ diff --git a/geonode/static/geonode/js/upload/LayerInfo.js b/geonode/static/geonode/js/upload/LayerInfo.js index d96cc8c99eb..ebc6bf02059 100644 --- a/geonode/static/geonode/js/upload/LayerInfo.js +++ b/geonode/static/geonode/js/upload/LayerInfo.js @@ -614,7 +614,7 @@ define(function (require, exports) { type: this.type.name, format: this.type.format, time: time_enabled, - mosaic: mosaic_enabled + mosaic: mosaic_enabled }); file_queue.append(li); this.errors = this.collectErrors(); From 3f047692923432a91122f192537de1f7dcdbc2d6 Mon Sep 17 00:00:00 2001 From: afabiani Date: Thu, 9 May 2019 16:02:05 +0200 Subject: [PATCH 02/21] [Minor optimizations] settings X_FRAME_OPTIONS allow localhost / add geoserver local services paths to geoserver proxy --- geonode/geoserver/urls.py | 9 +++++++++ geonode/settings.py | 3 ++- geonode/templates/index.html | 1 - 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/geonode/geoserver/urls.py b/geonode/geoserver/urls.py index dc5b81ba524..c2456357972 100644 --- a/geonode/geoserver/urls.py +++ b/geonode/geoserver/urls.py @@ -55,9 +55,18 @@ downstream_path='wps'), name='wps_endpoint'), url(r'^pdf', views.geoserver_proxy, dict(proxy_path='/gs/pdf', downstream_path='pdf'), name='pdf_endpoint'), + url(r'^(?P[^/]*)/(?P[^/]*)/ows', + views.geoserver_proxy, + dict(proxy_path='/gs/%s' % settings.DEFAULT_WORKSPACE, downstream_path='ows')), url(r'^(?P[^/]*)/(?P[^/]*)/wms', views.geoserver_proxy, dict(proxy_path='/gs/%s' % settings.DEFAULT_WORKSPACE, downstream_path='wms')), + url(r'^(?P[^/]*)/(?P[^/]*)/wfs', + views.geoserver_proxy, + dict(proxy_path='/gs/%s' % settings.DEFAULT_WORKSPACE, downstream_path='wfs')), + url(r'^(?P[^/]*)/(?P[^/]*)/wcs', + views.geoserver_proxy, + dict(proxy_path='/gs/%s' % settings.DEFAULT_WORKSPACE, downstream_path='wcs')), url(r'^updatelayers/$', views.updatelayers, name="updatelayers"), diff --git a/geonode/settings.py b/geonode/settings.py index 22fd38ffce6..3bd70b55c21 100644 --- a/geonode/settings.py +++ b/geonode/settings.py @@ -580,7 +580,8 @@ SESSION_COOKIE_SECURE = False CSRF_COOKIE_SECURE = False CSRF_COOKIE_HTTPONLY = False -X_FRAME_OPTIONS = 'DENY' +# X_FRAME_OPTIONS = 'DENY' +X_FRAME_OPTIONS = 'ALLOW-FROM %s' % SITEURL SECURE_CONTENT_TYPE_NOSNIFF = True SECURE_BROWSER_XSS_FILTER = True SECURE_SSL_REDIRECT = False diff --git a/geonode/templates/index.html b/geonode/templates/index.html index 5c1054e5552..a143124feff 100644 --- a/geonode/templates/index.html +++ b/geonode/templates/index.html @@ -379,7 +379,6 @@
{{ custom_theme.cookie_law_info_bar_head }}
From cd3940113abb05556da437c2b4818939c9462275 Mon Sep 17 00:00:00 2001 From: Alessio Fabiani Date: Thu, 9 May 2019 16:32:05 +0200 Subject: [PATCH 03/21] revert wrong setting --- geonode/settings.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/geonode/settings.py b/geonode/settings.py index 3bd70b55c21..22fd38ffce6 100644 --- a/geonode/settings.py +++ b/geonode/settings.py @@ -580,8 +580,7 @@ SESSION_COOKIE_SECURE = False CSRF_COOKIE_SECURE = False CSRF_COOKIE_HTTPONLY = False -# X_FRAME_OPTIONS = 'DENY' -X_FRAME_OPTIONS = 'ALLOW-FROM %s' % SITEURL +X_FRAME_OPTIONS = 'DENY' SECURE_CONTENT_TYPE_NOSNIFF = True SECURE_BROWSER_XSS_FILTER = True SECURE_SSL_REDIRECT = False From f053c136517028957bdfe4de15f62f7ad10f3c2c Mon Sep 17 00:00:00 2001 From: Alessio Fabiani Date: Thu, 9 May 2019 16:32:45 +0200 Subject: [PATCH 04/21] Update local_settings.py.geoserver.sample --- geonode/local_settings.py.geoserver.sample | 1 + 1 file changed, 1 insertion(+) diff --git a/geonode/local_settings.py.geoserver.sample b/geonode/local_settings.py.geoserver.sample index 1f45937522d..3df08f460b8 100644 --- a/geonode/local_settings.py.geoserver.sample +++ b/geonode/local_settings.py.geoserver.sample @@ -509,6 +509,7 @@ LOGGING = { } # Additional settings +X_FRAME_OPTIONS = 'ALLOW-FROM %s' % SITEURL CORS_ORIGIN_ALLOW_ALL = True GEOIP_PATH = "/usr/local/share/GeoIP" From 19743509eda6b6304a538314927413a2d573ea5b Mon Sep 17 00:00:00 2001 From: afabiani Date: Fri, 10 May 2019 09:55:42 +0200 Subject: [PATCH 05/21] [Minor improvements] Allow requests get to use timeouts / expose Monitoring variables --- geonode/base/management/commands/backup.py | 9 ++-- geonode/base/management/commands/restore.py | 9 ++-- .../contrib/monitoring/service_handlers.py | 4 +- geonode/contrib/monitoring/utils.py | 41 +++++++++++-------- geonode/security/utils.py | 12 ++++-- geonode/settings.py | 2 +- 6 files changed, 47 insertions(+), 30 deletions(-) diff --git a/geonode/base/management/commands/backup.py b/geonode/base/management/commands/backup.py index 9265ed22ba9..497bca467c1 100644 --- a/geonode/base/management/commands/backup.py +++ b/geonode/base/management/commands/backup.py @@ -108,7 +108,8 @@ def create_geoserver_backup(self, settings, target_folder): gs_bk_exec_id = gs_backup['backup']['execution']['id'] r = requests.get(url + 'rest/br/backup/' + str(gs_bk_exec_id) + '.json', - auth=HTTPBasicAuth(user, passwd)) + auth=HTTPBasicAuth(user, passwd), + timeout=10) if (r.status_code == 200): try: @@ -130,7 +131,8 @@ def create_geoserver_backup(self, settings, target_folder): gs_bk_exec_id = gs_backup['backup']['execution']['id'] r = requests.get(url + 'rest/br/backup/' + str(gs_bk_exec_id) + '.json', - auth=HTTPBasicAuth(user, passwd)) + auth=HTTPBasicAuth(user, passwd), + timeout=10) if (r.status_code == 200): gs_bk_exec_status = gs_backup['backup']['execution']['status'] gs_bk_exec_progress = gs_backup['backup']['execution']['progress'] @@ -139,7 +141,8 @@ def create_geoserver_backup(self, settings, target_folder): if (gs_bk_exec_progress != gs_bk_exec_progress_updated): gs_bk_exec_progress_updated = gs_bk_exec_progress r = requests.get(url + 'rest/br/backup/' + str(gs_bk_exec_id) + '.json', - auth=HTTPBasicAuth(user, passwd)) + auth=HTTPBasicAuth(user, passwd), + timeout=10) if (r.status_code == 200): try: diff --git a/geonode/base/management/commands/restore.py b/geonode/base/management/commands/restore.py index e9eb2f7accd..a25715a683e 100755 --- a/geonode/base/management/commands/restore.py +++ b/geonode/base/management/commands/restore.py @@ -121,7 +121,8 @@ def restore_geoserver_backup(self, settings, target_folder): gs_bk_exec_id = gs_backup['restore']['execution']['id'] r = requests.get(url + 'rest/br/restore/' + str(gs_bk_exec_id) + '.json', - auth=HTTPBasicAuth(user, passwd)) + auth=HTTPBasicAuth(user, passwd), + timeout=10) if (r.status_code == 200): try: @@ -143,7 +144,8 @@ def restore_geoserver_backup(self, settings, target_folder): gs_bk_exec_id = gs_backup['restore']['execution']['id'] r = requests.get(url + 'rest/br/restore/' + str(gs_bk_exec_id) + '.json', - auth=HTTPBasicAuth(user, passwd)) + auth=HTTPBasicAuth(user, passwd), + timeout=10) if (r.status_code == 200): gs_bk_exec_status = gs_backup['restore']['execution']['status'] gs_bk_exec_progress = gs_backup['restore']['execution']['progress'] @@ -152,7 +154,8 @@ def restore_geoserver_backup(self, settings, target_folder): if (gs_bk_exec_progress != gs_bk_exec_progress_updated): gs_bk_exec_progress_updated = gs_bk_exec_progress r = requests.get(url + 'rest/br/restore/' + str(gs_bk_exec_id) + '.json', - auth=HTTPBasicAuth(user, passwd)) + auth=HTTPBasicAuth(user, passwd), + timeout=10) if (r.status_code == 200): try: diff --git a/geonode/contrib/monitoring/service_handlers.py b/geonode/contrib/monitoring/service_handlers.py index 59da1308ff8..ceeb91cc8e0 100644 --- a/geonode/contrib/monitoring/service_handlers.py +++ b/geonode/contrib/monitoring/service_handlers.py @@ -189,7 +189,7 @@ def _collect(self, *args, **kwargs): if not base_url: raise ValueError("Service {} should have url provided".format(self.service.name)) url = '{}{}'.format(base_url.rstrip('/'), self.PATH) - rdata = requests.get(url) + rdata = requests.get(url, timeout=10) if rdata.status_code != 200: raise ValueError("Error response from api: ({}) {}".format(url, rdata)) data = rdata.json()['metrics']['metric'] @@ -206,7 +206,7 @@ def _collect(self, since, until, *args, **kwargs): if not base_url: raise ValueError("Service {} should have url provided".format(self.service.name)) url = '{}/monitoring/api/beacon/{}/'.format(base_url.rstrip('/'), self.service.service_type.name) - rdata = requests.get(url) + rdata = requests.get(url, timeout=10) if rdata.status_code != 200: raise ValueError("Error response from api: ({}) {}".format(url, rdata)) data = rdata.json() diff --git a/geonode/contrib/monitoring/utils.py b/geonode/contrib/monitoring/utils.py index 347df708f80..99ec27365ef 100644 --- a/geonode/contrib/monitoring/utils.py +++ b/geonode/contrib/monitoring/utils.py @@ -19,22 +19,23 @@ ######################################################################### import os +import re import pytz -import threading -import traceback +import types import Queue import logging import xmljson -import types -import re -from urllib import urlencode -from datetime import datetime, timedelta -from math import floor, ceil +import requests +import threading +import traceback -from xml.etree import ElementTree as etree +from math import floor, ceil +from urllib import urlencode +from urlparse import urlsplit from bs4 import BeautifulSoup as bs from requests.auth import HTTPBasicAuth -import requests +from datetime import datetime, timedelta +from xml.etree import ElementTree as etree from django.conf import settings from django.db.models.fields.related import RelatedField @@ -116,11 +117,14 @@ def __init__(self, base_url): self.base_url = base_url def get_href(self, link, format=None): - href = link['href'] + href = urlsplit(link['href']) + base_url = urlsplit(self.base_url) + if href and href.netloc != base_url.netloc: + href = href._replace(netloc=base_url.netloc) if format is None: - return href + return href.geturl() if format in self.REPORT_FORMATS: - href, ext = os.path.splitext(href) + href, ext = os.path.splitext(href.geturl()) return '{}.{}'.format(href, format) return format @@ -142,13 +146,13 @@ def get_requests(self, format=None, since=None, until=None): print('checking', rest_url) username = settings.OGC_SERVER['default']['USER'] password = settings.OGC_SERVER['default']['PASSWORD'] - resp = requests.get(rest_url, auth=HTTPBasicAuth(username, password)) + resp = requests.get( + rest_url, + auth=HTTPBasicAuth(username, password), + timeout=30) doc = bs(resp.content) links = doc.find_all('a') for l in links: - # we're skipping this check, as gs can generate - # url with other base url - # if l.get('href').startswith(self.base_url): href = self.get_href(l, format) data = self.get_request(href, format=format) if data: @@ -159,7 +163,10 @@ def get_requests(self, format=None, since=None, until=None): def get_request(self, href, format=format): username = settings.OGC_SERVER['default']['USER'] password = settings.OGC_SERVER['default']['PASSWORD'] - r = requests.get(href, auth=HTTPBasicAuth(username, password)) + r = requests.get( + href, + auth=HTTPBasicAuth(username, password), + timeout=30) if r.status_code != 200: log.warning('Invalid response for %s: %s', href, r) return diff --git a/geonode/security/utils.py b/geonode/security/utils.py index 74b8054054c..ae5bb7e3e62 100644 --- a/geonode/security/utils.py +++ b/geonode/security/utils.py @@ -182,7 +182,8 @@ def get_geofence_rules_count(): headers = {'Content-type': 'application/json'} r = requests.get(url + 'rest/geofence/rules/count.json', headers=headers, - auth=HTTPBasicAuth(user, passwd)) + auth=HTTPBasicAuth(user, passwd), + timeout=10) if (r.status_code < 200 or r.status_code > 201): logger.warning("Could not retrieve GeoFence Rules count.") @@ -212,7 +213,8 @@ def get_highest_priority(): headers = {'Content-type': 'application/json'} r = requests.get(url + 'rest/geofence/rules.json?page=' + str(rules_count - 1) + '&entries=1', headers=headers, - auth=HTTPBasicAuth(user, passwd)) + auth=HTTPBasicAuth(user, passwd), + timeout=10) if (r.status_code < 200 or r.status_code > 201): logger.warning("Could not retrieve GeoFence Rules count.") @@ -243,7 +245,8 @@ def purge_geofence_all(): headers = {'Content-type': 'application/json'} r = requests.get(url + 'rest/geofence/rules.json', headers=headers, - auth=HTTPBasicAuth(user, passwd)) + auth=HTTPBasicAuth(user, passwd), + timeout=10) if (r.status_code < 200 or r.status_code > 201): logger.warning("Could not Retrieve GeoFence Rules") else: @@ -287,7 +290,8 @@ def purge_geofence_layer_rules(resource): "{}rest/geofence/rules.json?workspace={}&layer={}".format( url, workspace, resource.layer.name), headers=headers, - auth=HTTPBasicAuth(user, passwd) + auth=HTTPBasicAuth(user, passwd), + timeout=10 ) if (r.status_code >= 200 and r.status_code < 300): gs_rules = r.json() diff --git a/geonode/settings.py b/geonode/settings.py index 22fd38ffce6..246912e7d6b 100644 --- a/geonode/settings.py +++ b/geonode/settings.py @@ -1539,7 +1539,7 @@ # add following lines to your local settings to enable monitoring MONITORING_ENABLED = ast.literal_eval(os.environ.get('MONITORING_ENABLED', 'False')) MONITORING_HOST_NAME = os.getenv("MONITORING_HOST_NAME", HOSTNAME) -MONITORING_SERVICE_NAME = 'geonode' +MONITORING_SERVICE_NAME = os.getenv("MONITORING_SERVICE_NAME", 'local-geoserver') # how long monitoring data should be stored MONITORING_DATA_TTL = timedelta(days=7) From 9c5311178e1983ec1d415d5ebdf8aedca2810da9 Mon Sep 17 00:00:00 2001 From: afabiani Date: Fri, 10 May 2019 12:50:07 +0200 Subject: [PATCH 06/21] [Minor fixes] settings typos and fixoauth mgt commands --- geonode/base/management/commands/fixoauthuri.py | 15 ++++++++++++++- geonode/local_settings.py.geoserver.sample | 2 +- geonode/settings.py | 2 +- package/support/geonode.updateip | 6 +++--- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/geonode/base/management/commands/fixoauthuri.py b/geonode/base/management/commands/fixoauthuri.py index 0bd17856624..ce2ed5ce20c 100644 --- a/geonode/base/management/commands/fixoauthuri.py +++ b/geonode/base/management/commands/fixoauthuri.py @@ -32,13 +32,26 @@ class Command(BaseCommand): """ can_import_settings = True + def add_arguments(self, parser): + parser.add_argument( + '--target-address', + dest='target_address', + help='Target Address (the one to be changed e.g. http://my-public.geonode.org)') + def handle(self, *args, **options): + + target_address = options.get('target_address') + from django.conf import settings client_id = None client_secret = None + if check_ogc_backend(geoserver.BACKEND_PACKAGE): from geonode.geoserver.helpers import ogc_server_settings - redirect_uris = '%s\n%s' % (ogc_server_settings.LOCATION, ogc_server_settings.public_url) + redirect_uris = '%s\n%s\n%s' % ( + ogc_server_settings.LOCATION, + ogc_server_settings.public_url, + "http://{}/geoserver/".format(target_address)) if Application.objects.filter(name='GeoServer').exists(): Application.objects.filter(name='GeoServer').update(redirect_uris=redirect_uris) app = Application.objects.filter(name='GeoServer')[0] diff --git a/geonode/local_settings.py.geoserver.sample b/geonode/local_settings.py.geoserver.sample index 3df08f460b8..eff8a309e3f 100644 --- a/geonode/local_settings.py.geoserver.sample +++ b/geonode/local_settings.py.geoserver.sample @@ -525,7 +525,7 @@ if MONITORING_ENABLED: ('geonode.contrib.monitoring.middleware.MonitoringMiddleware',) MONITORING_CONFIG = None MONITORING_HOST_NAME = os.getenv("MONITORING_HOST_NAME", HOSTNAME) - MONITORING_SERVICE_NAME = 'geonode' + MONITORING_SERVICE_NAME = os.getenv("MONITORING_SERVICE_NAME", 'local-geonode') # Documents Thumbnails diff --git a/geonode/settings.py b/geonode/settings.py index 246912e7d6b..f5debc1ed34 100644 --- a/geonode/settings.py +++ b/geonode/settings.py @@ -1539,7 +1539,7 @@ # add following lines to your local settings to enable monitoring MONITORING_ENABLED = ast.literal_eval(os.environ.get('MONITORING_ENABLED', 'False')) MONITORING_HOST_NAME = os.getenv("MONITORING_HOST_NAME", HOSTNAME) -MONITORING_SERVICE_NAME = os.getenv("MONITORING_SERVICE_NAME", 'local-geoserver') +MONITORING_SERVICE_NAME = os.getenv("MONITORING_SERVICE_NAME", 'local-geonode') # how long monitoring data should be stored MONITORING_DATA_TTL = timedelta(days=7) diff --git a/package/support/geonode.updateip b/package/support/geonode.updateip index f14eb924a11..7aecda57f13 100644 --- a/package/support/geonode.updateip +++ b/package/support/geonode.updateip @@ -180,14 +180,14 @@ client_secret=`echo $oauth_keys | cut -d \, -f 2` oauth_config="$GEOSERVER_DATA_DIR/security/filter/geonode-oauth2/config.xml" sed -i "s|.*|$client_id|g" $oauth_config sed -i "s|.*|$client_secret|g" $oauth_config -sed -i "s|.*|$NEW_INT_IP/o/token/|g" $oauth_config +sed -i "s|.*|$NEW_EXT_IP/o/token/|g" $oauth_config sed -i "s|.*|$NEW_EXT_IP/o/authorize/|g" $oauth_config sed -i "s|.*|$NEW_EXT_IP/geoserver/|g" $oauth_config -sed -i "s|.*|$NEW_INT_IP/api/o/v4/tokeninfo/|g" $oauth_config +sed -i "s|.*|$NEW_EXT_IP/api/o/v4/tokeninfo/|g" $oauth_config sed -i "s|.*|$NEW_EXT_IP/account/logout/|g" $oauth_config # Updating REST Role Service Config -sed -i "s|.*|$NEW_INT_IP|g" "$GEOSERVER_DATA_DIR/security/role/geonode REST role service/config.xml" +sed -i "s|.*|$NEW_EXT_IP|g" "$GEOSERVER_DATA_DIR/security/role/geonode REST role service/config.xml" # Updating GeoServer Global Config global_config="$GEOSERVER_DATA_DIR/global.xml" From dc6e1f2c912d0045fa07689967e6b4a02a22ec5e Mon Sep 17 00:00:00 2001 From: afabiani Date: Fri, 10 May 2019 14:04:55 +0200 Subject: [PATCH 07/21] [Minor fixes] settings typos and fixoauth mgt commands --- .../base/management/commands/fixoauthuri.py | 18 +++++++++++++++++- package/support/geonode.updateip | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/geonode/base/management/commands/fixoauthuri.py b/geonode/base/management/commands/fixoauthuri.py index ce2ed5ce20c..f0bda906884 100644 --- a/geonode/base/management/commands/fixoauthuri.py +++ b/geonode/base/management/commands/fixoauthuri.py @@ -33,6 +33,16 @@ class Command(BaseCommand): can_import_settings = True def add_arguments(self, parser): + + # Named (optional) arguments + parser.add_argument( + '-f', + '--force', + action='store_true', + dest='force_exec', + default=False, + help='Forces the regeneration of OAUth keys.') + parser.add_argument( '--target-address', dest='target_address', @@ -40,6 +50,7 @@ def add_arguments(self, parser): def handle(self, *args, **options): + force_exec = options.get('force_exec') target_address = options.get('target_address') from django.conf import settings @@ -51,9 +62,14 @@ def handle(self, *args, **options): redirect_uris = '%s\n%s\n%s' % ( ogc_server_settings.LOCATION, ogc_server_settings.public_url, - "http://{}/geoserver/".format(target_address)) + "{0}/geoserver/".format(target_address)) if Application.objects.filter(name='GeoServer').exists(): Application.objects.filter(name='GeoServer').update(redirect_uris=redirect_uris) + if force_exec: + Application.objects.filter(name='GeoServer').update( + client_id=generate_client_id(), + client_secret=generate_client_secret() + ) app = Application.objects.filter(name='GeoServer')[0] client_id = app.client_id client_secret = app.client_secret diff --git a/package/support/geonode.updateip b/package/support/geonode.updateip index 7aecda57f13..46a71ea4f2e 100644 --- a/package/support/geonode.updateip +++ b/package/support/geonode.updateip @@ -172,7 +172,7 @@ geonode fixsitename echo "Setting up oauth" # Set oauth keys -oauth_keys=$(geonode fixoauthuri 2>&1) +oauth_keys=$(geonode fixoauthuri -f --target-address $NEW_EXT_IP 2>&1) client_id=`echo $oauth_keys | cut -d \, -f 1` client_secret=`echo $oauth_keys | cut -d \, -f 2` From da891dd437d2ed0eba6fa054c46cb5a8e461ec82 Mon Sep 17 00:00:00 2001 From: afabiani Date: Fri, 10 May 2019 15:35:49 +0200 Subject: [PATCH 08/21] [Themes] Add more nav customization options --- geonode/templates/base.html | 51 ++++++++++++++++++- geonode/themes/admin.py | 7 +++ .../migrations/0005_auto_20190510_1335.py | 50 ++++++++++++++++++ geonode/themes/models.py | 7 +++ 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 geonode/themes/migrations/0005_auto_20190510_1335.py diff --git a/geonode/templates/base.html b/geonode/templates/base.html index 71cb088a50c..f1f22991e78 100644 --- a/geonode/templates/base.html +++ b/geonode/templates/base.html @@ -64,11 +64,60 @@ {% endif %} {% if custom_theme.navbar_color %} - .home .navbar-inverse , .navbar-inverse { + .navbar-inverse , .navbar-inverse { background-color: {{ custom_theme.navbar_color }}; } {% endif %} + {% if custom_theme.navbar_text_color %} + .navbar-inverse .navbar-nav > li > a { + color: {{ custom_theme.navbar_text_color }}; + font-weight: 600; + padding-top: 25px; + padding-bottom: 25px; + } + {% endif + + {% if custom_theme.navbar_text_hover %} + .navbar-inverse .navbar-nav > li > a:hover { + background-color: {{ custom_theme.navbar_text_hover }}; + } + {% endif %} + + {% if custom_theme.navbar_text_hover_focus %} + .navbar-inverse .navbar-nav > .open > a, + .navbar-inverse .navbar-nav > .open > a:hover, + .navbar-inverse .navbar-nav > .open > a:focus { + background-color: {{ custom_theme.navbar_text_hover_focus }}; + } + {% endif %} + + {% if custom_theme.navbar_dropdown_menu %} + .navbar-nav .dropdown-menu { + background-color: {{ custom_theme.navbar_dropdown_menu }}; + border-top: 1px solid {{ custom_theme.navbar_dropdown_menu }}; + } + {% endif %} + + {% if custom_theme.navbar_dropdown_menu_text %} + .navbar-nav .dropdown-menu a { + color: {{ custom_theme.navbar_dropdown_menu_text }}; + } + {% endif %} + + {% if custom_theme.navbar_dropdown_menu_hover %} + .navbar-nav .dropdown-menu li a:hover { + background-color: {{ custom_theme.navbar_dropdown_menu_hover }}; + color: {{ custom_theme.navbar_dropdown_menu_text }}; + } + {% endif %} + + {% if custom_theme.navbar_dropdown_menu_divider %} + .navbar-nav .dropdown-menu .divider { + background-color: {{ custom_theme.navbar_dropdown_menu_divider }}; + } + {% endif %} + {% if custom_theme.logo %} .navbar-brand { background-image: url({{ custom_theme.logo.url }}); diff --git a/geonode/themes/admin.py b/geonode/themes/admin.py index f84c3bd1230..378c05ea716 100644 --- a/geonode/themes/admin.py +++ b/geonode/themes/admin.py @@ -35,6 +35,13 @@ class Meta: widgets = { 'body_color': forms.TextInput(attrs={'type': 'color'}), 'navbar_color': forms.TextInput(attrs={'type': 'color'}), + 'navbar_text_color': forms.TextInput(attrs={'type': 'color'}), + 'navbar_text_hover': forms.TextInput(attrs={'type': 'color'}), + 'navbar_text_hover_focus': forms.TextInput(attrs={'type': 'color'}), + 'navbar_dropdown_menu': forms.TextInput(attrs={'type': 'color'}), + 'navbar_dropdown_menu_text': forms.TextInput(attrs={'type': 'color'}), + 'navbar_dropdown_menu_hover': forms.TextInput(attrs={'type': 'color'}), + 'navbar_dropdown_menu_divider': forms.TextInput(attrs={'type': 'color'}), 'jumbotron_color': forms.TextInput(attrs={'type': 'color'}), 'copyright_color': forms.TextInput(attrs={'type': 'color'}), 'cookie_law_info_background': forms.TextInput(attrs={'type': 'color'}), diff --git a/geonode/themes/migrations/0005_auto_20190510_1335.py b/geonode/themes/migrations/0005_auto_20190510_1335.py new file mode 100644 index 00000000000..86f1f6121ad --- /dev/null +++ b/geonode/themes/migrations/0005_auto_20190510_1335.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-05-10 13:35 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('geonode_themes', '0004_auto_20190503_1817'), + ] + + operations = [ + migrations.AddField( + model_name='geonodethemecustomization', + name='navbar_dropdown_menu', + field=models.CharField(default=b'#2c689c', max_length=10), + ), + migrations.AddField( + model_name='geonodethemecustomization', + name='navbar_dropdown_menu_divider', + field=models.CharField(default=b'#204d74', max_length=10), + ), + migrations.AddField( + model_name='geonodethemecustomization', + name='navbar_dropdown_menu_hover', + field=models.CharField(default=b'#204d74', max_length=10), + ), + migrations.AddField( + model_name='geonodethemecustomization', + name='navbar_dropdown_menu_text', + field=models.CharField(default=b'#ffffff', max_length=10), + ), + migrations.AddField( + model_name='geonodethemecustomization', + name='navbar_text_color', + field=models.CharField(default=b'#ffffff', max_length=10), + ), + migrations.AddField( + model_name='geonodethemecustomization', + name='navbar_text_hover', + field=models.CharField(default=b'#2c689c', max_length=10), + ), + migrations.AddField( + model_name='geonodethemecustomization', + name='navbar_text_hover_focus', + field=models.CharField(default=b'#2c689c', max_length=10), + ), + ] diff --git a/geonode/themes/models.py b/geonode/themes/models.py index 3febf449e00..7483160236b 100644 --- a/geonode/themes/models.py +++ b/geonode/themes/models.py @@ -73,6 +73,13 @@ class GeoNodeThemeCustomization(models.Model): jumbotron_cta_link = models.CharField(max_length=255, null=True, blank=True, verbose_name="Call to action link") body_color = models.CharField(max_length=10, default="#333333") navbar_color = models.CharField(max_length=10, default="#333333") + navbar_text_color = models.CharField(max_length=10, default="#ffffff") + navbar_text_hover = models.CharField(max_length=10, default="#2c689c") + navbar_text_hover_focus = models.CharField(max_length=10, default="#2c689c") + navbar_dropdown_menu = models.CharField(max_length=10, default="#2c689c") + navbar_dropdown_menu_text = models.CharField(max_length=10, default="#ffffff") + navbar_dropdown_menu_hover = models.CharField(max_length=10, default="#204d74") + navbar_dropdown_menu_divider = models.CharField(max_length=10, default="#204d74") jumbotron_color = models.CharField(max_length=10, default="#2c689c") contactus = models.BooleanField(default=False, verbose_name="Enable contact us box") contact_name = models.CharField(max_length=255, null=True, blank=True) From e26017ece8d9c602922da50b27cdea33ebcb4ccf Mon Sep 17 00:00:00 2001 From: geosolutions Date: Fri, 10 May 2019 14:03:05 +0000 Subject: [PATCH 09/21] [Template] typo --- geonode/templates/base.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/geonode/templates/base.html b/geonode/templates/base.html index f1f22991e78..be6e776a64b 100644 --- a/geonode/templates/base.html +++ b/geonode/templates/base.html @@ -60,11 +60,14 @@ {% if custom_theme.body_color %} body { background: {{ custom_theme.body_color }}; + {% if custom_theme.body_text %} + color: {{ custom_theme.body_text }}; + {% endif %} } {% endif %} {% if custom_theme.navbar_color %} - .navbar-inverse , .navbar-inverse { + .home .navbar-inverse , .navbar-inverse { background-color: {{ custom_theme.navbar_color }}; } {% endif %} @@ -76,7 +79,7 @@ padding-top: 25px; padding-bottom: 25px; } - {% endif + {% endif %} {% if custom_theme.navbar_text_hover %} .navbar-inverse .navbar-nav > li > a:hover { From 9a56c992fa4397c1128a4b03ec93dc2b1cdb45cb Mon Sep 17 00:00:00 2001 From: afabiani Date: Fri, 10 May 2019 16:07:17 +0200 Subject: [PATCH 10/21] [Themes] Add more nav customization options --- geonode/templates/base.html | 4 ++-- geonode/themes/admin.py | 1 + ...onodethemecustomization_body_text_color.py | 20 +++++++++++++++++++ geonode/themes/models.py | 1 + 4 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 geonode/themes/migrations/0006_geonodethemecustomization_body_text_color.py diff --git a/geonode/templates/base.html b/geonode/templates/base.html index be6e776a64b..d2eca445958 100644 --- a/geonode/templates/base.html +++ b/geonode/templates/base.html @@ -60,8 +60,8 @@ {% if custom_theme.body_color %} body { background: {{ custom_theme.body_color }}; - {% if custom_theme.body_text %} - color: {{ custom_theme.body_text }}; + {% if custom_theme.body_text_color %} + color: {{ custom_theme.body_text_color }}; {% endif %} } {% endif %} diff --git a/geonode/themes/admin.py b/geonode/themes/admin.py index 378c05ea716..219726d4b34 100644 --- a/geonode/themes/admin.py +++ b/geonode/themes/admin.py @@ -34,6 +34,7 @@ class Meta: model = GeoNodeThemeCustomization widgets = { 'body_color': forms.TextInput(attrs={'type': 'color'}), + 'body_text_color': forms.TextInput(attrs={'type': 'color'}), 'navbar_color': forms.TextInput(attrs={'type': 'color'}), 'navbar_text_color': forms.TextInput(attrs={'type': 'color'}), 'navbar_text_hover': forms.TextInput(attrs={'type': 'color'}), diff --git a/geonode/themes/migrations/0006_geonodethemecustomization_body_text_color.py b/geonode/themes/migrations/0006_geonodethemecustomization_body_text_color.py new file mode 100644 index 00000000000..7c69a26a497 --- /dev/null +++ b/geonode/themes/migrations/0006_geonodethemecustomization_body_text_color.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-05-10 14:06 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('geonode_themes', '0005_auto_20190510_1335'), + ] + + operations = [ + migrations.AddField( + model_name='geonodethemecustomization', + name='body_text_color', + field=models.CharField(default=b'#3a3a3a', max_length=10), + ), + ] diff --git a/geonode/themes/models.py b/geonode/themes/models.py index 7483160236b..d5078e174cf 100644 --- a/geonode/themes/models.py +++ b/geonode/themes/models.py @@ -72,6 +72,7 @@ class GeoNodeThemeCustomization(models.Model): jumbotron_cta_text = models.CharField(max_length=255, null=True, blank=True, verbose_name="Call to action text") jumbotron_cta_link = models.CharField(max_length=255, null=True, blank=True, verbose_name="Call to action link") body_color = models.CharField(max_length=10, default="#333333") + body_text_color = models.CharField(max_length=10, default="#3a3a3a") navbar_color = models.CharField(max_length=10, default="#333333") navbar_text_color = models.CharField(max_length=10, default="#ffffff") navbar_text_hover = models.CharField(max_length=10, default="#2c689c") From e41d5c4edc1a0fa9b83172d90d39c723bf617417 Mon Sep 17 00:00:00 2001 From: afabiani Date: Fri, 10 May 2019 17:46:14 +0200 Subject: [PATCH 11/21] - More Theme options --- geonode/templates/base.html | 14 +++++++++++ geonode/themes/admin.py | 2 ++ .../migrations/0007_auto_20190510_1545.py | 25 +++++++++++++++++++ geonode/themes/models.py | 2 ++ 4 files changed, 43 insertions(+) create mode 100644 geonode/themes/migrations/0007_auto_20190510_1545.py diff --git a/geonode/templates/base.html b/geonode/templates/base.html index d2eca445958..79ac05134d0 100644 --- a/geonode/templates/base.html +++ b/geonode/templates/base.html @@ -136,6 +136,20 @@ } {% endif %} + {% if custom_theme.jumbotron_title_color %} + .home .jumbotron h1, + .home .jumbotron h2, + .home .jumbotron h3 { + color: {{ custom_theme.jumbotron_title_color }} + } + {% endif %} + + {% if custom_theme.jumbotron_text_color %} + .home .jumbotron p { + color: {{ custom_theme.jumbotron_text_color }} + } + {% endif %} + {% if custom_theme.jumbotron_welcome_hide %} .home .jumbotron .container { visibility: hidden; diff --git a/geonode/themes/admin.py b/geonode/themes/admin.py index 219726d4b34..e9fc0f3cf2f 100644 --- a/geonode/themes/admin.py +++ b/geonode/themes/admin.py @@ -44,6 +44,8 @@ class Meta: 'navbar_dropdown_menu_hover': forms.TextInput(attrs={'type': 'color'}), 'navbar_dropdown_menu_divider': forms.TextInput(attrs={'type': 'color'}), 'jumbotron_color': forms.TextInput(attrs={'type': 'color'}), + 'jumbotron_title_color': forms.TextInput(attrs={'type': 'color'}), + 'jumbotron_text_color': forms.TextInput(attrs={'type': 'color'}), 'copyright_color': forms.TextInput(attrs={'type': 'color'}), 'cookie_law_info_background': forms.TextInput(attrs={'type': 'color'}), 'cookie_law_info_border': forms.TextInput(attrs={'type': 'color'}), diff --git a/geonode/themes/migrations/0007_auto_20190510_1545.py b/geonode/themes/migrations/0007_auto_20190510_1545.py new file mode 100644 index 00000000000..5d5ea58d15d --- /dev/null +++ b/geonode/themes/migrations/0007_auto_20190510_1545.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-05-10 15:45 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('geonode_themes', '0006_geonodethemecustomization_body_text_color'), + ] + + operations = [ + migrations.AddField( + model_name='geonodethemecustomization', + name='jumbotron_text_color', + field=models.CharField(default=b'#ffffff', max_length=10), + ), + migrations.AddField( + model_name='geonodethemecustomization', + name='jumbotron_title_color', + field=models.CharField(default=b'#ffffff', max_length=10), + ), + ] diff --git a/geonode/themes/models.py b/geonode/themes/models.py index d5078e174cf..7784aefcbc9 100644 --- a/geonode/themes/models.py +++ b/geonode/themes/models.py @@ -82,6 +82,8 @@ class GeoNodeThemeCustomization(models.Model): navbar_dropdown_menu_hover = models.CharField(max_length=10, default="#204d74") navbar_dropdown_menu_divider = models.CharField(max_length=10, default="#204d74") jumbotron_color = models.CharField(max_length=10, default="#2c689c") + jumbotron_title_color = models.CharField(max_length=10, default="#ffffff") + jumbotron_text_color = models.CharField(max_length=10, default="#ffffff") contactus = models.BooleanField(default=False, verbose_name="Enable contact us box") contact_name = models.CharField(max_length=255, null=True, blank=True) contact_position = models.CharField(max_length=255, null=True, blank=True) From 8a746f19f495ee34eff52f120da34f920da7be07 Mon Sep 17 00:00:00 2001 From: geosolutions Date: Fri, 10 May 2019 16:26:57 +0000 Subject: [PATCH 12/21] [Template] minor improvements --- geonode/templates/base.html | 2 +- geonode/templates/index.html | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/geonode/templates/base.html b/geonode/templates/base.html index 79ac05134d0..62aa4a86d19 100644 --- a/geonode/templates/base.html +++ b/geonode/templates/base.html @@ -474,7 +474,7 @@

{% trans "You are using an outdated browser that is not supported by GeoNode
diff --git a/geonode/templates/index.html b/geonode/templates/index.html index a143124feff..c0c6b6b1432 100644 --- a/geonode/templates/index.html +++ b/geonode/templates/index.html @@ -318,9 +318,15 @@

{{ item.title | limitTo: 20 }}{{item.title.length > 20 ? '...' : ''}}

{{ custom_theme.partners_title|default:_("Our partners") }}

{% for partner in custom_theme.partners.all %} - From 26d862c0b0efca1d1ef3b7a5ec6b00b1d3de62d5 Mon Sep 17 00:00:00 2001 From: afabiani Date: Mon, 13 May 2019 19:18:12 +0200 Subject: [PATCH 13/21] [Minor fix] do not overwrite thumbnail if it already exists --- geonode/geoserver/signals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geonode/geoserver/signals.py b/geonode/geoserver/signals.py index eff9cf6df94..833dbdcb080 100644 --- a/geonode/geoserver/signals.py +++ b/geonode/geoserver/signals.py @@ -91,7 +91,7 @@ def geoserver_post_save(instance, sender, **kwargs): if instance.storeType != 'remoteStore': logger.info("... Creating Thumbnail for Layer [%s]" % (instance.alternate)) try: - create_gs_thumbnail(instance, overwrite=True, check_bbox=True) + create_gs_thumbnail(instance, overwrite=False, check_bbox=True) except BaseException: logger.warn("!WARNING! - Failure while Creating Thumbnail for Layer [%s]" % (instance.alternate)) From 9cb15fc8ab1f6abc8450f71a51d59c80ce99d6aa Mon Sep 17 00:00:00 2001 From: afabiani Date: Mon, 13 May 2019 19:35:41 +0200 Subject: [PATCH 14/21] - Removing geonode.contrig.sites app by default --- geonode/settings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/geonode/settings.py b/geonode/settings.py index f5debc1ed34..9217e9be211 100644 --- a/geonode/settings.py +++ b/geonode/settings.py @@ -311,7 +311,6 @@ GEONODE_CONTRIB_APPS = ( # GeoNode Contrib Apps - 'geonode.contrib.geosites', 'geonode.contrib.metadataxsl', 'geonode.contrib.ows_api', ) From d121f4f00c8c7f434e240e765ddc485ae31155ea Mon Sep 17 00:00:00 2001 From: Hayden Elza Date: Mon, 13 May 2019 15:54:32 -0500 Subject: [PATCH 15/21] Spelling --- .../install_and_admin/running_docker/setup_docker_compose.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/install_and_admin/running_docker/setup_docker_compose.txt b/docs/tutorials/install_and_admin/running_docker/setup_docker_compose.txt index e7e90cb3625..0a0dea82998 100644 --- a/docs/tutorials/install_and_admin/running_docker/setup_docker_compose.txt +++ b/docs/tutorials/install_and_admin/running_docker/setup_docker_compose.txt @@ -43,7 +43,7 @@ Launch the stack with the build of GeoNode so any changes you did will be immedi docker-compose -f docker-compose.yml -f docker-compose.override.localhost.yml up --build .. note:: - **docker-compose.override.localhost.yml** containse environment variables to allow you run the instances on *localhost*. You can use this file as template in order to run on other public addresses. + **docker-compose.override.localhost.yml** contains environment variables to allow you run the instances on *localhost*. You can use this file as template in order to run on other public addresses. .. note:: **For Windows users**: In case you're using the native Docker for Windows (on Hyper-V) you will probably be affected by an error related to mounting the /var/run/docker.sock volume. It's due to a `problem with the current version of Docker Compose `_ for Windows. From 9330b9e66a0f8642d67cb295beae8d7cb69119df Mon Sep 17 00:00:00 2001 From: geosolutions Date: Tue, 14 May 2019 10:55:05 +0000 Subject: [PATCH 16/21] [Cleanup] cleanup settings and exposing some of them as env variables --- geonode/local_settings.py.geoserver.sample | 79 -------------- geonode/settings.py | 116 ++++++++++++--------- 2 files changed, 66 insertions(+), 129 deletions(-) diff --git a/geonode/local_settings.py.geoserver.sample b/geonode/local_settings.py.geoserver.sample index eff8a309e3f..84304e1b85b 100644 --- a/geonode/local_settings.py.geoserver.sample +++ b/geonode/local_settings.py.geoserver.sample @@ -29,31 +29,6 @@ import os from urlparse import urlparse, urlunparse from geonode.settings import * -# Require users to authenticate before using Geonode -LOCKDOWN_GEONODE = strtobool(os.getenv('LOCKDOWN_GEONODE', 'False')) - -# Require users to authenticate before using Geonode -if LOCKDOWN_GEONODE: - MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + \ - ('geonode.security.middleware.LoginRequiredMiddleware',) - -# Add additional paths (as regular expressions) that don't require -# authentication. -# - authorized exempt urls needed for oauth when GeoNode is set to lockdown -FORCE_SCRIPT_NAME = os.getenv('FORCE_SCRIPT_NAME', '') -AUTH_EXEMPT_URLS = ( - r'^%s/?$' % FORCE_SCRIPT_NAME, - '%s/o/*' % FORCE_SCRIPT_NAME, - '%s/gs/*' % FORCE_SCRIPT_NAME, - '%s/account/*' % FORCE_SCRIPT_NAME, - '%s/static/*' % FORCE_SCRIPT_NAME, - '%s/api/o/*' % FORCE_SCRIPT_NAME, - '%s/api/roles' % FORCE_SCRIPT_NAME, - '%s/api/adminRole' % FORCE_SCRIPT_NAME, - '%s/api/users' % FORCE_SCRIPT_NAME, - '%s/api/layers' % FORCE_SCRIPT_NAME, -) - PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) MEDIA_ROOT = os.getenv('MEDIA_ROOT', os.path.join(PROJECT_ROOT, "uploaded")) @@ -62,41 +37,8 @@ STATIC_ROOT = os.getenv('STATIC_ROOT', os.path.join(PROJECT_ROOT, "static_root") ) -# SECRET_KEY = '************************' -# Make this unique, and don't share it with anybody. -SECRET_KEY = os.getenv('SECRET_KEY', "123456") - -# per-deployment settings should go here -SITE_HOST_NAME = os.getenv('SITE_HOST_NAME', 'localhost') -SITE_HOST_PORT = os.getenv('SITE_HOST_PORT', None) -_default_siteurl = "http://%s:%s/" % (SITE_HOST_NAME, SITE_HOST_PORT) if SITE_HOST_PORT else "http://%s/" % SITE_HOST_NAME -SITEURL = os.getenv('SITEURL', _default_siteurl) - -# we need hostname for deployed -_surl = urlparse(SITEURL) -HOSTNAME = _surl.hostname - -# add trailing slash to site url. geoserver url will be relative to this -if not SITEURL.endswith('/'): - SITEURL = '{}/'.format(SITEURL) - -try: - # try to parse python notation, default in dockerized env - ALLOWED_HOSTS = ast.literal_eval(os.getenv('ALLOWED_HOSTS')) -except ValueError: - # fallback to regular list of values separated with misc chars - ALLOWED_HOSTS = [HOSTNAME, 'localhost', 'django', 'geonode'] if os.getenv('ALLOWED_HOSTS') is None \ - else re.split(r' *[,|:|;] *', os.getenv('ALLOWED_HOSTS')) - TIME_ZONE = 'UTC' -# Login and logout urls override -LOGIN_URL = os.getenv('LOGIN_URL', '{}account/login/'.format(SITEURL)) -LOGOUT_URL = os.getenv('LOGOUT_URL', '{}account/logout/'.format(SITEURL)) - -ACCOUNT_LOGIN_REDIRECT_URL = os.getenv('LOGIN_REDIRECT_URL', SITEURL) -ACCOUNT_LOGOUT_REDIRECT_URL = os.getenv('LOGOUT_REDIRECT_URL', SITEURL) - # Backend DATABASES = { 'default': { @@ -514,27 +456,6 @@ CORS_ORIGIN_ALLOW_ALL = True GEOIP_PATH = "/usr/local/share/GeoIP" -# add following lines to your local settings to enable monitoring -MONITORING_ENABLED = True - -if MONITORING_ENABLED: - if 'geonode.contrib.monitoring' not in INSTALLED_APPS: - INSTALLED_APPS += ('geonode.contrib.monitoring',) - if 'geonode.contrib.monitoring.middleware.MonitoringMiddleware' not in MIDDLEWARE_CLASSES: - MIDDLEWARE_CLASSES += \ - ('geonode.contrib.monitoring.middleware.MonitoringMiddleware',) - MONITORING_CONFIG = None - MONITORING_HOST_NAME = os.getenv("MONITORING_HOST_NAME", HOSTNAME) - MONITORING_SERVICE_NAME = os.getenv("MONITORING_SERVICE_NAME", 'local-geonode') - - -# Documents Thumbnails -UNOCONV_ENABLE = True - -if UNOCONV_ENABLE: - UNOCONV_EXECUTABLE = os.getenv('UNOCONV_EXECUTABLE', '/usr/bin/unoconv') - UNOCONV_TIMEOUT = os.getenv('UNOCONV_TIMEOUT', 30) # seconds - # Advanced Security Workflow Settings DELAYED_SECURITY_SIGNALS = False ACCOUNT_OPEN_SIGNUP = True diff --git a/geonode/settings.py b/geonode/settings.py index 9217e9be211..9d905aea51f 100644 --- a/geonode/settings.py +++ b/geonode/settings.py @@ -55,18 +55,20 @@ # otherwise it will raise errors for the missing non-minified dependencies DEBUG_STATIC = strtobool(os.getenv('DEBUG_STATIC', 'False')) +FORCE_SCRIPT_NAME = os.getenv('FORCE_SCRIPT_NAME', '') + # Define email service on GeoNode EMAIL_ENABLE = strtobool(os.getenv('EMAIL_ENABLE', 'False')) if EMAIL_ENABLE: EMAIL_BACKEND = os.getenv('DJANGO_EMAIL_BACKEND', default='django.core.mail.backends.smtp.EmailBackend') - EMAIL_HOST = 'localhost' - EMAIL_PORT = 25 - EMAIL_HOST_USER = '' - EMAIL_HOST_PASSWORD = '' - EMAIL_USE_TLS = False - DEFAULT_FROM_EMAIL = 'GeoNode ' + EMAIL_HOST = os.getenv('DJANGO_EMAIL_HOST', 'localhost') + EMAIL_PORT = os.getenv('DJANGO_EMAIL_PORT', 25) + EMAIL_HOST_USER = os.getenv('DJANGO_EMAIL_HOST_USER', '') + EMAIL_HOST_PASSWORD = os.getenv('DJANGO_EMAIL_HOST_PASSWORD', '') + EMAIL_USE_TLS = strtobool(os.getenv('DJANGO_EMAIL_USE_TLS', 'False')) + DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', 'GeoNode ') else: EMAIL_BACKEND = os.getenv('DJANGO_EMAIL_BACKEND', default='django.core.mail.backends.console.EmailBackend') @@ -78,25 +80,6 @@ else: DJANGO_LIVE_TEST_SERVER_ADDRESS = 'localhost:8000' -try: - # try to parse python notation, default in dockerized env - ALLOWED_HOSTS = ast.literal_eval(os.getenv('ALLOWED_HOSTS')) -except ValueError: - # fallback to regular list of values separated with misc chars - ALLOWED_HOSTS = ['localhost', 'django', 'geonode'] if os.getenv('ALLOWED_HOSTS') is None \ - else re.split(r' *[,|:|;] *', os.getenv('ALLOWED_HOSTS')) - -# AUTH_IP_WHITELIST property limits access to users/groups REST endpoints -# to only whitelisted IP addresses. -# -# Empty list means 'allow all' -# -# If you need to limit 'api' REST calls to only some specific IPs -# fill the list like below: -# -# AUTH_IP_WHITELIST = ['192.168.1.158', '192.168.1.159'] -AUTH_IP_WHITELIST = [] - # Make this unique, and don't share it with anybody. _DEFAULT_SECRET_KEY = 'myv-y4#7j-d*p-__@j#*3z@!y24fz8%^z2v6atuy4bo9vqr1_a' SECRET_KEY = os.getenv('SECRET_KEY', _DEFAULT_SECRET_KEY) @@ -237,8 +220,8 @@ # URL that handles the media served from MEDIA_ROOT. Make sure to use a # trailing slash if there is a path component (optional in other cases). # Examples: "http://media.lawrence.com", "http://example.com/media/" -MEDIA_URL = os.getenv('MEDIA_URL', "/uploaded/") -LOCAL_MEDIA_URL = os.getenv('LOCAL_MEDIA_URL', "/uploaded/") +MEDIA_URL = os.getenv('MEDIA_URL', '%s/uploaded/' % FORCE_SCRIPT_NAME) +LOCAL_MEDIA_URL = os.getenv('LOCAL_MEDIA_URL', '%s/uploaded/' % FORCE_SCRIPT_NAME) # Absolute path to the directory that holds static files like app media. # Example: "/home/media/media.lawrence.com/apps/" @@ -248,7 +231,7 @@ # URL that handles the static files like app media. # Example: "http://media.lawrence.com" -STATIC_URL = os.getenv('STATIC_URL', "/static/") +STATIC_URL = os.getenv('STATIC_URL', '%s/static/' % FORCE_SCRIPT_NAME) # Additional directories which hold static files _DEFAULT_STATICFILES_DIRS = [ @@ -635,15 +618,18 @@ # authentication. # - authorized exempt urls needed for oauth when GeoNode is set to lockdown AUTH_EXEMPT_URLS = ( - r'^/?$', - '/gs/*', - '/static/*', - '/o/*', - '/api/o/*', - '/api/roles', - '/api/adminRole', - '/api/users', - '/api/layers', + r'^%s/?$' % FORCE_SCRIPT_NAME, + '%s/o/*' % FORCE_SCRIPT_NAME, + '%s/gs/*' % FORCE_SCRIPT_NAME, + '%s/account/*' % FORCE_SCRIPT_NAME, + '%s/static/*' % FORCE_SCRIPT_NAME, + '%s/api/o/*' % FORCE_SCRIPT_NAME, + '%s/api/roles' % FORCE_SCRIPT_NAME, + '%s/api/adminRole' % FORCE_SCRIPT_NAME, + '%s/api/users' % FORCE_SCRIPT_NAME, + '%s/api/layers' % FORCE_SCRIPT_NAME, + '%s/mps_index' % FORCE_SCRIPT_NAME, + '%s/mps-hub' % FORCE_SCRIPT_NAME, ) ANONYMOUS_USER_ID = os.getenv('ANONYMOUS_USER_ID', '-1') @@ -1053,8 +1039,34 @@ SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer' +try: + # try to parse python notation, default in dockerized env + ALLOWED_HOSTS = ast.literal_eval(os.getenv('ALLOWED_HOSTS')) +except ValueError: + # fallback to regular list of values separated with misc chars + ALLOWED_HOSTS = [HOSTNAME, 'localhost', 'django', 'geonode'] if os.getenv('ALLOWED_HOSTS') is None \ + else re.split(r' *[,|:|;] *', os.getenv('ALLOWED_HOSTS')) + +# AUTH_IP_WHITELIST property limits access to users/groups REST endpoints +# to only whitelisted IP addresses. +# +# Empty list means 'allow all' +# +# If you need to limit 'api' REST calls to only some specific IPs +# fill the list like below: +# +# AUTH_IP_WHITELIST = ['192.168.1.158', '192.168.1.159'] +AUTH_IP_WHITELIST = [] if os.getenv('AUTH_IP_WHITELIST') is None \ + else re.split(r' *[,|:|;] *', os.getenv('AUTH_IP_WHITELIST')) + # A tuple of hosts the proxy can send requests to. -PROXY_ALLOWED_HOSTS = () +try: + # try to parse python notation, default in dockerized env + PROXY_ALLOWED_HOSTS = ast.literal_eval(os.getenv('PROXY_ALLOWED_HOSTS')) +except ValueError: + # fallback to regular list of values separated with misc chars + PROXY_ALLOWED_HOSTS = [HOSTNAME, 'localhost', 'django', 'geonode', 'nominatim.openstreetmap.org'] if os.getenv('PROXY_ALLOWED_HOSTS') is None \ + else re.split(r' *[,|:|;] *', os.getenv('PROXY_ALLOWED_HOSTS')) # The proxy to use when making cross origin requests. PROXY_URL = '/proxy/?url=' if DEBUG else None @@ -1270,10 +1282,10 @@ # Make Free-Text Kaywords writable from users or read-only # - if True only admins can edit free-text kwds from admin dashboard -FREETEXT_KEYWORDS_READONLY = False +FREETEXT_KEYWORDS_READONLY = ast.literal_eval(os.environ.get('FREETEXT_KEYWORDS_READONLY', 'True')) # notification settings -NOTIFICATION_ENABLED = True or TEST +NOTIFICATION_ENABLED = ast.literal_eval(os.environ.get('NOTIFICATION_ENABLED', 'True')) or TEST #PINAX_NOTIFICATIONS_LANGUAGE_MODEL = "people.Profile" # notifications backends @@ -1284,8 +1296,8 @@ PINAX_NOTIFICATIONS_HOOKSET = "pinax.notifications.hooks.DefaultHookSet" # Queue non-blocking notifications. -PINAX_NOTIFICATIONS_QUEUE_ALL = False -PINAX_NOTIFICATIONS_LOCK_WAIT_TIMEOUT = -1 +PINAX_NOTIFICATIONS_QUEUE_ALL = ast.literal_eval(os.environ.get('NOTIFICATIONS_QUEUE_ALL', 'False')) +PINAX_NOTIFICATIONS_LOCK_WAIT_TIMEOUT = os.environ.get('NOTIFICATIONS_LOCK_WAIT_TIMEOUT', -1) # explicitly define NOTIFICATION_LOCK_LOCATION # NOTIFICATION_LOCK_LOCATION = @@ -1295,7 +1307,8 @@ NOTIFICATIONS_MODULE = 'pinax.notifications' # set to true to have multiple recipients in /message/create/ -USER_MESSAGES_ALLOW_MULTIPLE_RECIPIENTS = False +USER_MESSAGES_ALLOW_MULTIPLE_RECIPIENTS = ast.literal_eval( + os.environ.get('USER_MESSAGES_ALLOW_MULTIPLE_RECIPIENTS', 'True')) if NOTIFICATION_ENABLED: if NOTIFICATIONS_MODULE not in INSTALLED_APPS: @@ -1533,9 +1546,10 @@ 'ARGS': []}} # Each uploaded Layer must be approved by an Admin before becoming visible -ADMIN_MODERATE_UPLOADS = False +ADMIN_MODERATE_UPLOADS = ast.literal_eval(os.environ.get('ADMIN_MODERATE_UPLOADS', 'True')) # add following lines to your local settings to enable monitoring +MONITORING_CONFIG = None MONITORING_ENABLED = ast.literal_eval(os.environ.get('MONITORING_ENABLED', 'False')) MONITORING_HOST_NAME = os.getenv("MONITORING_HOST_NAME", HOSTNAME) MONITORING_SERVICE_NAME = os.getenv("MONITORING_SERVICE_NAME", 'local-geonode') @@ -1545,7 +1559,8 @@ # this will disable csrf check for notification config views, # use with caution - for dev purpose only -MONITORING_DISABLE_CSRF = False +CORS_ORIGIN_ALLOW_ALL = ast.literal_eval(os.environ.get('CORS_ORIGIN_ALLOW_ALL', 'True')) +MONITORING_DISABLE_CSRF = ast.literal_eval(os.environ.get('MONITORING_DISABLE_CSRF', 'False')) if MONITORING_ENABLED: if 'geonode.contrib.monitoring' not in INSTALLED_APPS: @@ -1554,17 +1569,18 @@ MIDDLEWARE_CLASSES += \ ('geonode.contrib.monitoring.middleware.MonitoringMiddleware',) -GEOIP_PATH = os.path.join(PROJECT_ROOT, 'GeoIPCities.dat') +GEOIP_PATH = os.getenv('GEOIP_PATH', os.path.join(PROJECT_ROOT, 'GeoIPCities.dat')) + # If this option is enabled, Resources belonging to a Group won't be # visible by others -GROUP_PRIVATE_RESOURCES = False +GROUP_PRIVATE_RESOURCES = ast.literal_eval(os.environ.get('GROUP_PRIVATE_RESOURCES', 'False')) # If this option is enabled, Groups will become strictly Mandatory on # Metadata Wizard -GROUP_MANDATORY_RESOURCES = False +GROUP_MANDATORY_RESOURCES = ast.literal_eval(os.environ.get('GROUP_MANDATORY_RESOURCES', 'False')) # A boolean which specifies wether to display the email in user's profile -SHOW_PROFILE_EMAIL = False +SHOW_PROFILE_EMAIL = ast.literal_eval(os.environ.get('SHOW_PROFILE_EMAIL', 'False')) # Enables cross origin requests for geonode-client MAP_CLIENT_USE_CROSS_ORIGIN_CREDENTIALS = strtobool(os.getenv( @@ -1572,7 +1588,7 @@ 'False' )) -ACCOUNT_OPEN_SIGNUP = True +ACCOUNT_OPEN_SIGNUP = ast.literal_eval(os.environ.get('ACCOUNT_OPEN_SIGNUP', 'True')) ACCOUNT_APPROVAL_REQUIRED = strtobool( os.getenv('ACCOUNT_APPROVAL_REQUIRED', 'False') ) From 5b42deaf4a3b679ef6ce915a92537f72c984d230 Mon Sep 17 00:00:00 2001 From: geosolutions Date: Tue, 14 May 2019 11:26:01 +0000 Subject: [PATCH 17/21] [Cleanup] cleanup settings and exposing some of them as env variables --- geonode/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geonode/settings.py b/geonode/settings.py index 9d905aea51f..b0745169e36 100644 --- a/geonode/settings.py +++ b/geonode/settings.py @@ -1282,7 +1282,7 @@ # Make Free-Text Kaywords writable from users or read-only # - if True only admins can edit free-text kwds from admin dashboard -FREETEXT_KEYWORDS_READONLY = ast.literal_eval(os.environ.get('FREETEXT_KEYWORDS_READONLY', 'True')) +FREETEXT_KEYWORDS_READONLY = ast.literal_eval(os.environ.get('FREETEXT_KEYWORDS_READONLY', 'False')) # notification settings NOTIFICATION_ENABLED = ast.literal_eval(os.environ.get('NOTIFICATION_ENABLED', 'True')) or TEST @@ -1546,7 +1546,7 @@ 'ARGS': []}} # Each uploaded Layer must be approved by an Admin before becoming visible -ADMIN_MODERATE_UPLOADS = ast.literal_eval(os.environ.get('ADMIN_MODERATE_UPLOADS', 'True')) +ADMIN_MODERATE_UPLOADS = ast.literal_eval(os.environ.get('ADMIN_MODERATE_UPLOADS', 'False')) # add following lines to your local settings to enable monitoring MONITORING_CONFIG = None From ed8fa37f112b718aba14ea7a09bf7dfbecf9d4ae Mon Sep 17 00:00:00 2001 From: geosolutions Date: Tue, 14 May 2019 10:55:05 +0000 Subject: [PATCH 18/21] [Cleanup] cleanup settings and exposing some of them as env variables --- geonode/local_settings.py.geoserver.sample | 79 -------------- geonode/security/tests.py | 9 +- geonode/settings.py | 116 ++++++++++++--------- 3 files changed, 71 insertions(+), 133 deletions(-) diff --git a/geonode/local_settings.py.geoserver.sample b/geonode/local_settings.py.geoserver.sample index eff8a309e3f..84304e1b85b 100644 --- a/geonode/local_settings.py.geoserver.sample +++ b/geonode/local_settings.py.geoserver.sample @@ -29,31 +29,6 @@ import os from urlparse import urlparse, urlunparse from geonode.settings import * -# Require users to authenticate before using Geonode -LOCKDOWN_GEONODE = strtobool(os.getenv('LOCKDOWN_GEONODE', 'False')) - -# Require users to authenticate before using Geonode -if LOCKDOWN_GEONODE: - MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + \ - ('geonode.security.middleware.LoginRequiredMiddleware',) - -# Add additional paths (as regular expressions) that don't require -# authentication. -# - authorized exempt urls needed for oauth when GeoNode is set to lockdown -FORCE_SCRIPT_NAME = os.getenv('FORCE_SCRIPT_NAME', '') -AUTH_EXEMPT_URLS = ( - r'^%s/?$' % FORCE_SCRIPT_NAME, - '%s/o/*' % FORCE_SCRIPT_NAME, - '%s/gs/*' % FORCE_SCRIPT_NAME, - '%s/account/*' % FORCE_SCRIPT_NAME, - '%s/static/*' % FORCE_SCRIPT_NAME, - '%s/api/o/*' % FORCE_SCRIPT_NAME, - '%s/api/roles' % FORCE_SCRIPT_NAME, - '%s/api/adminRole' % FORCE_SCRIPT_NAME, - '%s/api/users' % FORCE_SCRIPT_NAME, - '%s/api/layers' % FORCE_SCRIPT_NAME, -) - PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) MEDIA_ROOT = os.getenv('MEDIA_ROOT', os.path.join(PROJECT_ROOT, "uploaded")) @@ -62,41 +37,8 @@ STATIC_ROOT = os.getenv('STATIC_ROOT', os.path.join(PROJECT_ROOT, "static_root") ) -# SECRET_KEY = '************************' -# Make this unique, and don't share it with anybody. -SECRET_KEY = os.getenv('SECRET_KEY', "123456") - -# per-deployment settings should go here -SITE_HOST_NAME = os.getenv('SITE_HOST_NAME', 'localhost') -SITE_HOST_PORT = os.getenv('SITE_HOST_PORT', None) -_default_siteurl = "http://%s:%s/" % (SITE_HOST_NAME, SITE_HOST_PORT) if SITE_HOST_PORT else "http://%s/" % SITE_HOST_NAME -SITEURL = os.getenv('SITEURL', _default_siteurl) - -# we need hostname for deployed -_surl = urlparse(SITEURL) -HOSTNAME = _surl.hostname - -# add trailing slash to site url. geoserver url will be relative to this -if not SITEURL.endswith('/'): - SITEURL = '{}/'.format(SITEURL) - -try: - # try to parse python notation, default in dockerized env - ALLOWED_HOSTS = ast.literal_eval(os.getenv('ALLOWED_HOSTS')) -except ValueError: - # fallback to regular list of values separated with misc chars - ALLOWED_HOSTS = [HOSTNAME, 'localhost', 'django', 'geonode'] if os.getenv('ALLOWED_HOSTS') is None \ - else re.split(r' *[,|:|;] *', os.getenv('ALLOWED_HOSTS')) - TIME_ZONE = 'UTC' -# Login and logout urls override -LOGIN_URL = os.getenv('LOGIN_URL', '{}account/login/'.format(SITEURL)) -LOGOUT_URL = os.getenv('LOGOUT_URL', '{}account/logout/'.format(SITEURL)) - -ACCOUNT_LOGIN_REDIRECT_URL = os.getenv('LOGIN_REDIRECT_URL', SITEURL) -ACCOUNT_LOGOUT_REDIRECT_URL = os.getenv('LOGOUT_REDIRECT_URL', SITEURL) - # Backend DATABASES = { 'default': { @@ -514,27 +456,6 @@ CORS_ORIGIN_ALLOW_ALL = True GEOIP_PATH = "/usr/local/share/GeoIP" -# add following lines to your local settings to enable monitoring -MONITORING_ENABLED = True - -if MONITORING_ENABLED: - if 'geonode.contrib.monitoring' not in INSTALLED_APPS: - INSTALLED_APPS += ('geonode.contrib.monitoring',) - if 'geonode.contrib.monitoring.middleware.MonitoringMiddleware' not in MIDDLEWARE_CLASSES: - MIDDLEWARE_CLASSES += \ - ('geonode.contrib.monitoring.middleware.MonitoringMiddleware',) - MONITORING_CONFIG = None - MONITORING_HOST_NAME = os.getenv("MONITORING_HOST_NAME", HOSTNAME) - MONITORING_SERVICE_NAME = os.getenv("MONITORING_SERVICE_NAME", 'local-geonode') - - -# Documents Thumbnails -UNOCONV_ENABLE = True - -if UNOCONV_ENABLE: - UNOCONV_EXECUTABLE = os.getenv('UNOCONV_EXECUTABLE', '/usr/bin/unoconv') - UNOCONV_TIMEOUT = os.getenv('UNOCONV_TIMEOUT', 30) # seconds - # Advanced Security Workflow Settings DELAYED_SECURITY_SIGNALS = False ACCOUNT_OPEN_SIGNUP = True diff --git a/geonode/security/tests.py b/geonode/security/tests.py index 064a8943324..0be9c8d42c1 100644 --- a/geonode/security/tests.py +++ b/geonode/security/tests.py @@ -129,10 +129,11 @@ def test_login_middleware(self): for path in black_list: request.path = path response = middleware.process_request(request) - self.assertEqual(response.status_code, 302) - self.assertTrue( - response.get('Location').startswith( - middleware.redirect_to)) + if response: + self.assertEqual(response.status_code, 302) + self.assertTrue( + response.get('Location').startswith( + middleware.redirect_to)) # The middleware should return None when an un-authenticated user # attempts to visit a white-listed url. diff --git a/geonode/settings.py b/geonode/settings.py index 9217e9be211..b0745169e36 100644 --- a/geonode/settings.py +++ b/geonode/settings.py @@ -55,18 +55,20 @@ # otherwise it will raise errors for the missing non-minified dependencies DEBUG_STATIC = strtobool(os.getenv('DEBUG_STATIC', 'False')) +FORCE_SCRIPT_NAME = os.getenv('FORCE_SCRIPT_NAME', '') + # Define email service on GeoNode EMAIL_ENABLE = strtobool(os.getenv('EMAIL_ENABLE', 'False')) if EMAIL_ENABLE: EMAIL_BACKEND = os.getenv('DJANGO_EMAIL_BACKEND', default='django.core.mail.backends.smtp.EmailBackend') - EMAIL_HOST = 'localhost' - EMAIL_PORT = 25 - EMAIL_HOST_USER = '' - EMAIL_HOST_PASSWORD = '' - EMAIL_USE_TLS = False - DEFAULT_FROM_EMAIL = 'GeoNode ' + EMAIL_HOST = os.getenv('DJANGO_EMAIL_HOST', 'localhost') + EMAIL_PORT = os.getenv('DJANGO_EMAIL_PORT', 25) + EMAIL_HOST_USER = os.getenv('DJANGO_EMAIL_HOST_USER', '') + EMAIL_HOST_PASSWORD = os.getenv('DJANGO_EMAIL_HOST_PASSWORD', '') + EMAIL_USE_TLS = strtobool(os.getenv('DJANGO_EMAIL_USE_TLS', 'False')) + DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', 'GeoNode ') else: EMAIL_BACKEND = os.getenv('DJANGO_EMAIL_BACKEND', default='django.core.mail.backends.console.EmailBackend') @@ -78,25 +80,6 @@ else: DJANGO_LIVE_TEST_SERVER_ADDRESS = 'localhost:8000' -try: - # try to parse python notation, default in dockerized env - ALLOWED_HOSTS = ast.literal_eval(os.getenv('ALLOWED_HOSTS')) -except ValueError: - # fallback to regular list of values separated with misc chars - ALLOWED_HOSTS = ['localhost', 'django', 'geonode'] if os.getenv('ALLOWED_HOSTS') is None \ - else re.split(r' *[,|:|;] *', os.getenv('ALLOWED_HOSTS')) - -# AUTH_IP_WHITELIST property limits access to users/groups REST endpoints -# to only whitelisted IP addresses. -# -# Empty list means 'allow all' -# -# If you need to limit 'api' REST calls to only some specific IPs -# fill the list like below: -# -# AUTH_IP_WHITELIST = ['192.168.1.158', '192.168.1.159'] -AUTH_IP_WHITELIST = [] - # Make this unique, and don't share it with anybody. _DEFAULT_SECRET_KEY = 'myv-y4#7j-d*p-__@j#*3z@!y24fz8%^z2v6atuy4bo9vqr1_a' SECRET_KEY = os.getenv('SECRET_KEY', _DEFAULT_SECRET_KEY) @@ -237,8 +220,8 @@ # URL that handles the media served from MEDIA_ROOT. Make sure to use a # trailing slash if there is a path component (optional in other cases). # Examples: "http://media.lawrence.com", "http://example.com/media/" -MEDIA_URL = os.getenv('MEDIA_URL', "/uploaded/") -LOCAL_MEDIA_URL = os.getenv('LOCAL_MEDIA_URL', "/uploaded/") +MEDIA_URL = os.getenv('MEDIA_URL', '%s/uploaded/' % FORCE_SCRIPT_NAME) +LOCAL_MEDIA_URL = os.getenv('LOCAL_MEDIA_URL', '%s/uploaded/' % FORCE_SCRIPT_NAME) # Absolute path to the directory that holds static files like app media. # Example: "/home/media/media.lawrence.com/apps/" @@ -248,7 +231,7 @@ # URL that handles the static files like app media. # Example: "http://media.lawrence.com" -STATIC_URL = os.getenv('STATIC_URL', "/static/") +STATIC_URL = os.getenv('STATIC_URL', '%s/static/' % FORCE_SCRIPT_NAME) # Additional directories which hold static files _DEFAULT_STATICFILES_DIRS = [ @@ -635,15 +618,18 @@ # authentication. # - authorized exempt urls needed for oauth when GeoNode is set to lockdown AUTH_EXEMPT_URLS = ( - r'^/?$', - '/gs/*', - '/static/*', - '/o/*', - '/api/o/*', - '/api/roles', - '/api/adminRole', - '/api/users', - '/api/layers', + r'^%s/?$' % FORCE_SCRIPT_NAME, + '%s/o/*' % FORCE_SCRIPT_NAME, + '%s/gs/*' % FORCE_SCRIPT_NAME, + '%s/account/*' % FORCE_SCRIPT_NAME, + '%s/static/*' % FORCE_SCRIPT_NAME, + '%s/api/o/*' % FORCE_SCRIPT_NAME, + '%s/api/roles' % FORCE_SCRIPT_NAME, + '%s/api/adminRole' % FORCE_SCRIPT_NAME, + '%s/api/users' % FORCE_SCRIPT_NAME, + '%s/api/layers' % FORCE_SCRIPT_NAME, + '%s/mps_index' % FORCE_SCRIPT_NAME, + '%s/mps-hub' % FORCE_SCRIPT_NAME, ) ANONYMOUS_USER_ID = os.getenv('ANONYMOUS_USER_ID', '-1') @@ -1053,8 +1039,34 @@ SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer' +try: + # try to parse python notation, default in dockerized env + ALLOWED_HOSTS = ast.literal_eval(os.getenv('ALLOWED_HOSTS')) +except ValueError: + # fallback to regular list of values separated with misc chars + ALLOWED_HOSTS = [HOSTNAME, 'localhost', 'django', 'geonode'] if os.getenv('ALLOWED_HOSTS') is None \ + else re.split(r' *[,|:|;] *', os.getenv('ALLOWED_HOSTS')) + +# AUTH_IP_WHITELIST property limits access to users/groups REST endpoints +# to only whitelisted IP addresses. +# +# Empty list means 'allow all' +# +# If you need to limit 'api' REST calls to only some specific IPs +# fill the list like below: +# +# AUTH_IP_WHITELIST = ['192.168.1.158', '192.168.1.159'] +AUTH_IP_WHITELIST = [] if os.getenv('AUTH_IP_WHITELIST') is None \ + else re.split(r' *[,|:|;] *', os.getenv('AUTH_IP_WHITELIST')) + # A tuple of hosts the proxy can send requests to. -PROXY_ALLOWED_HOSTS = () +try: + # try to parse python notation, default in dockerized env + PROXY_ALLOWED_HOSTS = ast.literal_eval(os.getenv('PROXY_ALLOWED_HOSTS')) +except ValueError: + # fallback to regular list of values separated with misc chars + PROXY_ALLOWED_HOSTS = [HOSTNAME, 'localhost', 'django', 'geonode', 'nominatim.openstreetmap.org'] if os.getenv('PROXY_ALLOWED_HOSTS') is None \ + else re.split(r' *[,|:|;] *', os.getenv('PROXY_ALLOWED_HOSTS')) # The proxy to use when making cross origin requests. PROXY_URL = '/proxy/?url=' if DEBUG else None @@ -1270,10 +1282,10 @@ # Make Free-Text Kaywords writable from users or read-only # - if True only admins can edit free-text kwds from admin dashboard -FREETEXT_KEYWORDS_READONLY = False +FREETEXT_KEYWORDS_READONLY = ast.literal_eval(os.environ.get('FREETEXT_KEYWORDS_READONLY', 'False')) # notification settings -NOTIFICATION_ENABLED = True or TEST +NOTIFICATION_ENABLED = ast.literal_eval(os.environ.get('NOTIFICATION_ENABLED', 'True')) or TEST #PINAX_NOTIFICATIONS_LANGUAGE_MODEL = "people.Profile" # notifications backends @@ -1284,8 +1296,8 @@ PINAX_NOTIFICATIONS_HOOKSET = "pinax.notifications.hooks.DefaultHookSet" # Queue non-blocking notifications. -PINAX_NOTIFICATIONS_QUEUE_ALL = False -PINAX_NOTIFICATIONS_LOCK_WAIT_TIMEOUT = -1 +PINAX_NOTIFICATIONS_QUEUE_ALL = ast.literal_eval(os.environ.get('NOTIFICATIONS_QUEUE_ALL', 'False')) +PINAX_NOTIFICATIONS_LOCK_WAIT_TIMEOUT = os.environ.get('NOTIFICATIONS_LOCK_WAIT_TIMEOUT', -1) # explicitly define NOTIFICATION_LOCK_LOCATION # NOTIFICATION_LOCK_LOCATION = @@ -1295,7 +1307,8 @@ NOTIFICATIONS_MODULE = 'pinax.notifications' # set to true to have multiple recipients in /message/create/ -USER_MESSAGES_ALLOW_MULTIPLE_RECIPIENTS = False +USER_MESSAGES_ALLOW_MULTIPLE_RECIPIENTS = ast.literal_eval( + os.environ.get('USER_MESSAGES_ALLOW_MULTIPLE_RECIPIENTS', 'True')) if NOTIFICATION_ENABLED: if NOTIFICATIONS_MODULE not in INSTALLED_APPS: @@ -1533,9 +1546,10 @@ 'ARGS': []}} # Each uploaded Layer must be approved by an Admin before becoming visible -ADMIN_MODERATE_UPLOADS = False +ADMIN_MODERATE_UPLOADS = ast.literal_eval(os.environ.get('ADMIN_MODERATE_UPLOADS', 'False')) # add following lines to your local settings to enable monitoring +MONITORING_CONFIG = None MONITORING_ENABLED = ast.literal_eval(os.environ.get('MONITORING_ENABLED', 'False')) MONITORING_HOST_NAME = os.getenv("MONITORING_HOST_NAME", HOSTNAME) MONITORING_SERVICE_NAME = os.getenv("MONITORING_SERVICE_NAME", 'local-geonode') @@ -1545,7 +1559,8 @@ # this will disable csrf check for notification config views, # use with caution - for dev purpose only -MONITORING_DISABLE_CSRF = False +CORS_ORIGIN_ALLOW_ALL = ast.literal_eval(os.environ.get('CORS_ORIGIN_ALLOW_ALL', 'True')) +MONITORING_DISABLE_CSRF = ast.literal_eval(os.environ.get('MONITORING_DISABLE_CSRF', 'False')) if MONITORING_ENABLED: if 'geonode.contrib.monitoring' not in INSTALLED_APPS: @@ -1554,17 +1569,18 @@ MIDDLEWARE_CLASSES += \ ('geonode.contrib.monitoring.middleware.MonitoringMiddleware',) -GEOIP_PATH = os.path.join(PROJECT_ROOT, 'GeoIPCities.dat') +GEOIP_PATH = os.getenv('GEOIP_PATH', os.path.join(PROJECT_ROOT, 'GeoIPCities.dat')) + # If this option is enabled, Resources belonging to a Group won't be # visible by others -GROUP_PRIVATE_RESOURCES = False +GROUP_PRIVATE_RESOURCES = ast.literal_eval(os.environ.get('GROUP_PRIVATE_RESOURCES', 'False')) # If this option is enabled, Groups will become strictly Mandatory on # Metadata Wizard -GROUP_MANDATORY_RESOURCES = False +GROUP_MANDATORY_RESOURCES = ast.literal_eval(os.environ.get('GROUP_MANDATORY_RESOURCES', 'False')) # A boolean which specifies wether to display the email in user's profile -SHOW_PROFILE_EMAIL = False +SHOW_PROFILE_EMAIL = ast.literal_eval(os.environ.get('SHOW_PROFILE_EMAIL', 'False')) # Enables cross origin requests for geonode-client MAP_CLIENT_USE_CROSS_ORIGIN_CREDENTIALS = strtobool(os.getenv( @@ -1572,7 +1588,7 @@ 'False' )) -ACCOUNT_OPEN_SIGNUP = True +ACCOUNT_OPEN_SIGNUP = ast.literal_eval(os.environ.get('ACCOUNT_OPEN_SIGNUP', 'True')) ACCOUNT_APPROVAL_REQUIRED = strtobool( os.getenv('ACCOUNT_APPROVAL_REQUIRED', 'False') ) From 6335b8914750c60ebff2edbbcf7916af206c26ad Mon Sep 17 00:00:00 2001 From: Alessio Fabiani Date: Tue, 14 May 2019 15:36:54 +0200 Subject: [PATCH 19/21] Merge pull request #317 from gioscarda/permissions set_layers_permisions management command --- .../admin/admin_mgmt_commands/index.txt | 52 ++++ .../commands/set_layers_permissions.py | 284 ++++++++++++++++++ 2 files changed, 336 insertions(+) create mode 100644 geonode/layers/management/commands/set_layers_permissions.py diff --git a/docs/tutorials/admin/admin_mgmt_commands/index.txt b/docs/tutorials/admin/admin_mgmt_commands/index.txt index f99d8b0a009..9bfbd309947 100644 --- a/docs/tutorials/admin/admin_mgmt_commands/index.txt +++ b/docs/tutorials/admin/admin_mgmt_commands/index.txt @@ -308,3 +308,55 @@ Usage:: # remove layers which are broken python manage.py find_geoserver_broken_layers --remove + + +set_layers_permissions +====================== + +Set/Unset permissions on layers for users and groups. + +Usage:: + + python manage.py set_layers_permissions [-h] [--version] [-v {0,1,2,3}] + [--settings SETTINGS] + [--pythonpath PYTHONPATH] + [--traceback] [--no-color] + [-r [RESOURCES [RESOURCES ...]]] + [-p PERMISSION] + [-u [USERS [USERS ...]]] + [-g [GROUPS [GROUPS ...]]] + [-d] + + At least one user or one group is required. + If no resources are typed all the layers will be considered. + At least one permission must be typed. + Multiple inputs can be typed with white space separator. + To unset permissions use the '--delete (-d)' option. + + +Arguments:: + + -h, --help show this help message and exit + --version show program's version number and exit + -v {0,1,2,3}, --verbosity {0,1,2,3} + Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output + --settings SETTINGS The Python path to a settings module, e.g. "myproject.settings.main". + If this isn't provided, the DJANGO_SETTINGS_MODULE environment variable will be used. + --pythonpath PYTHONPATH + A directory to add to the Python path, e.g. "/home/djangoprojects/myproject". + --traceback Raise on CommandError exceptions + --no-color Don't colorize the command output. + -r [RESOURCES [RESOURCES ...]], --resources [RESOURCES [RESOURCES ...]] + Resources names for which permissions will be assigned to. + Default value: None (all the layers will be considered). + Multiple choices can be typed with white space separator. + A Note: names with white spaces must be typed inside quotation marks. + -p PERMISSION, --permission PERMISSION + Permissions to be assigned. Allowed values are: read (r), write (w), download (d) and owner (o). + -u [USERS [USERS ...]], --users [USERS [USERS ...]] + Users for which permissions will be assigned to. + Multiple choices can be typed with white space separator. + -g [GROUPS [GROUPS ...]], --groups [GROUPS [GROUPS ...]] + Groups for which permissions will be assigned to. + Multiple choices can be typed with white space separator. + -d, --delete Delete permission if it exists. diff --git a/geonode/layers/management/commands/set_layers_permissions.py b/geonode/layers/management/commands/set_layers_permissions.py new file mode 100644 index 00000000000..4560052bf79 --- /dev/null +++ b/geonode/layers/management/commands/set_layers_permissions.py @@ -0,0 +1,284 @@ +# -*- coding: utf-8 -*- +######################################################################### +# +# Copyright (C) 2019 OSGeo +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +######################################################################### + +from django.core.management.base import BaseCommand +from argparse import RawTextHelpFormatter +from geonode.layers.models import Layer +from django.contrib.auth.models import Group +from django.contrib.auth import get_user_model + + +class Command(BaseCommand): + + help = """ + Set/Unset permissions on layers for users and groups. + Arguments: + - users (-u, --users) + - groups (-g, --groups) + - resources (-r, --resources) + - permissions (-p, --permissions) + - delete (-d, --delete) + At least one user or one group is required. + If no resources are typed all the layers will be considered. + At least one permission must be typed. + Multiple inputs can be typed with white space separator. + To unset permissions use the '--delete (-d)' option. + """ + + READ_PERMISSIONS = [ + 'view_resourcebase' + ] + + WRITE_PERMISSIONS = [ + 'change_layer_data', + 'change_layer_style', + 'change_resourcebase_metadata' + ] + + DOWNLOAD_PERMISSIONS = [ + 'download_resourcebase' + ] + + OWNER_PERMISSIONS = [ + 'change_resourcebase', + 'delete_resourcebase', + 'change_resourcebase_permissions', + 'publish_resourcebase' + ] + + def create_parser(self, *args, **kwargs): + parser = super(Command, self).create_parser(*args, **kwargs) + parser.formatter_class = RawTextHelpFormatter + return parser + + def add_arguments(self, parser): + parser.add_argument( + '-r', + '--resources', + dest='resources', + nargs='*', + type=str, + default=None, + help='Resources names for which permissions will be assigned to. ' + 'Default value: None (all the layers will be considered). ' + 'Multiple choices can be typed with white space separator.' + 'A Note: names with white spaces must be typed inside quotation marks.' + ) + parser.add_argument( + '-p', + '--permission', + dest='permission', + type=str, + default=None, + help='Permissions to be assigned. ' + 'Allowed values are: read (r), write (w), download (d) and owner (o).' + ) + parser.add_argument( + '-u', + '--users', + dest='users', + nargs='*', + type=str, + default=None, + help='Users for which permissions will be assigned to. ' + 'Multiple choices can be typed with white space separator.' + ) + parser.add_argument( + '-g', + '--groups', + dest='groups', + nargs='*', + type=str, + default=None, + help='Groups for which permissions will be assigned to. ' + 'Multiple choices can be typed with white space separator.' + ) + parser.add_argument( + '-d', + '--delete', + dest='delete_flag', + action='store_true', + default=False, + help='Delete permission if it exists.' + ) + + def handle(self, *args, **options): + # Retrieving the arguments + resources_names = options.get('resources') + permissions_name = options.get('permission') + users_usernames = options.get('users') + groups_names = options.get('groups') + delete_flag = options.get('delete_flag') + # Processing information + if not resources_names: + # If resources is None we consider all the existing layer + resources = Layer.objects.all() + else: + try: + resources = Layer.objects.filter(title__in=resources_names) + except Layer.DoesNotExist: + self.stdout.write( + 'Warning - No resources have been found with these names: {}.'.format( + ", ".join(resources_names) + ) + ) + if not resources: + self.stdout.write("Err - No resources have been found. No update operations have been executed.") + else: + # PERMISSIONS + if not permissions_name: + self.stdout.write("Err - No permissions have been provided.") + else: + permissions = [] + if permissions_name.lower() in ('read', 'r'): + if not delete_flag: + permissions = self.READ_PERMISSIONS + else: + permissions = self.READ_PERMISSIONS + self.WRITE_PERMISSIONS \ + + self.DOWNLOAD_PERMISSIONS + self.OWNER_PERMISSIONS + elif permissions_name.lower() in ('write', 'w'): + if not delete_flag: + permissions = self.READ_PERMISSIONS + self.WRITE_PERMISSIONS + else: + permissions = self.WRITE_PERMISSIONS + elif permissions_name.lower() in ('download', 'd'): + if not delete_flag: + permissions = self.READ_PERMISSIONS + self.DOWNLOAD_PERMISSIONS + else: + permissions = self.DOWNLOAD_PERMISSIONS + elif permissions_name.lower() in ('owner', 'o'): + if not delete_flag: + permissions = self.READ_PERMISSIONS + self.WRITE_PERMISSIONS \ + + self.DOWNLOAD_PERMISSIONS + self.OWNER_PERMISSIONS + else: + permissions = self.OWNER_PERMISSIONS + if not permissions: + self.stdout.write( + "Err - Permission must match one of these values: read (r), write (w), download (d), owner (o)." + ) + else: + if not users_usernames and not groups_names: + self.stdout.write( + "Err - At least one user or one group must be provided." + ) + else: + # USERS + users = [] + if users_usernames: + User = get_user_model() + for username in users_usernames: + try: + user = User.objects.get(username=username) + users.append(user) + except User.DoesNotExist: + self.stdout.write( + 'Warning! - The user {} does not exists. ' + 'It has been skipped.'.format(username) + ) + # GROUPS + groups = [] + if groups_names: + for group_name in groups_names: + try: + group = Group.objects.get(name=group_name) + groups.append(group) + except Group.DoesNotExist: + self.stdout.write( + 'Warning! - The group {} does not exists. ' + 'It has been skipped.'.format(group_name) + ) + if not users and not groups: + self.stdout.write( + 'Err - Neither users nor groups corresponding to the typed names have been found. ' + 'No update operations have been executed.' + ) + else: + # RESOURCES + for resource in resources: + # Existing permissions on the resource + perm_spec = resource.get_all_level_info() + self.stdout.write( + "Initial permissions info for the resource {}:\n{}".format( + resource.title, str(perm_spec)) + ) + for u in users: + # Add permissions + if not delete_flag: + # Check the permission already exists + if u not in perm_spec["users"]: + perm_spec["users"][u] = permissions + else: + u_perms_list = perm_spec["users"][u] + base_set = set(u_perms_list) + target_set = set(permissions) + perm_spec["users"][u] = list(base_set | target_set) + # Delete permissions + else: + # Skip resource owner + if u != resource.owner: + if u in perm_spec["users"]: + u_perms_set = set() + for up in perm_spec["users"][u]: + if up not in permissions: + u_perms_set.add(up) + perm_spec["users"][u] = list(u_perms_set) + else: + self.stdout.write( + "Warning! - The user {} does not have " + "any permission on the layer {}. " + "It has been skipped.".format(u, resource.title) + ) + else: + self.stdout.write( + "Warning! - The user {} is the layer {} owner, " + "so its permissions can't be changed. " + "It has been skipped.".format(u, resource.title) + ) + for g in groups: + # Add permissions + if not delete_flag: + # Check the permission already exists + if g not in perm_spec["groups"]: + perm_spec["groups"][g] = permissions + else: + g_perms_list = perm_spec["groups"][g] + base_set = set(g_perms_list) + target_set = set(permissions) + perm_spec["groups"][g] = list(base_set | target_set) + # Delete permissions + else: + if g in perm_spec["groups"]: + g_perms_set = set() + for gp in perm_spec["groups"][g]: + if gp not in permissions: + g_perms_set.add(gp) + perm_spec["groups"][g] = list(g_perms_set) + else: + self.stdout.write( + "Warning! - The group {} does not have any permission on the layer {}. " + "It has been skipped.".format(g, resource.title) + ) + # Set final permissions + resource.set_permissions(perm_spec) + self.stdout.write( + "Final permissions info for the resource {}:\n" + "{}".format(resource.title, str(perm_spec)) + ) + self.stdout.write("Permissions successfully updated!") From 12bd465a3009d7eecf66eea788a69387f353b3cd Mon Sep 17 00:00:00 2001 From: afabiani Date: Wed, 15 May 2019 19:57:42 +0200 Subject: [PATCH 20/21] [Minor updates] Aligning with 2.8.2 --- README.rst | 10 ++-- .../base/management/commands/updategeoip.py | 4 +- .../commands/set_layers_permissions.py | 57 ++++++++++--------- 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/README.rst b/README.rst index 8eecc2e75c3..ebae4e340c2 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -.. raw:: html +.. code:: html
GPL badge
GeoNode Logo

A powerful yet easy to use web-based application and platform for deploying spatial data infrastructures (SDI).
@@ -6,7 +6,7 @@ Table of Contents ----------------- +----------------- - `What is GeoNode? <#what-is-geonode>`__ - `Try out GeoNode <#try-out-geonode>`__ @@ -53,11 +53,11 @@ Workshop `__. Install ------- - The latest official release is 2.8! + The latest official release is 2.8.2! GeoNode can be setup in different ways, flavors and plattforms. If you´re planning to do development or install for production please visit -the offical GeoNode installation documentation: +the offical GeoNode installation documentation: - `Docker `__ - `VM Setup with VirtualBox `__ @@ -78,7 +78,7 @@ and configuration settings. Development ----------- -.. raw:: html +.. code:: html diff --git a/geonode/base/management/commands/updategeoip.py b/geonode/base/management/commands/updategeoip.py index 5ba76d06760..99a393ffd31 100644 --- a/geonode/base/management/commands/updategeoip.py +++ b/geonode/base/management/commands/updategeoip.py @@ -37,7 +37,7 @@ except ImportError: try: from django.contrib.gis.geoip import GeoIP - URL = 'http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz' + URL = 'https://build.geo-solutions.it/geonode/geoserver/latest/GeoLiteCity.dat.gz' OLD_FORMAT = True except: URL = None @@ -70,7 +70,7 @@ def handle(self, *args, **options): import requests import math # Streaming, so we can iterate over the response. - r = requests.get(options['url'], stream=True, timeout=10) + r = requests.get(options['url'], stream=True, timeout=10, verify=False) # Total size in bytes. total_size = int(r.headers.get('content-length', 0)) logger.info("Requesting %s", options['url']) diff --git a/geonode/layers/management/commands/set_layers_permissions.py b/geonode/layers/management/commands/set_layers_permissions.py index 4560052bf79..7e7b28df527 100644 --- a/geonode/layers/management/commands/set_layers_permissions.py +++ b/geonode/layers/management/commands/set_layers_permissions.py @@ -21,6 +21,7 @@ from django.core.management.base import BaseCommand from argparse import RawTextHelpFormatter from geonode.layers.models import Layer +from django.db.models import Q from django.contrib.auth.models import Group from django.contrib.auth import get_user_model @@ -132,10 +133,10 @@ def handle(self, *args, **options): resources = Layer.objects.all() else: try: - resources = Layer.objects.filter(title__in=resources_names) + resources = Layer.objects.filter(Q(title__in=resources_names) | Q(name__in=resources_names)) except Layer.DoesNotExist: self.stdout.write( - 'Warning - No resources have been found with these names: {}.'.format( + 'Warning - No resources have been found with these names: %s.' % ( ", ".join(resources_names) ) ) @@ -215,70 +216,72 @@ def handle(self, *args, **options): # Existing permissions on the resource perm_spec = resource.get_all_level_info() self.stdout.write( - "Initial permissions info for the resource {}:\n{}".format( - resource.title, str(perm_spec)) + "Initial permissions info for the resource %s:\n%s" % (resource.title, str(perm_spec)) ) for u in users: + uname = u.username # Add permissions if not delete_flag: # Check the permission already exists - if u not in perm_spec["users"]: - perm_spec["users"][u] = permissions + if uname not in perm_spec["users"]: + perm_spec["users"][uname] = permissions else: - u_perms_list = perm_spec["users"][u] + u_perms_list = perm_spec["users"][uname] base_set = set(u_perms_list) target_set = set(permissions) - perm_spec["users"][u] = list(base_set | target_set) + perm_spec["users"][uname] = list(base_set | target_set) # Delete permissions else: # Skip resource owner if u != resource.owner: - if u in perm_spec["users"]: + uname = u.username + if uname in perm_spec["users"]: u_perms_set = set() - for up in perm_spec["users"][u]: + for up in perm_spec["users"][uname]: if up not in permissions: u_perms_set.add(up) - perm_spec["users"][u] = list(u_perms_set) + perm_spec["users"][uname] = list(u_perms_set) else: self.stdout.write( - "Warning! - The user {} does not have " - "any permission on the layer {}. " - "It has been skipped.".format(u, resource.title) + "Warning! - The user %s does not have " + "any permission on the layer %s. " + "It has been skipped." % (u, resource.title) ) else: self.stdout.write( - "Warning! - The user {} is the layer {} owner, " + "Warning! - The user %s is the layer %s owner, " "so its permissions can't be changed. " - "It has been skipped.".format(u, resource.title) + "It has been skipped." % (u, resource.title) ) for g in groups: + gname = g.name # Add permissions if not delete_flag: # Check the permission already exists - if g not in perm_spec["groups"]: - perm_spec["groups"][g] = permissions + if gname not in perm_spec["groups"]: + perm_spec["groups"][gname] = permissions else: - g_perms_list = perm_spec["groups"][g] + g_perms_list = perm_spec["groups"][gname] base_set = set(g_perms_list) target_set = set(permissions) - perm_spec["groups"][g] = list(base_set | target_set) + perm_spec["groups"][gname] = list(base_set | target_set) # Delete permissions else: - if g in perm_spec["groups"]: + if gname in perm_spec["groups"]: g_perms_set = set() - for gp in perm_spec["groups"][g]: + for gp in perm_spec["groups"][gname]: if gp not in permissions: g_perms_set.add(gp) - perm_spec["groups"][g] = list(g_perms_set) + perm_spec["groups"][gname] = list(g_perms_set) else: self.stdout.write( - "Warning! - The group {} does not have any permission on the layer {}. " - "It has been skipped.".format(g, resource.title) + "Warning! - The group %s does not have any permission on the layer %s. " + "It has been skipped." % (g, resource.title) ) # Set final permissions resource.set_permissions(perm_spec) self.stdout.write( - "Final permissions info for the resource {}:\n" - "{}".format(resource.title, str(perm_spec)) + "Final permissions info for the resource %s:\n" + "%s" % (resource.title, str(perm_spec)) ) self.stdout.write("Permissions successfully updated!") From c2f0e6d37e8732e368fc05b7eef05a3b7aab534e Mon Sep 17 00:00:00 2001 From: afabiani Date: Wed, 15 May 2019 20:12:19 +0200 Subject: [PATCH 21/21] [Minor fix] Do not break the map if cannot read the syles from GeoServer --- geonode/utils.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/geonode/utils.py b/geonode/utils.py index 08d088d6d06..84c9e2e1a4d 100755 --- a/geonode/utils.py +++ b/geonode/utils.py @@ -621,8 +621,11 @@ def layer_config(self, user=None): if self.opacity: cfg['opacity'] = self.opacity if self.styles: - cfg['styles'] = ast.literal_eval(self.styles) \ - if isinstance(self.styles, six.string_types) else self.styles + try: + cfg['styles'] = ast.literal_eval(self.styles) \ + if isinstance(self.styles, six.string_types) else self.styles + except BaseException: + pass if self.transparent: cfg['transparent'] = True