Change usage of whitelist/blacklist to allowlist/blocklist, attempt

backwards compatibility.
This commit is contained in:
Nate Coraor
2020-06-11 09:59:34 -04:00
parent 5b9b1d2637
commit 06bded296b
39 changed files with 281 additions and 262 deletions
@@ -109,9 +109,9 @@ const AdminPanel = Backbone.View.extend({
target: "__use_router__",
},
{
title: _l("Manage Whitelist"),
url: "admin/sanitize_whitelist",
id: "admin-link-whitelist",
title: _l("Manage Allowlist"),
url: "admin/sanitize_allowlist",
id: "admin-link-allowlist",
},
{
title: _l("Manage Dependencies"),
+2 -2
View File
@@ -220,7 +220,7 @@ define({
"Reload a tool's configuration": "Recharger une configuration d'outils",
"Review tool migration stages": "Vérifier les étapes de migration d'outils",
"View Tool Error Logs": "Voir les logs d'erreur d'outils",
"Manage Display Whitelist": "Gérer la liste blanche d'outils graphiques",
"Manage Allowlist": "Gérer la liste blanche d'outils graphiques",
"Manage Tool Dependencies": "Gérer les dépendances d'outils",
Users: false,
Groups: false,
@@ -373,7 +373,7 @@ define({
"View migration stages": false,
"View lineage": false,
"Manage dependencies": false,
"Manage whitelist": false,
"Manage allowlist": false,
"Manage metadata": false,
"Manage tools": false,
"Monitor installation": false,
+1 -1
View File
@@ -253,7 +253,7 @@ define({
"Reload a tool's configuration": "ツールのコンフィグのリロード",
"Review tool migration stages": "ツール移行ステージのレビュー",
"View Tool Error Logs": "ツールのエラーログ",
"Manage Display Whitelist": "表示ホワイトリストの管理",
"Manage Allowlist": "表示ホワイトリストの管理",
"Manage Tool Dependencies": "ツール依存関係の管理",
Users: "ユーザー",
Groups: "グループ",
+2 -2
View File
@@ -220,7 +220,7 @@ define({
"Reload a tool's configuration": false,
"Review tool migration stages": false,
"View Tool Error Logs": false,
"Manage Display Whitelist": false,
"Manage Allowlist": false,
"Manage Tool Dependencies": false,
Users: false,
Groups: false,
@@ -373,7 +373,7 @@ define({
"View migration stages": false,
"View lineage": false,
"Manage dependencies": false,
"Manage whitelist": false,
"Manage allowlist": false,
"Manage metadata": false,
"Manage tools": false,
"Monitor installation": false,
+1 -1
View File
@@ -217,7 +217,7 @@ define({
"Reload a tool's configuration": "重新加载工具的配置",
"Review tool migration stages": "查看工具迁移状态",
"View Tool Error Logs": "查看工具错误日志",
"Manage Display Whitelist": "管理显示白名单",
"Manage Allowlist": "管理显示白名单",
"Manage Tool Dependencies": "管理工具依赖",
Users: "用户",
Groups: "组别",
@@ -1 +0,0 @@
../lib/galaxy/config/sample/disposable_email_blacklist.conf.sample
+1
View File
@@ -0,0 +1 @@
../lib/galaxy/config/sample/disposable_email_blocklist.conf.sample
+22 -22
View File
@@ -1254,35 +1254,35 @@
:Type: str
~~~~~~~~~~~~~~~~~~
``blacklist_file``
~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``email_domain_blocklist_file``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:Description:
E-mail domains blacklist is used for filtering out users that are
E-mail domains blocklist is used for filtering out users that are
using disposable email addresses at registration. If their
address domain matches any domain on the list, they are refused
registration.
Example value 'email_blacklist.conf'
Example value 'email_blocklist.conf'
The value of this option will be resolved with respect to
<config_dir>.
:Default: ``None``
:Type: str
~~~~~~~~~~~~~~~~~~
``whitelist_file``
~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``email_domain_allowlist_file``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:Description:
E-mail domains whitelist is used to specify allowed email address
E-mail domains allowlist is used to specify allowed email address
domains. If the list is non-empty and a user attempts registration
using an email address belonging to a domain that is not on the
list, registration will be denied. This is a more restrictive
option than <blacklist_file>, and therefore, in case
<whitelist_file> is set and is not empty, <blacklist_file> will be
ignored.
Example value 'email_whitelist.conf'
option than <email_domain_blocklist_file>, and therefore, in case
<email_domain_allowlist_file> is set and is not empty,
<email_domain_blocklist_file> will be ignored.
Example value 'email_allowlist.conf'
The value of this option will be resolved with respect to
<config_dir>.
:Default: ``None``
@@ -2231,17 +2231,17 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~
``sanitize_whitelist_file``
``sanitize_allowlist_file``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
:Description:
Whitelist sanitization file. Datasets created by tools listed in
this file are trusted and will not have their HTML sanitized on
display. This can be manually edited or manipulated through the
Admin control panel -- see "Manage Display Whitelist"
Datasets created by tools listed in this file are trusted and will
not have their HTML sanitized on display. This can be manually
edited or manipulated through the Admin control panel -- see
"Manage Display Allowlist"
The value of this option will be resolved with respect to
<mutable_config_dir>.
:Default: ``sanitize_whitelist.txt``
:Default: ``sanitize_allowlist.txt``
:Type: str
@@ -2512,7 +2512,7 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``user_library_import_symlink_whitelist``
``user_library_import_symlink_allowlist``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:Description:
@@ -2976,11 +2976,11 @@
~~~~~~~~~~~~~~~~~~~~~~~
``fetch_url_whitelist``
``fetch_url_allowlist``
~~~~~~~~~~~~~~~~~~~~~~~
:Description:
Whitelist for local network addresses for "Upload from URL"
List of allowed local network addresses for "Upload from URL"
dialog. By default, Galaxy will deny access to the local network
address space, to prevent users making requests to services which
the administrator did not intend to expose. Previously, you could
+2 -2
View File
@@ -45,8 +45,8 @@ def validate_server_directory_upload(trans, server_dir):
unsafe = None
if safe_relpath(server_dir):
username = trans.user.username if trans.app.config.user_library_import_check_permissions else None
if import_dir_desc == 'user_library_import_dir' and safe_contains(import_dir, full_dir, whitelist=trans.app.config.user_library_import_symlink_whitelist):
for unsafe in unsafe_walk(full_dir, whitelist=[import_dir] + trans.app.config.user_library_import_symlink_whitelist, username=username):
if import_dir_desc == 'user_library_import_dir' and safe_contains(import_dir, full_dir, allowlist=trans.app.config.user_library_import_symlink_allowlist):
for unsafe in unsafe_walk(full_dir, allowlist=[import_dir] + trans.app.config.user_library_import_symlink_allowlist, username=username):
log.error('User attempted to import a path that resolves to a path outside of their import dir: %s -> %s', unsafe, os.path.realpath(unsafe))
else:
log.error('User attempted to import a directory path that resolves to a path outside of their import dir: %s -> %s', server_dir, os.path.realpath(full_dir))
+1 -1
View File
@@ -81,7 +81,7 @@ class UniverseApplication(config.ConfiguresGalaxyMixin):
# A lot of postfork initialization depends on the server name, ensure it is set immediately after forking before other postfork functions
self.application_stack = application_stack_instance(app=self)
self.application_stack.register_postfork_function(self.application_stack.set_postfork_server_name, self)
self.config.reload_sanitize_whitelist(explicit='sanitize_whitelist_file' in kwargs)
self.config.reload_sanitize_allowlist(explicit='sanitize_allowlist_file' in kwargs)
self.amqp_internal_connection_obj = galaxy.queues.connection_from_config(self.config)
# queue_worker *can* be initialized with a queue, but here we don't
# want to and we'll allow postfork to bind and start it.
+1 -1
View File
@@ -46,7 +46,7 @@ AUTH_PIPELINE = (
'social_core.pipeline.social_auth.social_uid',
# Verifies that the current auth process is valid within the current
# project, this is where emails and domains whitelists are applied (if
# project, this is where emails and domains allowlists are applied (if
# defined).
'social_core.pipeline.social_auth.auth_allowed',
+39 -20
View File
@@ -110,6 +110,7 @@ def find_root(kwargs):
class BaseAppConfiguration(object):
# Override in subclasses (optional): {KEY: config option, VALUE: deprecated directory name}
# If VALUE == first directory in a user-supplied path that resolves to KEY, it will be stripped from that path
renamed_options = None
deprecated_dirs = None
def __init__(self, **kwargs):
@@ -313,6 +314,13 @@ class BaseAppConfiguration(object):
setattr(self, var + '_set', False)
setattr(self, var, [root_join(x) for x in paths])
# update kwargs to set unset renamed options
if self.renamed_options is not None:
for old, new in self.renamed_options.items():
if new not in config_kwargs and old in config_kwargs:
# don't pop so that if the old option is deprecated, that can be logged
config_kwargs[new] = config_kwargs[old]
class CommonConfigurationMixin(object):
"""Shared configuration settings code for Galaxy and ToolShed."""
@@ -362,7 +370,15 @@ class CommonConfigurationMixin(object):
class GalaxyAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
deprecated_options = ('database_file', 'track_jobs_in_database')
deprecated_options = ('database_file', 'track_jobs_in_database', 'blacklist_file', 'whitelist_file',
'sanitize_whitelist_file', 'user_library_import_symlink_whitelist', 'fetch_url_whitelist')
renamed_options = {
'blacklist_file': 'email_domain_blocklist_file',
'whitelist_file': 'email_domain_allowlist_file',
'sanitize_whitelist_file': 'sanitize_allowlist_file',
'user_library_import_symlink_whitelist': 'user_library_import_symlink_allowlist',
'fetch_url_whitelist': 'fetch_url_allowlist',
}
default_config_file_name = 'galaxy.yml'
deprecated_dirs = {'config_dir': 'config', 'data_dir': 'database'}
@@ -461,11 +477,11 @@ class GalaxyAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
self.tool_secret = kwargs.get("tool_secret", "")
self.metadata_strategy = kwargs.get("metadata_strategy", "directory")
self.use_remote_user = self.use_remote_user or self.single_user
self.fetch_url_whitelist_ips = [
self.fetch_url_allowlist_ips = [
ipaddress.ip_network(unicodify(ip.strip())) # If it has a slash, assume 127.0.0.1/24 notation
if '/' in ip else
ipaddress.ip_address(unicodify(ip.strip())) # Otherwise interpret it as an ip address.
for ip in kwargs.get("fetch_url_whitelist", "").split(',')
for ip in kwargs.get("fetch_url_allowlist", "").split(',')
if len(ip.strip()) > 0
]
self.template_path = self._in_root_dir(kwargs.get("template_path", "templates"))
@@ -488,8 +504,8 @@ class GalaxyAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
activation_email = kwargs.get('activation_email')
self.email_from = self.email_from or activation_email
self.blacklist_content = self._load_list_from_file(self._in_config_dir(self.blacklist_file)) if self.blacklist_file else None
self.whitelist_content = self._load_list_from_file(self._in_config_dir(self.whitelist_file)) if self.whitelist_file else None
self.email_domain_blocklist_content = self._load_list_from_file(self._in_config_dir(self.email_domain_blocklist_file)) if self.email_domain_blocklist_file else None
self.email_domain_allowlist_content = self._load_list_from_file(self._in_config_dir(self.email_domain_allowlist_file)) if self.email_domain_allowlist_file else None
self.persistent_communication_rooms = listify(self.persistent_communication_rooms, do_strip=True)
# The transfer manager and deferred job queue
@@ -507,15 +523,18 @@ class GalaxyAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
self.pbs_dataset_path = kwargs.get('pbs_dataset_path', "")
self.pbs_stage_path = kwargs.get('pbs_stage_path', "")
_sanitize_whitelist_path = self._in_managed_config_dir(self.sanitize_whitelist_file)
if not os.path.isfile(_sanitize_whitelist_path): # then check old default location
deprecated = self._in_root_dir('config/sanitize_whitelist.txt')
if os.path.isfile(deprecated):
log.warning("The path '%s' for the 'sanitize_whitelist_file' config option is "
"deprecated and will be no longer checked in a future release. Please consult "
"the latest version of the sample configuration file." % deprecated)
_sanitize_whitelist_path = deprecated
self.sanitize_whitelist_file = _sanitize_whitelist_path
_sanitize_allowlist_path = self._in_managed_config_dir(self.sanitize_allowlist_file)
if not os.path.isfile(_sanitize_allowlist_path): # then check old default location
for deprecated in (
self._in_managed_config_dir('sanitize_whitelist.txt'),
self._in_root_dir('config/sanitize_whitelist.txt')):
if os.path.isfile(deprecated):
log.warning("The path '%s' for the 'sanitize_allowlist_file' config option is "
"deprecated and will be no longer checked in a future release. Please consult "
"the latest version of the sample configuration file." % deprecated)
_sanitize_allowlist_path = deprecated
break
self.sanitize_allowlist_file = _sanitize_allowlist_path
self.allowed_origin_hostnames = self._parse_allowed_origin_hostnames(kwargs)
if "trust_jupyter_notebook_conversion" not in kwargs:
@@ -524,7 +543,7 @@ class GalaxyAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
self.trust_jupyter_notebook_conversion = string_as_bool(kwargs.get('trust_ipython_notebook_conversion', _default))
# Configuration for the message box directly below the masthead.
self.blog_url = kwargs.get('blog_url')
self.user_library_import_symlink_whitelist = listify(self.user_library_import_symlink_whitelist, do_strip=True)
self.user_library_import_symlink_allowlist = listify(self.user_library_import_symlink_allowlist, do_strip=True)
self.user_library_import_dir_auto_creation = self.user_library_import_dir_auto_creation if self.user_library_import_dir else False
# Searching data libraries
self.ftp_upload_dir_template = kwargs.get('ftp_upload_dir_template', '${ftp_upload_dir}%s${ftp_upload_dir_identifier}' % os.path.sep)
@@ -798,16 +817,16 @@ class GalaxyAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
self.datatypes_config = self.datatypes_config_file
self.tool_configs = self.tool_config_file
def reload_sanitize_whitelist(self, explicit=True):
self.sanitize_whitelist = []
def reload_sanitize_allowlist(self, explicit=True):
self.sanitize_allowlist = []
try:
with open(self.sanitize_whitelist_file, 'rt') as f:
with open(self.sanitize_allowlist_file, 'rt') as f:
for line in f.readlines():
if not line.startswith("#"):
self.sanitize_whitelist.append(line.strip())
self.sanitize_allowlist.append(line.strip())
except IOError:
if explicit:
log.warning("Sanitize log file explicitly specified as '%s' but does not exist, continuing with no tools whitelisted.", self.sanitize_whitelist_file)
log.warning("Sanitize log file explicitly specified as '%s' but does not exist, continuing with no tools allowlisted.", self.sanitize_allowlist_file)
def ensure_tempdir(self):
self._ensure_directory(self.new_file_path)
@@ -1,9 +1,9 @@
If you want to disable registration for users that are using disposable email address
rename this file to disposable_email_blacklist.conf and fill it with the disposable domains
that you want to have blacklisted. Each on its own line without the '@' character as shown below.
rename this file to disposable_email_blocklist.conf and fill it with the disposable domains
that you want to have denied. Each on its own line without the '@' character as shown below.
Users using emails from these domains will get an error during the registration.
mailinator.com
sogetthis.com
spamgourmet.com
trashmail.net
trashmail.net
+20 -19
View File
@@ -699,25 +699,26 @@ galaxy:
# Example value 'https://galaxyproject.org/'
#instance_resource_url: null
# E-mail domains blacklist is used for filtering out users that are
# E-mail domains blocklist is used for filtering out users that are
# using disposable email addresses at registration. If their address
# domain matches any domain on the list, they are refused
# registration.
# Example value 'email_blacklist.conf'
# Example value 'email_blocklist.conf'
# The value of this option will be resolved with respect to
# <config_dir>.
#blacklist_file: null
#email_domain_blocklist_file: null
# E-mail domains whitelist is used to specify allowed email address
# E-mail domains allowlist is used to specify allowed email address
# domains. If the list is non-empty and a user attempts registration
# using an email address belonging to a domain that is not on the
# list, registration will be denied. This is a more restrictive option
# than <blacklist_file>, and therefore, in case <whitelist_file> is
# set and is not empty, <blacklist_file> will be ignored.
# Example value 'email_whitelist.conf'
# than <email_domain_blocklist_file>, and therefore, in case
# <email_domain_allowlist_file> is set and is not empty,
# <email_domain_blocklist_file> will be ignored.
# Example value 'email_allowlist.conf'
# The value of this option will be resolved with respect to
# <config_dir>.
#whitelist_file: null
#email_domain_allowlist_file: null
# Registration warning message is used to discourage people from
# registering multiple accounts. Applies mostly for the main Galaxy
@@ -1119,13 +1120,13 @@ galaxy:
# attacks initiated by your users.
#sanitize_all_html: true
# Whitelist sanitization file. Datasets created by tools listed in
# this file are trusted and will not have their HTML sanitized on
# display. This can be manually edited or manipulated through the
# Admin control panel -- see "Manage Display Whitelist"
# Datasets created by tools listed in this file are trusted and will
# not have their HTML sanitized on display. This can be manually
# edited or manipulated through the Admin control panel -- see "Manage
# Display Allowlist"
# The value of this option will be resolved with respect to
# <mutable_config_dir>.
#sanitize_whitelist_file: sanitize_whitelist.txt
#sanitize_allowlist_file: sanitize_allowlist.txt
# By default Galaxy will serve non-HTML tool output that may
# potentially contain browser executable JavaScript content as plain
@@ -1260,7 +1261,7 @@ galaxy:
# user with library import permissions can import from anywhere in
# these directories (assuming they are able to create symlinks to
# them).
#user_library_import_symlink_whitelist: null
#user_library_import_symlink_allowlist: null
# In conjunction or alternatively, Galaxy can restrict user library
# imports to those files that the user can read (by checking basic
@@ -1469,15 +1470,15 @@ galaxy:
# overridden and set to false.
#expose_user_email: false
# Whitelist for local network addresses for "Upload from URL" dialog.
# By default, Galaxy will deny access to the local network address
# space, to prevent users making requests to services which the
# administrator did not intend to expose. Previously, you could
# List of allowed local network addresses for "Upload from URL"
# dialog. By default, Galaxy will deny access to the local network
# address space, to prevent users making requests to services which
# the administrator did not intend to expose. Previously, you could
# request any network service that Galaxy might have had access to,
# even if the user could not normally access it. It should be a
# comma-separated list of IP addresses or IP address/mask, e.g.
# 10.10.10.10,10.0.1.0/24,fd00::/8
#fetch_url_whitelist: null
#fetch_url_allowlist: null
# Enables GDPR Compliance mode. This makes several changes to the way
# Galaxy logs and exposes data externally such as removing emails and
+11 -10
View File
@@ -340,19 +340,20 @@ tool_shed:
# intercept upload requests.
#nginx_upload_path: null
# E-mail domains blacklist is used for filtering out users that are
# using disposable email address during the registration. If their
# address domain matches any domain in the blacklist, they are refused
# the registration.
#blacklist_file: config/disposable_email_blacklist.conf
# E-mail domains blocklist is used for filtering out users that are
# using disposable email addresses at registration. If their address
# domain matches any domain on the list, they are refused
# registration.
#email_domain_blocklist_file: null
# E-mail domains whitelist is used to specify allowed email address
# E-mail domains allowlist is used to specify allowed email address
# domains. If the list is non-empty and a user attempts registration
# using an email address belonging to a domain that is not on the
# list, registration will be enied. This is a more restrictive option
# than <blacklist_file>, and therefore, in case <whitelist_file> is
# defined, <blacklist_file> will be ignored.
#whitelist_file: disposable_email_whitelist.conf
# list, registration will be denied. This is a more restrictive option
# than <email_domain_blocklist_file>, and therefore, in case
# <email_domain_allowlist_file> is set and is not empty,
# <email_domain_blocklist_file> will be ignored.
#email_domain_allowlist_file: null
# Append "/{brand}" to the "Galaxy" text in the masthead.
#brand: null
+2 -2
View File
@@ -496,9 +496,9 @@ class Data(object):
"""This method is responsible for sanitizing the HTML if needed."""
if trans.app.config.sanitize_all_html and trans.response.get_content_type() == "text/html":
# Sanitize anytime we respond with plain text/html content.
# Check to see if this dataset's parent job is whitelisted
# Check to see if this dataset's parent job is allowlisted
# We cannot currently trust imported datasets for rendering.
if not from_dataset.creating_job.imported and from_dataset.creating_job.tool_id in trans.app.config.sanitize_whitelist:
if not from_dataset.creating_job.imported and from_dataset.creating_job.tool_id in trans.app.config.sanitize_allowlist:
return open(filename, mode='rb')
# This is returning to the browser, it needs to be encoded.
@@ -4,7 +4,7 @@ from ast import (
walk,
)
AST_NODE_TYPE_WHITELIST = [
AST_NODE_TYPE_ALLOWLIST = [
'Expr', 'Load', 'Str', 'Num', 'BoolOp', 'Compare', 'And', 'Eq', 'NotEq',
'Or', 'GtE', 'LtE', 'Lt', 'Gt', 'BinOp', 'Add', 'Div', 'Sub', 'Mult', 'Mod',
'Pow', 'LShift', 'GShift', 'BitAnd', 'BitOr', 'BitXor', 'UnaryOp', 'Invert',
@@ -104,7 +104,7 @@ def _check_expression(text, allowed_variables=None):
# Toss out everything that is not a "simple" expression,
# imports, error handling, etc...
if ast_node_class not in AST_NODE_TYPE_WHITELIST:
if ast_node_class not in AST_NODE_TYPE_ALLOWLIST:
return False
# White-list more potentially dangerous types AST elements.
+4 -4
View File
@@ -914,7 +914,7 @@ class ModelFilterParser(HasAModelManager):
self.date_string_re = re.compile(r'^(\d{4}\-\d{2}\-\d{2})[T| ]{0,1}(\d{2}:\d{2}:\d{2}(?:\.\d{1,6}){0,1}){0,1}Z{0,1}$')
# dictionary containing parsing data for ORM/SQLAlchemy-based filters
# ..note: although kind of a pain in the ass and verbose, opt-in/whitelisting allows more control
# ..note: although kind of a pain in the ass and verbose, opt-in/allowlisting allows more control
# over potentially expensive queries
self.orm_filter_parsers = {}
@@ -1013,11 +1013,11 @@ class ModelFilterParser(HasAModelManager):
# orm_filter_list is a dict: orm_filter_list[ attr ] = <list of allowed ops>
column_map = self.orm_filter_parsers.get(attr, None)
if not column_map:
# no column mapping (not whitelisted)
# no column mapping (not allowlisted)
return None
if callable(column_map):
return self.parsed_filter(filter_type="orm_function", filter=column_map(attr, op, val))
# attr must be a whitelisted column by attr name or by key passed in column_map
# attr must be an allowlisted column by attr name or by key passed in column_map
# note: column_map[ 'column' ] takes precedence
if 'column' in column_map:
attr = column_map['column']
@@ -1029,7 +1029,7 @@ class ModelFilterParser(HasAModelManager):
# no orm column
return None
# op must be whitelisted: contained in the list orm_filter_list[ attr ][ 'op' ]
# op must be allowlisted: contained in the list orm_filter_list[ attr ][ 'op' ]
allowed_ops = column_map.get('op')
if op not in allowed_ops:
return None
+4 -4
View File
@@ -219,9 +219,9 @@ def reload_display_application(app, **kwargs):
app.datatypes_registry.reload_display_applications(display_application_ids)
def reload_sanitize_whitelist(app):
log.debug("Executing reload sanitize whitelist control task.")
app.config.reload_sanitize_whitelist()
def reload_sanitize_allowlist(app):
log.debug("Executing reload sanitize allowlist control task.")
app.config.reload_sanitize_allowlist()
def recalculate_user_disk_usage(app, **kwargs):
@@ -320,7 +320,7 @@ control_message_to_task = {
'reload_tool_data_tables': reload_tool_data_tables,
'reload_job_rules': reload_job_rules,
'admin_job_lock': admin_job_lock,
'reload_sanitize_whitelist': reload_sanitize_whitelist,
'reload_sanitize_allowlist': reload_sanitize_allowlist,
'recalculate_user_disk_usage': recalculate_user_disk_usage,
'rebuild_toolbox_search_index': rebuild_toolbox_search_index,
'reconfigure_watcher': reconfigure_watcher,
+7 -7
View File
@@ -55,7 +55,7 @@ def validate_publicname_str(publicname):
def validate_email(trans, email, user=None, check_dup=True, allow_empty=False):
"""
Validates the email format, also checks whether the domain is blacklisted in the disposable domains configuration.
Validates the email format, also checks whether the domain is blocklisted in the disposable domains configuration.
"""
if (user and user.email == email) or (email == "" and allow_empty):
return ''
@@ -64,19 +64,19 @@ def validate_email(trans, email, user=None, check_dup=True, allow_empty=False):
pass
elif check_dup and trans.sa_session.query(trans.app.model.User).filter(func.lower(trans.app.model.User.table.c.email) == email.lower()).first():
message = "User with email '%s' already exists." % email
# If the whitelist is not empty filter out any domain not in the list and ignore blacklist.
elif trans.app.config.whitelist_content is not None:
# If the allowlist is not empty filter out any domain not in the list and ignore blocklist.
elif trans.app.config.email_domain_allowlist_content is not None:
domain = email.split('@')[1]
if len(domain.split('.')) > 2:
domain = ('.').join(domain.split('.')[-2:])
if domain not in trans.app.config.whitelist_content:
if domain not in trans.app.config.email_domain_allowlist_content:
message = "Please enter an allowed domain email address for this server."
# If the blacklist is not empty filter out the disposable domains.
elif trans.app.config.blacklist_content is not None:
# If the blocklist is not empty filter out the disposable domains.
elif trans.app.config.email_domain_blocklist_content is not None:
domain = email.split('@')[1]
if len(domain.split('.')) > 2:
domain = ('.').join(domain.split('.')[-2:])
if domain in trans.app.config.blacklist_content:
if domain in trans.app.config.email_domain_blocklist_content:
message = "Please enter your permanent email address."
return message
+1 -1
View File
@@ -397,7 +397,7 @@ admin:
groups: '#admin-link-groups'
roles: '#admin-link-roles'
impersonate: '#admin-link-impersonate'
whitelist: '#admin-link-whitelist'
allowlist: '#admin-link-allowlist'
selectors:
# TODO: place betters IDS or something on this in these grids in the DOM
+15 -15
View File
@@ -67,25 +67,25 @@ def get_conda_envs(filepath):
return [n.split('__')[-1].replace('@', ':') for n in glob('%s/*' % filepath)]
def get_missing_containers(quay_list, singularity_list, blacklist_file=None):
def get_missing_containers(quay_list, singularity_list, blocklist_file=None):
r"""
Return list of quay containers that do not exist as singularity containers. Files stored in a blacklist will be ignored
Return list of quay containers that do not exist as singularity containers. Files stored in a blocklist will be ignored
"""
blacklist = []
if blacklist_file:
blacklist = open(blacklist_file).read().split('\n')
return [n for n in quay_list if n not in singularity_list and n not in blacklist]
blocklist = []
if blocklist_file:
blocklist = open(blocklist_file).read().split('\n')
return [n for n in quay_list if n not in singularity_list and n not in blocklist]
def get_missing_envs(quay_list, conda_list, blacklist_file=None):
def get_missing_envs(quay_list, conda_list, blocklist_file=None):
r"""
Compares list of conda envs and docker containers and returns missing conda envs
"""
blacklist = []
if blacklist_file:
blacklist = open(blacklist_file).read().split('\n')
blocklist = []
if blocklist_file:
blocklist = open(blocklist_file).read().split('\n')
return [n for n in quay_list if n.split('--')[0] not in conda_list and n.split('--')[0] not in blacklist]
return [n for n in quay_list if n.split('--')[0] not in conda_list and n.split('--')[0] not in blocklist]
def main():
@@ -99,8 +99,8 @@ def main():
help="Exclude Docker containers from which Conda environments have already been extracted.")
parser.add_argument('--conda-filepath', dest='conda_filepath', default=None,
help="If searching for conda environments or employing the --not-conda option, a filepath where the environments are located.")
parser.add_argument('-b', '--blacklist', dest='blacklist', default=None,
help="Provide a 'blacklist file' containing containers which should be excluded from the list.")
parser.add_argument('-b', '--blocklist', '--blacklist', dest='blocklist', default=None,
help="Provide a 'blocklist file' containing containers which should be excluded from the list.")
parser.add_argument('-f', '--file', dest='output', default=None,
help="File to write list to. If not given output will be returned on the command line.")
@@ -110,10 +110,10 @@ def main():
containers = get_quay_containers()
if args.not_singularity:
containers = get_missing_containers(
containers, get_singularity_containers(), args.blacklist)
containers, get_singularity_containers(), args.blocklist)
if args.not_conda:
containers = get_missing_envs(containers, get_conda_envs(
args.conda_filepath), args.blacklist)
args.conda_filepath), args.blocklist)
elif args.source == 'singularity':
containers = get_singularity_containers()
elif args.source == 'conda':
+8 -8
View File
@@ -32,7 +32,7 @@ def validate_datatype_extension(datatypes_registry, ext):
raise RequestParameterInvalidException("Requested extension '%s' unknown, cannot upload dataset." % ext)
def validate_url(url, ip_whitelist):
def validate_url(url, ip_allowlist):
# If it doesn't look like a URL, ignore it.
if not (url.lstrip().startswith('http://') or url.lstrip().startswith('https://')):
return url
@@ -94,17 +94,17 @@ def validate_url(url, ip_whitelist):
# If this is a private address
if ip.is_private:
results = []
# If this IP is not anywhere in the whitelist
for whitelisted in ip_whitelist:
# If this IP is not anywhere in the allowlist
for allowlisted in ip_allowlist:
# If it's an IP address range (rather than a single one...)
if hasattr(whitelisted, 'subnets'):
results.append(ip in whitelisted)
if hasattr(allowlisted, 'subnets'):
results.append(ip in allowlisted)
else:
results.append(ip == whitelisted)
results.append(ip == allowlisted)
if any(results):
# If we had any True, then THIS (and ONLY THIS) IP address that
# that specific DNS entry resolved to is in whitelisted and
# that specific DNS entry resolved to is in allowlisted and
# safe to access. But we cannot exit here, we must ensure that
# all IPs that that DNS entry resolves to are likewise safe.
pass
@@ -133,7 +133,7 @@ def persist_uploads(params, trans):
raise Exception('Uploaded file was encoded in a way not understood by Galaxy.')
if 'url_paste' in upload_dataset and upload_dataset['url_paste'] and upload_dataset['url_paste'].strip() != '':
upload_dataset['url_paste'] = datatypes.sniff.stream_to_file(
StringIO(validate_url(upload_dataset['url_paste'], trans.app.config.fetch_url_whitelist_ips)),
StringIO(validate_url(upload_dataset['url_paste'], trans.app.config.fetch_url_allowlist_ips)),
prefix="strio_url_paste_"
)
else:
+35 -35
View File
@@ -47,49 +47,49 @@ WALK_MAX_DIRS = 10000
log = logging.getLogger(__name__)
def safe_path(path, whitelist=None):
"""Ensure that a the absolute location of the path (after following symlinks) is either itself or on the whitelist
def safe_path(path, allowlist=None):
"""Ensure that a the absolute location of the path (after following symlinks) is either itself or on the allowlist
of acceptable locations.
This function does not perform an existence check, thus, if the path does not exist, ``True`` is returned.
:type path: string
:param path: a path to check
:type whitelist: comma separated list of strings
:param whitelist: list of acceptable locations
:return: ``True`` if ``path`` resolves to itself or a whitelisted location
:type allowlist: comma separated list of strings
:param allowlist: list of acceptable locations
:return: ``True`` if ``path`` resolves to itself or a allowlisted location
"""
return any(__contains(dirname(path), path, whitelist=whitelist))
return any(__contains(dirname(path), path, allowlist=allowlist))
def safe_contains(prefix, path, whitelist=None, real=None):
def safe_contains(prefix, path, allowlist=None, real=None):
"""Ensure a path is contained within another path.
Given any two filesystem paths, ensure that ``path`` is contained in ``prefix``. If ``path`` exists (either as an
absolute path or relative to ``prefix``), it is canonicalized with :func:`os.path.realpath` to ensure it is not a
symbolic link that points outside of ``prefix``. If it is a symbolic link and ``whitelist`` is set, the symbolic link
may also point inside a ``whitelist`` path.
symbolic link that points outside of ``prefix``. If it is a symbolic link and ``allowlist`` is set, the symbolic link
may also point inside a ``allowlist`` path.
The ``path`` is checked against ``whitelist`` using either its absolute pathname (if passed in as absolute) or
relative to ``prefix`` and canonicalized (if applicable). It is *not* ``os.path.join()``ed with each ``whitelist``
The ``path`` is checked against ``allowlist`` using either its absolute pathname (if passed in as absolute) or
relative to ``prefix`` and canonicalized (if applicable). It is *not* ``os.path.join()``ed with each ``allowlist``
directory.
:type prefix: string
:param prefix: a directory under which ``path`` is to be checked
:type path: string
:param path: a filename to check
:type whitelist: list of strings
:param whitelist: list of additional paths under which ``path`` may be located
:type allowlist: list of strings
:param allowlist: list of additional paths under which ``path`` may be located
:rtype: bool
:returns: ``True`` if ``path`` is contained within ``prefix`` or ``whitelist``, ``False`` otherwise.
:returns: ``True`` if ``path`` is contained within ``prefix`` or ``allowlist``, ``False`` otherwise.
"""
return any(__contains(prefix, path, whitelist=whitelist, real=real))
return any(__contains(prefix, path, allowlist=allowlist, real=real))
class _SafeContainsDirectoryChecker(object):
def __init__(self, dirpath, prefix, whitelist=None):
self.whitelist = whitelist
def __init__(self, dirpath, prefix, allowlist=None):
self.allowlist = allowlist
self.dirpath = dirpath
self.prefix = prefix
self.real_dirpath = realpath(join(prefix, dirpath))
@@ -97,9 +97,9 @@ class _SafeContainsDirectoryChecker(object):
def check(self, filename):
dirpath_path = join(self.real_dirpath, filename)
if islink(dirpath_path):
return safe_contains(self.prefix, filename, whitelist=self.whitelist)
return safe_contains(self.prefix, filename, allowlist=self.allowlist)
else:
return safe_contains(self.prefix, filename, whitelist=self.whitelist, real=dirpath_path)
return safe_contains(self.prefix, filename, allowlist=self.allowlist, real=dirpath_path)
def safe_makedirs(path):
@@ -133,24 +133,24 @@ def safe_relpath(path):
return not (isabs(path) or normpath(path).startswith(pardir))
def safe_walk(path, whitelist=None):
def safe_walk(path, allowlist=None):
"""Walk a path and return only the contents that are not symlinks outside the path.
Symbolic links are followed if a whitelist is provided. The path itself cannot be a symbolic link unless the pointed
to location is in the whitelist.
Symbolic links are followed if a allowlist is provided. The path itself cannot be a symbolic link unless the pointed
to location is in the allowlist.
:type path: string
:param path: a directory to check for unsafe contents
:type whitelist: list of strings
:param whitelist: list of additional paths under which contents may be located
:type allowlist: list of strings
:param allowlist: list of additional paths under which contents may be located
:rtype: iterator
:returns: Iterator of "safe" ``os.walk()`` tuples found under ``path``
"""
for i, elems in enumerate(walk(path, followlinks=bool(whitelist)), start=1):
for i, elems in enumerate(walk(path, followlinks=bool(allowlist)), start=1):
dirpath, dirnames, filenames = elems
_check = _SafeContainsDirectoryChecker(dirpath, path, whitelist=None).check
_check = _SafeContainsDirectoryChecker(dirpath, path, allowlist=None).check
if whitelist and i % WALK_MAX_DIRS == 0:
if allowlist and i % WALK_MAX_DIRS == 0:
raise RuntimeError(
'Breaking out of walk of %s after %s iterations (most likely infinite symlink recursion) at: %s' %
(path, WALK_MAX_DIRS, dirpath))
@@ -175,7 +175,7 @@ def safe_walk(path, whitelist=None):
yield (dirpath, dirnames, filenames)
def unsafe_walk(path, whitelist=None, username=None):
def unsafe_walk(path, allowlist=None, username=None):
"""Walk a path and ensure that none of its contents are symlinks outside the path.
It is assumed that ``path`` itself has already been validated e.g. with :func:`safe_relpath` or
@@ -184,14 +184,14 @@ def unsafe_walk(path, whitelist=None, username=None):
:type path: string
:param path: a directory to check for unsafe contents
:type whitelist: list of strings
:param whitelist: list of additional paths under which contents may be located
:type allowlist: list of strings
:param allowlist: list of additional paths under which contents may be located
:rtype: list of strings
:returns: A list of "bad" files found under ``path``
"""
unsafe_paths = []
for walked_path in __walk(abspath(path)):
is_safe = safe_contains(path, walked_path, whitelist=whitelist)
is_safe = safe_contains(path, walked_path, allowlist=allowlist)
if username and is_safe:
is_safe = full_path_permission_for_user(path, walked_path, username=username, skip_prefix=True)
if not is_safe:
@@ -365,12 +365,12 @@ def __walk(path):
yield join(dirpath, name)
def __contains(prefix, path, whitelist=None, real=None):
def __contains(prefix, path, allowlist=None, real=None):
real = real or realpath(join(prefix, path))
yield not relpath(real, prefix).startswith(pardir)
for wldir in whitelist or []:
# a path is under the whitelist if the relative path between it and the whitelist does not have to go up (..)
yield not relpath(real, wldir).startswith(pardir)
for aldir in allowlist or []:
# a path is under the allowlist if the relative path between it and the allowlist does not have to go up (..)
yield not relpath(real, aldir).startswith(pardir)
def __ext_strip_sep(ext):
@@ -169,7 +169,7 @@ class RemoteUser(object):
)
if not path_info.startswith('/user'):
# shortcut the following whitelist for non-user-controller
# shortcut the following allowlist for non-user-controller
# requests.
pass
elif environ[self.remote_user_header] in self.admin_users and \
+1 -1
View File
@@ -165,7 +165,7 @@ def validate_and_normalize_targets(trans, payload):
if not looks_like_url:
raise RequestParameterInvalidException("Invalid URL [%s] found in src definition." % url)
validate_url(url, trans.app.config.fetch_url_whitelist_ips)
validate_url(url, trans.app.config.fetch_url_allowlist_ips)
item["in_place"] = run_as_real_user
elif src == "files":
item["in_place"] = run_as_real_user
@@ -428,7 +428,7 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin, Libra
raise exceptions.ConfigDoesNotAllowException('The configuration of this Galaxy instance does not allow upload from user directories.')
full_dir = os.path.join(user_base_dir, user_login)
if not safe_contains(full_dir, path, whitelist=trans.app.config.user_library_import_symlink_whitelist):
if not safe_contains(full_dir, path, allowlist=trans.app.config.user_library_import_symlink_allowlist):
# the path is a symlink outside the user dir
path = os.path.join(full_dir, path)
log.error('User attempted to import a path that resolves to a path outside of their import dir: %s -> %s', path, os.path.realpath(path))
@@ -438,7 +438,7 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin, Libra
'%s -> %s and cannot be read by them.', path, os.path.realpath(path))
raise exceptions.RequestParameterInvalidException('The given path is invalid.')
path = os.path.join(full_dir, path)
for unsafe in unsafe_walk(path, whitelist=[full_dir] + trans.app.config.user_library_import_symlink_whitelist, username=username):
for unsafe in unsafe_walk(path, allowlist=[full_dir] + trans.app.config.user_library_import_symlink_allowlist, username=username):
# the path is a dir and contains files that symlink outside the user dir
error = 'User attempted to import a path that resolves to a path outside of their import dir: %s -> %s', \
path, os.path.realpath(path)
+17 -17
View File
@@ -57,7 +57,7 @@ class RemoteFilesAPIController(BaseAPIController):
if format == 'jstree':
disable = kwd.get('disable', 'folders')
try:
userdir_jstree = self.__create_jstree(full_import_dir, disable, whitelist=trans.app.config.user_library_import_symlink_whitelist)
userdir_jstree = self.__create_jstree(full_import_dir, disable, allowlist=trans.app.config.user_library_import_symlink_allowlist)
response = userdir_jstree.jsonData()
except Exception as e:
log.debug(unicodify(e))
@@ -68,7 +68,7 @@ class RemoteFilesAPIController(BaseAPIController):
raise exceptions.NotImplemented('Not implemented yet. Sorry.')
else:
try:
response = self.__load_all_filenames(full_import_dir, whitelist=trans.app.config.user_library_import_symlink_whitelist)
response = self.__load_all_filenames(full_import_dir, allowlist=trans.app.config.user_library_import_symlink_allowlist)
except Exception:
log.exception('Could not get user import files')
raise exceptions.InternalServerError('Could not get the files from your user directory folder.')
@@ -81,7 +81,7 @@ class RemoteFilesAPIController(BaseAPIController):
if format == 'jstree':
disable = kwd.get('disable', 'folders')
try:
importdir_jstree = self.__create_jstree(base_dir, disable, whitelist=trans.app.config.user_library_import_symlink_whitelist)
importdir_jstree = self.__create_jstree(base_dir, disable, allowlist=trans.app.config.user_library_import_symlink_allowlist)
response = importdir_jstree.jsonData()
except Exception as e:
log.debug(unicodify(e))
@@ -90,7 +90,7 @@ class RemoteFilesAPIController(BaseAPIController):
raise exceptions.NotImplemented('Not implemented yet. Sorry.')
else:
try:
response = self.__load_all_filenames(base_dir, trans.app.config.user_library_import_symlink_whitelist)
response = self.__load_all_filenames(base_dir, trans.app.config.user_library_import_symlink_allowlist)
except Exception:
log.exception('Could not get user import files')
raise exceptions.InternalServerError('Could not get the files from your import directory folder.')
@@ -101,7 +101,7 @@ class RemoteFilesAPIController(BaseAPIController):
try:
user_ftp_dir = trans.user_ftp_dir
if user_ftp_dir is not None:
response = self.__load_all_filenames(user_ftp_dir, trans.app.config.user_library_import_symlink_whitelist)
response = self.__load_all_filenames(user_ftp_dir, trans.app.config.user_library_import_symlink_allowlist)
else:
log.warning('You do not have an FTP directory named as your login at this Galaxy instance.')
return None
@@ -110,14 +110,14 @@ class RemoteFilesAPIController(BaseAPIController):
return None
return response
def __load_all_filenames(self, directory, whitelist=None):
def __load_all_filenames(self, directory, allowlist=None):
"""
Loads recursively all files within the given folder and its
subfolders and returns a flat list.
"""
response = []
if self.__safe_directory(directory, whitelist=whitelist):
for (dirpath, dirnames, filenames) in safe_walk(directory, whitelist=whitelist):
if self.__safe_directory(directory, allowlist=allowlist):
for (dirpath, dirnames, filenames) in safe_walk(directory, allowlist=allowlist):
for filename in filenames:
path = os.path.relpath(os.path.join(dirpath, filename), directory)
statinfo = os.lstat(os.path.join(dirpath, filename))
@@ -131,15 +131,15 @@ class RemoteFilesAPIController(BaseAPIController):
response = sorted(response, key=itemgetter("path"))
return response
def __create_jstree(self, directory, disable='folders', whitelist=None):
def __create_jstree(self, directory, disable='folders', allowlist=None):
"""
Loads recursively all files and folders within the given folder
and its subfolders and returns jstree representation
of its structure.
"""
jstree_paths = []
if self.__safe_directory(directory, whitelist=whitelist):
for (dirpath, dirnames, filenames) in safe_walk(directory, whitelist=whitelist):
if self.__safe_directory(directory, allowlist=allowlist):
for (dirpath, dirnames, filenames) in safe_walk(directory, allowlist=allowlist):
for dirname in dirnames:
dir_path = os.path.relpath(os.path.join(dirpath, dirname), directory)
dir_path_hash = hashlib.sha1(smart_str(dir_path)).hexdigest()
@@ -156,18 +156,18 @@ class RemoteFilesAPIController(BaseAPIController):
userdir_jstree = jstree.JSTree(jstree_paths)
return userdir_jstree
def __safe_directory(self, directory, whitelist=None):
def __safe_directory(self, directory, allowlist=None):
"""
Checks to see if the directory is contained within itself or the whitelist, and whether it exists
Checks to see if the directory is contained within itself or the allowlist, and whether it exists
:param directory: the directory to check for safety
:type directory: string
:param whitelist: a list of acceptable paths to import from
:type whitelist: comma separated list of strings
:param allowlist: a list of acceptable paths to import from
:type allowlist: comma separated list of strings
:return: ``True`` if the path is safe to import from, ``False`` otherwise
"""
if not safe_path(directory, whitelist=whitelist):
raise exceptions.ConfigDoesNotAllowException('directory (%s) is a symlink to a location not on the whitelist' % directory)
if not safe_path(directory, allowlist=allowlist):
raise exceptions.ConfigDoesNotAllowException('directory (%s) is a symlink to a location not on the allowlist' % directory)
if not os.path.exists(directory):
return False
return True
+15 -15
View File
@@ -925,29 +925,30 @@ mapping:
Example value 'https://galaxyproject.org/'
blacklist_file:
email_domain_blocklist_file:
type: str
required: false
desc: |
E-mail domains blacklist is used for filtering out users that are using
E-mail domains blocklist is used for filtering out users that are using
disposable email addresses at registration. If their address domain matches any
domain on the list, they are refused registration.
Example value 'email_blacklist.conf'
Example value 'email_blocklist.conf'
The value of this option will be resolved with respect to <config_dir>.
whitelist_file:
email_domain_allowlist_file:
type: str
required: false
desc: |
E-mail domains whitelist is used to specify allowed email address domains.
E-mail domains allowlist is used to specify allowed email address domains.
If the list is non-empty and a user attempts registration using an email
address belonging to a domain that is not on the list, registration will be
denied. This is a more restrictive option than <blacklist_file>, and therefore,
in case <whitelist_file> is set and is not empty, <blacklist_file> will be ignored.
denied. This is a more restrictive option than <email_domain_blocklist_file>, and
therefore, in case <email_domain_allowlist_file> is set and is not empty,
<email_domain_blocklist_file> will be ignored.
Example value 'email_whitelist.conf'
Example value 'email_allowlist.conf'
The value of this option will be resolved with respect to <config_dir>.
@@ -1639,15 +1640,14 @@ mapping:
special tools that require unaltered output. WARNING: disabling this does
make the Galaxy instance susceptible to XSS attacks initiated by your users.
sanitize_whitelist_file:
sanitize_allowlist_file:
type: str
default: sanitize_whitelist.txt
default: sanitize_allowlist.txt
required: false
desc: |
Whitelist sanitization file.
Datasets created by tools listed in this file are trusted and will not have
their HTML sanitized on display. This can be manually edited or manipulated
through the Admin control panel -- see "Manage Display Whitelist"
through the Admin control panel -- see "Manage Display Allowlist"
The value of this option will be resolved with respect to <mutable_config_dir>.
@@ -1844,7 +1844,7 @@ mapping:
If user_library_import_dir is set, this option will auto create a library
import directory for every user (based on their email) upon login.
user_library_import_symlink_whitelist:
user_library_import_symlink_allowlist:
type: str
required: false
desc: |
@@ -2195,11 +2195,11 @@ mapping:
If enable_beta_gdpr is set to true, then this option will be
overridden and set to false.
fetch_url_whitelist:
fetch_url_allowlist:
type: str
required: false
desc: |
Whitelist for local network addresses for "Upload from URL" dialog.
List of allowed local network addresses for "Upload from URL" dialog.
By default, Galaxy will deny access to the local network address space, to
prevent users making requests to services which the administrator did not
intend to expose. Previously, you could request any network service that
+11 -11
View File
@@ -1620,19 +1620,19 @@ class AdminGalaxy(controller.JSAppLauncher, AdminActions, UsesQuotaMixin, QuotaP
@web.expose
@web.require_admin
def sanitize_whitelist(self, trans, submit_whitelist=False, tools_to_whitelist=[]):
if submit_whitelist:
# write the configured sanitize_whitelist_file with new whitelist
def sanitize_allowlist(self, trans, submit_allowlist=False, tools_to_allowlist=[]):
if submit_allowlist:
# write the configured sanitize_allowlist_file with new allowlist
# and update in-memory list.
with open(trans.app.config.sanitize_whitelist_file, 'wt') as f:
if isinstance(tools_to_whitelist, six.string_types):
tools_to_whitelist = [tools_to_whitelist]
new_whitelist = sorted([tid for tid in tools_to_whitelist if tid in trans.app.toolbox.tools_by_id])
f.write("\n".join(new_whitelist))
trans.app.config.sanitize_whitelist = new_whitelist
trans.app.queue_worker.send_control_task('reload_sanitize_whitelist', noop_self=True)
with open(trans.app.config.sanitize_allowlist_file, 'wt') as f:
if isinstance(tools_to_allowlist, six.string_types):
tools_to_allowlist = [tools_to_allowlist]
new_allowlist = sorted([tid for tid in tools_to_allowlist if tid in trans.app.toolbox.tools_by_id])
f.write("\n".join(new_allowlist))
trans.app.config.sanitize_allowlist = new_allowlist
trans.app.queue_worker.send_control_task('reload_sanitize_allowlist', noop_self=True)
# dispatch a message to reload list for other processes
return trans.fill_template('/webapps/galaxy/admin/sanitize_whitelist.mako',
return trans.fill_template('/webapps/galaxy/admin/sanitize_allowlist.mako',
sanitize_all=trans.app.config.sanitize_all_html,
tools=trans.app.toolbox.tools_by_id)
+1 -1
View File
@@ -424,7 +424,7 @@ def update_repository(app, trans, id, **kwds):
message = "You are not the owner of this repository, so you cannot administer it."
return None, message
# Whitelist properties that can be changed via this method
# Allowlist properties that can be changed via this method
for key in ('type', 'description', 'long_description', 'remote_repository_url', 'homepage_url'):
# If that key is available, not None and different than what's in the model
if key in kwds and kwds[key] is not None and kwds[key] != getattr(repository, key):
+4 -4
View File
@@ -101,10 +101,10 @@ class ToolShedAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
# Galaxy flavor Docker Image
self.user_activation_on = None
self.registration_warning_message = kwargs.get('registration_warning_message')
self.blacklist_location = kwargs.get('blacklist_file')
self.blacklist_content = None
self.whitelist_location = kwargs.get('whitelist_file')
self.whitelist_content = None
self.email_domain_blocklist_location = kwargs.get('email_domain_blocklist_file')
self.email_domain_blocklist_content = None
self.email_domain_allowlist_location = kwargs.get('email_domain_allowlist_file')
self.email_domain_allowlist_content = None
self.template_path = templates_path
self.template_cache_path = self._in_root_dir(kwargs.get('template_cache_path', 'database/compiled_templates/community'))
self.error_email_to = kwargs.get('error_email_to')
+9 -11
View File
@@ -469,26 +469,24 @@ mapping:
path where the nginx_upload_module has been configured to intercept upload
requests.
blacklist_file:
email_domain_blocklist_file:
type: str
default: config/disposable_email_blacklist.conf
required: false
desc: |
E-mail domains blacklist is used for filtering out users that are using
disposable email address during the registration. If their address domain
matches any domain in the blacklist, they are refused the registration.
E-mail domains blocklist is used for filtering out users that are using
disposable email addresses at registration. If their address domain matches any
domain on the list, they are refused registration.
whitelist_file:
email_domain_allowlist_file:
type: str
default: disposable_email_whitelist.conf
path_resolves_to: config_dir
required: false
desc: |
E-mail domains whitelist is used to specify allowed email address domains.
E-mail domains allowlist is used to specify allowed email address domains.
If the list is non-empty and a user attempts registration using an email
address belonging to a domain that is not on the list, registration will be
enied. This is a more restrictive option than <blacklist_file>, and therefore,
in case <whitelist_file> is defined, <blacklist_file> will be ignored.
denied. This is a more restrictive option than <email_domain_blocklist_file>, and
therefore, in case <email_domain_allowlist_file> is set and is not empty,
<email_domain_blocklist_file> will be ignored.
brand:
type: str
@@ -10,25 +10,25 @@
in your galaxy configuration file. This prevents Galaxy from sanitizing
tool outputs, which is an important security feature. For improved
security, we recommend you disable the old-style blanket sanitization and
manage it via this whitelist instead.</p></div>
manage it via this allowlist instead.</p></div>
%else:
<div><p>This interface will allow you to mark particular tools as 'trusted'
after which Galaxy will no longer attempt to sanitize any HTML contents of
datasets created by these tools upon display. Please be aware of the
potential security implications of doing this -- bypassing sanitization
using this whitelist disables Galaxy's security feature (for the indicated
using this allowlist disables Galaxy's security feature (for the indicated
tools) that prevents Galaxy from displaying potentially malicious
Javascript.<br/>
Note that datasets originating from an archive import are still sanitized
even when their creating tool is whitelisted since it isn't possible to
even when their creating tool is allowlisted since it isn't possible to
validate the information supplied in the archive.</p></div>
<form name="sanitize_whitelist" method="post" action="${h.url_for( controller='admin', action='sanitize_whitelist' )}">
<form name="sanitize_allowlist" method="post" action="${h.url_for( controller='admin', action='sanitize_allowlist' )}">
<div class="card mb-3">
<div class="card-header">Tool Sanitization Whitelist</div>
<div class="card-header">Tool Sanitization Allowlist</div>
<div class="card-body overflow-auto">
<table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<th>Whitelist</th>
<th>Allowlist</th>
<th>Name</th>
<th>ID</th>
</tr>
@@ -40,10 +40,10 @@
<tr class="tr">
%endif
<td>
%if tool.id in trans.app.config.sanitize_whitelist:
<input type="checkbox" name="tools_to_whitelist" value="${tool.id}" checked="checked"/>
%if tool.id in trans.app.config.sanitize_allowlist:
<input type="checkbox" name="tools_to_allowlist" value="${tool.id}" checked="checked"/>
%else:
<input type="checkbox" name="tools_to_whitelist" value="${tool.id}"/>
<input type="checkbox" name="tools_to_allowlist" value="${tool.id}"/>
%endif
</td>
<td>${ tool.name | h }</td>
@@ -54,6 +54,6 @@
</table>
</div>
</div>
<input type="submit" name="submit_whitelist" value="Submit new whitelist"/>
<input type="submit" name="submit_allowlist" value="Submit new allowlist"/>
</form>
%endif
+4 -4
View File
@@ -46,7 +46,7 @@ PATH_CONFIG_PROPERTIES = [
'managed_config_dir',
'data_dir',
'auth_config_file',
'blacklist_file',
'email_domain_blocklist_file',
'builds_file_path',
'citation_cache_data_dir',
'citation_cache_lock_dir',
@@ -78,7 +78,7 @@ PATH_CONFIG_PROPERTIES = [
'oidc_backends_config_file',
'oidc_config_file',
'openid_consumer_cache_path',
'sanitize_whitelist_file',
'sanitize_allowlist_file',
'shed_data_manager_config_file',
'shed_tool_config_file',
'shed_tool_data_path',
@@ -115,7 +115,7 @@ RESOLVE = {
'object_store_config_file': 'config_dir',
'oidc_backends_config_file': 'config_dir',
'oidc_config_file': 'config_dir',
'sanitize_whitelist_file': 'managed_config_dir',
'sanitize_allowlist_file': 'managed_config_dir',
'shed_data_manager_config_file': 'managed_config_dir',
'shed_tool_config_file': 'managed_config_dir',
'shed_tool_data_path': 'tool_data_path',
@@ -139,7 +139,7 @@ CUSTOM = {
'password_expiration_period': timedelta,
'toolbox_filter_base_modules': listify,
'mulled_channels': listify,
'user_library_import_symlink_whitelist': listify,
'user_library_import_symlink_allowlist': listify,
'tool_filters': listify,
'tool_label_filters': listify,
'tool_section_filters': listify,
+2 -2
View File
@@ -41,7 +41,7 @@ class ExpectedValues:
'tool_section_filters': listify_strip,
'toolbox_filter_base_modules': listify_strip,
'use_remote_user': None, # TODO: should be False (config logic incorrect)
'user_library_import_symlink_whitelist': listify_strip,
'user_library_import_symlink_allowlist': listify_strip,
'user_tool_filters': listify_strip,
'user_tool_label_filters': listify_strip,
'user_tool_section_filters': listify_strip,
@@ -87,7 +87,7 @@ class ExpectedValues:
'oidc_backends_config_file': self._in_config_dir('oidc_backends_config.xml'),
'oidc_config_file': self._in_config_dir('oidc_config.xml'),
'openid_consumer_cache_path': self._in_data_dir('openid_consumer_cache'),
'sanitize_whitelist_file': self._in_managed_config_dir('sanitize_whitelist.txt'),
'sanitize_allowlist_file': self._in_managed_config_dir('sanitize_allowlist.txt'),
'shed_data_manager_config_file': self._in_managed_config_dir('shed_data_manager_conf.xml'),
'shed_tool_config_file': self._in_managed_config_dir('shed_tool_conf.xml'),
'shed_tool_data_path': self._in_root_dir('tool-data'),
+2 -2
View File
@@ -705,11 +705,11 @@ class HistoryFiltersTestCase(BaseTestCase):
self.assertRaises(exceptions.RequestParameterInvalidException, self.filter_parser.parse_filters, [
('merp', 'eq', 'wot'),
])
self.log('should error on non-whitelisted attr')
self.log('should error on non-allowlisted attr')
self.assertRaises(exceptions.RequestParameterInvalidException, self.filter_parser.parse_filters, [
('user_id', 'eq', 'wot'),
])
self.log('should error on non-whitelisted op')
self.log('should error on non-allowlisted op')
self.assertRaises(exceptions.RequestParameterInvalidException, self.filter_parser.parse_filters, [
('name', 'lt', 'wot'),
])
+11 -11
View File
@@ -1,12 +1,12 @@
from galaxy.util import sqlite
def test_query_whitelisting():
__assert_whitelisted("SELECT * from FOO")
__assert_whitelisted("SELECT f.col1, f.col2 from FOO as f")
__assert_whitelisted("SELECT f.col1, b.col2 from FOO as f inner join BAR as b on f.id = b.foo_id")
__assert_not_whitelisted("UPDATE FOO SET foo=6")
__assert_not_whitelisted("TRUNCATE FOO")
def test_query_allowed():
__assert_allowed("SELECT * from FOO")
__assert_allowed("SELECT f.col1, f.col2 from FOO as f")
__assert_allowed("SELECT f.col1, b.col2 from FOO as f inner join BAR as b on f.id = b.foo_id")
__assert_not_allowed("UPDATE FOO SET foo=6")
__assert_not_allowed("TRUNCATE FOO")
def test_sqlite_exploits():
@@ -31,7 +31,7 @@ def test_sqlite_exploits():
# Ensure nested queries cannot modify database.
__assert_query_errors(connection, "select * from FOO where foo1 in (INSERT INTO FOO VALUES ('bar')")
# Should access to the schema be blacklisted?
# Should access to the schema be disallowed?
# __assert_has_n_rows(connection, "select * from SQLITE_MASTER", 0)
@@ -52,9 +52,9 @@ def __assert_query_errors(connection, query):
assert exception
def __assert_whitelisted(query):
assert sqlite.is_read_only_query(query), "Query [%s] fails whitelist." % query
def __assert_allowed(query):
assert sqlite.is_read_only_query(query), "Query [%s] fails allowlist." % query
def __assert_not_whitelisted(query):
assert not sqlite.is_read_only_query(query), "Query [%s] incorrectly fails whitelist." % query
def __assert_not_allowed(query):
assert not sqlite.is_read_only_query(query), "Query [%s] incorrectly fails allowlist." % query
@@ -21,10 +21,10 @@ def test_get_singularity_containers():
def test_get_missing_containers():
test_dir = tempfile.mkdtemp()
try:
exclude_list = '%s/blacklist.txt' % test_dir
exclude_list = '%s/blocklist.txt' % test_dir
with open(exclude_list, 'w') as f:
f.write('a\n\nb\nc\nd')
containers = get_missing_containers(quay_list=['1', '2', '3', 'a', 'b', 'z'], singularity_list=['3', '4', '5'], blacklist_file=exclude_list)
containers = get_missing_containers(quay_list=['1', '2', '3', 'a', 'b', 'z'], singularity_list=['3', '4', '5'], blocklist_file=exclude_list)
assert containers == ['1', '2', 'z']
finally:
shutil.rmtree(test_dir)
@@ -33,10 +33,10 @@ def test_get_missing_containers():
def test_get_missing_envs():
test_dir = tempfile.mkdtemp()
try:
exclude_list = '%s/blacklist.txt' % test_dir
exclude_list = '%s/blocklist.txt' % test_dir
with open(exclude_list, 'w') as f:
f.write('a\n\nb\nc\nd')
envs = get_missing_envs(quay_list=['1', '2', '3', 'a', 'b--2', 'z--1'], conda_list=['3', '4', '5'], blacklist_file=exclude_list)
envs = get_missing_envs(quay_list=['1', '2', '3', 'a', 'b--2', 'z--1'], conda_list=['3', '4', '5'], blocklist_file=exclude_list)
assert envs == ['1', '2', 'z--1']
finally:
shutil.rmtree(test_dir)