diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index cc2ef4201df..17ca031a48f 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -491,6 +491,9 @@ class Home(http.Controller): if 'login' not in values and request.session.get('auth_login'): values['login'] = request.session.get('auth_login') + if not odoo.tools.config['list_db']: + values['disable_database_manager'] = True + response = request.render('web.login', values) response.headers['X-Frame-Options'] = 'DENY' return response diff --git a/addons/web/views/database_manager.html b/addons/web/views/database_manager.html index 7f0d2fc04ff..f59cca973f9 100644 --- a/addons/web/views/database_manager.html +++ b/addons/web/views/database_manager.html @@ -116,7 +116,11 @@
- {% if insecure and databases %} + {% if not list_db %} +
+ The database manager has been disabled by the administrator +
+ {% elif insecure and databases %}
Warning, your Odoo database manager is not protected. Please set a master password @@ -126,7 +130,7 @@ {% if error %}
{{ error }}
{% endif %} - {% if databases %} + {% if list_db and databases %}
{% for db in databases %} @@ -161,7 +165,7 @@ Manage databases
{% endif %} - {% else %} + {% elif list_db %}
{{ create_form() }} diff --git a/doc/setup/deploy.rst b/doc/setup/deploy.rst index 9879117b607..6e54815496a 100644 --- a/doc/setup/deploy.rst +++ b/doc/setup/deploy.rst @@ -71,7 +71,8 @@ in ``/etc/odoo.conf`` set: Once it is correctly working and only matching a single database per hostname, it is strongly recommended to block access to the database manager screens, and to use the ``--no-database-list`` startup paramater to prevent listing - your databases. See also security_. + your databases, and to block access to the database management screens. + See also security_. PostgreSQL @@ -427,10 +428,14 @@ security-related topics: - Use appropriate database filters ( :option:`--db-filter `) to restrict the visibility of your databases according to the hostname. See :ref:`db_filter`. + You may also use :option:`-d ` to provide your own (comma-separated) + list of available databases to filter from, instead of letting the system fetch + them all from the database backend. -- Once your ``db_filter`` is configured and only matches a single database per hostname, - you should set ``list_db`` configuration option to ``False``, to prevent listing databases - entirely (this is also exposed as the :option:`--no-database-list ` +- Once your ``db_name`` and ``db_filter`` are configured and only match a single database + per hostname, you should set ``list_db`` configuration option to ``False``, to prevent + listing databases entirely, and to block access to the database management screens + (this is also exposed as the :option:`--no-database-list ` command-line option) - Make sure the PostgreSQL user (:option:`--db_user `) is *not* a super-user, @@ -473,10 +478,16 @@ Database Manager Security This setting is used on all database management screens (to create, delete, dump or restore databases). -If the management screens must not be accessible, or must only be accessible -from a selected set of machines, use the proxy server's features to block -access to all routes starting with ``/web/database`` except (maybe) -``/web/database/selector`` which displays the database-selection screen. +If the management screens must not be accessible at all, you should set ``list_db`` +configuration option to ``False``, to block access to all the database selection and +management screens. But be sure to setup an appropriate ``db_name`` parameter +(and optionally, ``db_filter`` too) so that the system can determine the target database +for each request, otherwise users will be blocked as they won't be allowed to choose the +database themselves. + +If the management screens must only be accessible from a selected set of machines, +use the proxy server's features to block access to all routes starting with ``/web/database`` +except (maybe) ``/web/database/selector`` which displays the database-selection screen. If the database-management screen should be left accessible, the ``admin_passwd`` setting must be changed from its ``admin`` default: this diff --git a/odoo/service/db.py b/odoo/service/db.py index 045afc9f0d8..505f86ec50e 100644 --- a/odoo/service/db.py +++ b/odoo/service/db.py @@ -12,12 +12,13 @@ import zipfile from functools import wraps from contextlib import closing +from decorator import decorator import psycopg2 import odoo from odoo import SUPERUSER_ID -from odoo.exceptions import UserError +from odoo.exceptions import AccessDenied import odoo.release import odoo.sql_db import odoo.tools @@ -30,6 +31,15 @@ _logger = logging.getLogger(__name__) class DatabaseExists(Warning): pass + +def check_db_management_enabled(method): + def if_db_mgt_enabled(method, self, *args, **kwargs): + if not odoo.tools.config['list_db']: + _logger.error('Database management functions blocked, admin disabled database listing') + raise AccessDenied() + return method(self, *args, **kwargs) + return decorator(if_db_mgt_enabled, method) + #---------------------------------------------------------- # Master password required #---------------------------------------------------------- @@ -89,6 +99,7 @@ def _create_empty_database(name): cr.autocommit(True) # avoid transaction block cr.execute("""CREATE DATABASE "%s" ENCODING 'unicode' TEMPLATE "%s" """ % (name, chosen_template)) +@check_db_management_enabled def exp_create_database(db_name, demo, lang, user_password='admin', login='admin', country_code=None): """ Similar to exp_create but blocking.""" _logger.info('Create database `%s`.', db_name) @@ -96,6 +107,7 @@ def exp_create_database(db_name, demo, lang, user_password='admin', login='admin _initialize_db(id, db_name, demo, lang, user_password, login, country_code) return True +@check_db_management_enabled def exp_duplicate_database(db_original_name, db_name): _logger.info('Duplicate database `%s` to `%s`.', db_original_name, db_name) odoo.sql_db.close_db(db_original_name) @@ -133,6 +145,7 @@ def _drop_conn(cr, db_name): except Exception: pass +@check_db_management_enabled def exp_drop(db_name): if db_name not in list_dbs(True): return False @@ -157,12 +170,14 @@ def exp_drop(db_name): shutil.rmtree(fs) return True +@check_db_management_enabled def exp_dump(db_name, format): with tempfile.TemporaryFile(mode='w+b') as t: dump_db(db_name, t, format) t.seek(0) return base64.b64encode(t.read()).decode() +@check_db_management_enabled def dump_db_manifest(cr): pg_version = "%d.%d" % divmod(cr._obj.connection.server_version / 100, 100) cr.execute("SELECT name, latest_version FROM ir_module_module WHERE state = 'installed'") @@ -178,6 +193,7 @@ def dump_db_manifest(cr): } return manifest +@check_db_management_enabled def dump_db(db_name, stream, backup_format='zip'): """Dump database `db` into file-like object `stream` if stream is None return a file object with the dump """ @@ -213,6 +229,7 @@ def dump_db(db_name, stream, backup_format='zip'): else: return stdout +@check_db_management_enabled def exp_restore(db_name, data, copy=False): data_file = tempfile.NamedTemporaryFile(delete=False) try: @@ -223,6 +240,7 @@ def exp_restore(db_name, data, copy=False): os.unlink(data_file.name) return True +@check_db_management_enabled def restore_db(db, dump_file, copy=False): assert isinstance(db, pycompat.string_types) if exp_db_exist(db): @@ -277,6 +295,7 @@ def restore_db(db, dump_file, copy=False): _logger.info('RESTORE DB: %s', db) +@check_db_management_enabled def exp_rename(old_name, new_name): odoo.modules.registry.Registry.delete(old_name) odoo.sql_db.close_db(old_name) @@ -298,11 +317,13 @@ def exp_rename(old_name, new_name): shutil.move(old_fs, new_fs) return True +@check_db_management_enabled def exp_change_admin_password(new_password): odoo.tools.config.set_admin_password(new_password) odoo.tools.config.save() return True +@check_db_management_enabled def exp_migrate_databases(databases): for db in databases: _logger.info('migrate database %s', db) diff --git a/odoo/tools/config.py b/odoo/tools/config.py index ba7121e7ca8..1901620cf4e 100644 --- a/odoo/tools/config.py +++ b/odoo/tools/config.py @@ -245,7 +245,9 @@ class configmanager(object): security = optparse.OptionGroup(parser, 'Security-related options') security.add_option('--no-database-list', action="store_false", dest='list_db', my_default=True, - help="disable the ability to return the list of databases") + help="Disable the ability to obtain or view the list of databases. " + "Also disable access to the database manager and selector, " + "so be sure to set a proper --database parameter first") parser.add_option_group(security) # Advanced options