diff --git a/CHANGELOG b/CHANGELOG index 37f39de616..cd04d128c4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Remove super password +* Remove database management from RPC * Remove ModelView.view_header_get * Remove string attribute from views * Don't check write access on model for button with groups diff --git a/doc/topics/configuration.rst b/doc/topics/configuration.rst index ff80ad9e60..012d01707b 100644 --- a/doc/topics/configuration.rst +++ b/doc/topics/configuration.rst @@ -219,15 +219,6 @@ The time in seconds until a session expires. Default: `600` -super_pwd -~~~~~~~~~ - -The server password used to authenticate from the client for database -management tasks. It is encrypted using using the Unix `crypt(3)` routine. -A password can be generated using this command line:: - - python -c 'import getpass,crypt,random,string; print crypt.crypt(getpass.getpass(), "".join(random.sample(string.ascii_letters + string.digits, 8)))' - report ------ diff --git a/trytond/backend/database.py b/trytond/backend/database.py index 22567cd61c..d825c6be27 100644 --- a/trytond/backend/database.py +++ b/trytond/backend/database.py @@ -65,27 +65,6 @@ class DatabaseInterface(object): ''' raise NotImplementedError - @staticmethod - def dump(database_name): - ''' - Dump a database - - :param database_name: the database name - :return: the dump - ''' - raise NotImplementedError - - @staticmethod - def restore(database_name, data): - ''' - Restore a database - - :param database_name: the database name - :param data: the data - :return: True if succeed - ''' - raise NotImplementedError - def list(self): ''' Get the list of database diff --git a/trytond/backend/mysql/database.py b/trytond/backend/mysql/database.py index 0c091f69c2..a59f3901fe 100644 --- a/trytond/backend/mysql/database.py +++ b/trytond/backend/mysql/database.py @@ -9,7 +9,6 @@ from MySQLdb import IntegrityError as DatabaseIntegrityError from MySQLdb import OperationalError as DatabaseOperationalError import os import time -import tempfile import urllib from sql import Flavor, Expression @@ -126,79 +125,6 @@ class Database(DatabaseInterface): cursor.execute('DROP DATABASE `' + database_name + '`') cls._list_cache = None - @staticmethod - def dump(database_name): - from trytond.tools import exec_command_pipe - - cmd = ['mysqldump', '--no-create-db'] - uri = parse_uri(config.get('database', 'uri')) - if uri.username: - cmd.append('--user=' + uri.username) - if uri.hostname: - cmd.append('--host=' + uri.hostname) - if uri.port: - cmd.append('--port=' + str(uri.port)) - if uri.password: - cmd.append('--password=' + uri.password) - cmd.append(database_name) - - pipe = exec_command_pipe(*tuple(cmd)) - pipe.stdin.close() - data = pipe.stdout.read() - res = pipe.wait() - if res: - raise Exception('Couldn\'t dump database!') - return data - - @staticmethod - def restore(database_name, data): - from trytond.tools import exec_command_pipe - - database = Database().connect() - cursor = database.cursor(autocommit=True) - database.create(cursor, database_name) - cursor.commit() - cursor.close() - - cmd = ['mysql'] - uri = parse_uri(config.get('database', 'uri')) - if uri.username: - cmd.append('--user=' + uri.username) - if uri.hostname: - cmd.append('--host=' + uri.hostname) - if uri.port: - cmd.append('--port=' + str(uri.port)) - if uri.password: - cmd.append('--password=' + uri.password) - cmd.append(database_name) - - fd, file_name = tempfile.mkstemp() - with os.fdopen(fd, 'wb+') as fd: - fd.write(data) - - cmd.append('<') - cmd.append(file_name) - - args2 = tuple(cmd) - - pipe = exec_command_pipe(*args2) - pipe.stdin.close() - res = pipe.wait() - os.remove(file_name) - if res: - raise Exception('Couldn\'t restore database') - - database = Database(database_name).connect() - cursor = database.cursor() - if not cursor.test(): - cursor.close() - database.close() - raise Exception('Couldn\'t restore database!') - cursor.close() - database.close() - Database._list_cache = None - return True - def list(self): now = time.time() timeout = config.getint('session', 'timeout') diff --git a/trytond/backend/postgresql/database.py b/trytond/backend/postgresql/database.py index e0c11f4306..74272d856a 100644 --- a/trytond/backend/postgresql/database.py +++ b/trytond/backend/postgresql/database.py @@ -146,84 +146,6 @@ class Database(DatabaseInterface): RE_VERSION.search(version).groups())) return self._version_cache[self.name] - @staticmethod - def dump(database_name): - from trytond.tools import exec_command_pipe - - cmd = ['pg_dump', '--format=c', '--no-owner'] - env = {} - uri = parse_uri(config.get('database', 'uri')) - if uri.username: - cmd.append('--username=' + uri.username) - if uri.hostname: - cmd.append('--host=' + uri.hostname) - if uri.port: - cmd.append('--port=' + str(uri.port)) - if uri.password: - # if db_password is set in configuration we should pass - # an environment variable PGPASSWORD to our subprocess - # see libpg documentation - env['PGPASSWORD'] = uri.password - cmd.append(database_name) - - pipe = exec_command_pipe(*tuple(cmd), env=env) - pipe.stdin.close() - data = pipe.stdout.read() - res = pipe.wait() - if res: - raise Exception('Couldn\'t dump database!') - return data - - @staticmethod - def restore(database_name, data): - from trytond.tools import exec_command_pipe - - database = Database().connect() - connection = database.get_connection(autocommit=True) - database.create(connection, database_name) - database.close() - - cmd = ['pg_restore', '--no-owner'] - env = {} - uri = parse_uri(config.get('database', 'uri')) - if uri.username: - cmd.append('--username=' + uri.username) - if uri.hostname: - cmd.append('--host=' + uri.hostname) - if uri.port: - cmd.append('--port=' + str(uri.port)) - if uri.password: - env['PGPASSWORD'] = uri.password - cmd.append('--dbname=' + database_name) - args2 = tuple(cmd) - - if os.name == "nt": - tmpfile = (os.environ['TMP'] or 'C:\\') + os.tmpnam() - with open(tmpfile, 'wb') as fp: - fp.write(data) - args2 = list(args2) - args2.append(' ' + tmpfile) - args2 = tuple(args2) - - pipe = exec_command_pipe(*args2, env=env) - if not os.name == "nt": - pipe.stdin.write(data) - pipe.stdin.close() - res = pipe.wait() - if res: - raise Exception('Couldn\'t restore database') - - database = Database(database_name).connect() - cursor = database.get_connection().cursor() - if not database.test(): - cursor.close() - database.close() - raise Exception('Couldn\'t restore database!') - cursor.close() - database.close() - Database._list_cache = None - return True - def list(self): now = time.time() timeout = config.getint('session', 'timeout') diff --git a/trytond/backend/sqlite/database.py b/trytond/backend/sqlite/database.py index ff5a91a23c..139a1894e8 100644 --- a/trytond/backend/sqlite/database.py +++ b/trytond/backend/sqlite/database.py @@ -279,31 +279,6 @@ class Database(DatabaseInterface): os.remove(os.path.join(config.get('database', 'path'), database_name + '.sqlite')) - @staticmethod - def dump(database_name): - if database_name == ':memory:': - raise Exception('Unable to dump memory database!') - if os.sep in database_name: - raise Exception('Wrong database name!') - path = os.path.join(config.get('database', 'path'), - database_name + '.sqlite') - with open(path, 'rb') as file_p: - data = file_p.read() - return data - - @staticmethod - def restore(database_name, data): - if database_name == ':memory:': - raise Exception('Unable to restore memory database!') - if os.sep in database_name: - raise Exception('Wrong database name!') - path = os.path.join(config.get('database', 'path'), - database_name + '.sqlite') - if os.path.isfile(path): - raise Exception('Database already exists!') - with open(path, 'wb') as file_p: - file_p.write(data) - def list(self): res = [] listdir = [':memory:'] diff --git a/trytond/protocols/dispatcher.py b/trytond/protocols/dispatcher.py index dbed4fab49..b55bc493b3 100644 --- a/trytond/protocols/dispatcher.py +++ b/trytond/protocols/dispatcher.py @@ -2,7 +2,6 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import logging -import time import pydoc from functools import wraps @@ -48,11 +47,6 @@ def rpc(request, database_name): methods = { 'common.db.login': login, 'common.db.logout': logout, - 'common.db.db_exist': db_exist, - 'common.db.create': create, - 'common.db.restore': restore, - 'common.db.drop': drop, - 'common.db.dump': dump, 'system.listMethods': list_method, 'system.methodHelp': help_method, 'system.methodSignature': lambda *a: 'signatures not supported', @@ -96,7 +90,6 @@ def logout(request, database_name): def root(request, *args): methods = { 'common.server.version': lambda *a: __version__, - 'common.db.list_lang': list_lang, 'common.db.list': db_list, } return methods[request.method](request, *request.params) @@ -107,31 +100,6 @@ def home(request): return redirect('/index.html') # XXX find a better way -def list_lang(*args): - return [ - ('bg_BG', 'Български'), - ('ca_ES', 'Català'), - ('cs_CZ', 'Čeština'), - ('de_DE', 'Deutsch'), - ('en_US', 'English'), - ('es_AR', 'Español (Argentina)'), - ('es_EC', 'Español (Ecuador)'), - ('es_ES', 'Español (España)'), - ('es_CO', 'Español (Colombia)'), - ('es_MX', 'Español (México)'), - ('fr_FR', 'Français'), - ('hu_HU', 'Magyar'), - ('it_IT', 'Italiano'), - ('lt_LT', 'Lietuvių'), - ('lo_LA', 'ລາວ'), - ('nl_NL', 'Nederlands'), - ('pt_BR', 'Português (Brasil)'), - ('ru_RU', 'Russian'), - ('sl_SI', 'Slovenščina'), - ('zh_CN', '中国(简体)'), - ] - - def db_exist(request, database_name): Database = backend.get('Database') try: @@ -237,119 +205,3 @@ def _dispatch(request, pool, *args, **kwargs): logger.debug('Reset session failed', exc_info=True) logger.debug('Result: %s', result) return result - - -def create(request, database_name, password, lang, admin_password): - ''' - Create a database - - :param database_name: the database name - :param password: the server password - :param lang: the default language for the database - :param admin_password: the admin password - :return: True if succeed - ''' - Database = backend.get('Database') - security.check_super(password) - res = False - - try: - with Transaction().start(None, 0, close=True, autocommit=True) \ - as transaction: - transaction.database.create(transaction.connection, database_name) - - with Transaction().start(database_name, 0) as transaction,\ - transaction.connection.cursor() as cursor: - Database(database_name).init() - cursor.execute(*ir_configuration.insert( - [ir_configuration.language], [[lang]])) - - pool = Pool(database_name) - pool.init(update=['res', 'ir'], lang=[lang]) - with Transaction().start(database_name, 0) as transaction: - User = pool.get('res.user') - Lang = pool.get('ir.lang') - language, = Lang.search([('code', '=', lang)]) - language.translatable = True - language.save() - users = User.search([('login', '!=', 'root')]) - User.write(users, { - 'language': language.id, - }) - admin, = User.search([('login', '=', 'admin')]) - User.write([admin], { - 'password': admin_password, - }) - Module = pool.get('ir.module') - if Module: - Module.update_list() - res = True - except Exception: - logger.error('CREATE DB: %s failed', database_name, exc_info=True) - raise - else: - logger.info('CREATE DB: %s', database_name) - return res - - -def drop(request, database_name, password): - Database = backend.get('Database') - security.check_super(password) - database = Database(database_name) - database.close() - # Sleep to let connections close - time.sleep(1) - - with Transaction().start(None, 0, close=True, autocommit=True) \ - as transaction: - try: - database.drop(transaction.connection, database_name) - except Exception: - logger.error('DROP DB: %s failed', database_name, exc_info=True) - raise - else: - logger.info('DROP DB: %s', database_name) - Pool.stop(database_name) - Cache.drop(database_name) - return True - - -def dump(request, database_name, password): - Database = backend.get('Database') - security.check_super(password) - Database(database_name).close() - # Sleep to let connections close - time.sleep(1) - - data = Database.dump(database_name) - logger.info('DUMP DB: %s', database_name) - if bytes == str: - return bytearray(data) - else: - return bytes(data) - - -def restore(request, database_name, password, data, update=False): - Database = backend.get('Database') - security.check_super(password) - try: - Database(database_name).connect() - existing = True - except Exception: - existing = False - if existing: - raise Exception('Database already exists!') - Database.restore(database_name, data) - logger.info('RESTORE DB: %s', database_name) - if update: - with Transaction().start(database_name, 0) as transaction,\ - transaction.connection.cursor() as cursor: - cursor.execute(*ir_lang.select(ir_lang.code, - where=ir_lang.translatable)) - lang = [x[0] for x in cursor.fetchall()] - cursor.execute(*ir_module.select(ir_module.name, - where=(ir_module.state == 'installed'))) - update = [x[0] for x in cursor.fetchall()] - Pool(database_name).init(update=update, lang=lang) - logger.info('Update/Init succeed!') - return True diff --git a/trytond/security.py b/trytond/security.py index 034ac48924..dedeb501f0 100644 --- a/trytond/security.py +++ b/trytond/security.py @@ -1,10 +1,5 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. -try: - import crypt -except ImportError: - pass - from trytond.pool import Pool from trytond.config import config from trytond.transaction import Transaction @@ -56,13 +51,6 @@ def logout(dbname, user, session): return name -def check_super(passwd): - cryptedpasswd = config.get('session', 'super_pwd') - if cryptedpasswd and crypt.crypt(passwd, cryptedpasswd) == cryptedpasswd: - return True - raise Exception('AccessDenied') - - def check(dbname, user, session): DatabaseOperationalError = backend.get('DatabaseOperationalError') for count in range(config.getint('database', 'retry'), -1, -1): diff --git a/trytond/tests/test_tryton.py b/trytond/tests/test_tryton.py index fad1a5baba..c47b8807b0 100644 --- a/trytond/tests/test_tryton.py +++ b/trytond/tests/test_tryton.py @@ -11,31 +11,28 @@ import operator from functools import wraps from lxml import etree +from sql import Table from trytond.pool import Pool, isregisteredby from trytond import backend from trytond.model import Workflow from trytond.model.fields import get_eval_fields -from trytond.protocols.dispatcher import create, drop from trytond.tools import is_instance_method from trytond.transaction import Transaction -from trytond import security from trytond.cache import Cache -__all__ = ['POOL', 'DB_NAME', 'USER', 'USER_PASSWORD', 'CONTEXT', +__all__ = ['POOL', 'DB_NAME', 'USER', 'CONTEXT', 'install_module', 'ModuleTestCase', 'with_transaction', 'doctest_setup', 'doctest_teardown', 'doctest_checker', 'suite', 'all_suite', 'modules_suite'] Pool.start() USER = 1 -USER_PASSWORD = 'admin' CONTEXT = {} DB_NAME = os.environ['DB_NAME'] DB = backend.get('Database')(DB_NAME) Pool.test = True POOL = Pool(DB_NAME) -security.check_super = lambda *a, **k: True def install_module(name): @@ -278,26 +275,58 @@ class ModuleTestCase(unittest.TestCase): }) -def db_exist(): +def db_exist(name=DB_NAME): Database = backend.get('Database') database = Database().connect() - return DB_NAME in database.list() + return name in database.list() -def create_db(): - if not db_exist(): - create(None, DB_NAME, None, 'en_US', USER_PASSWORD) +def create_db(name=DB_NAME, lang='en_US'): + Database = backend.get('Database') + if not db_exist(name): + with Transaction().start(None, 0, close=True, autocommit=True) \ + as transaction: + transaction.database.create(transaction.connection, name) + + with Transaction().start(name, 0) as transaction,\ + transaction.connection.cursor() as cursor: + Database(name).init() + ir_configuration = Table('ir_configuration') + cursor.execute(*ir_configuration.insert( + [ir_configuration.language], [[lang]])) + + pool = Pool(name) + pool.init(update=['res', 'ir'], lang=[lang]) + with Transaction().start(name, 0) as transaction: + User = pool.get('res.user') + Lang = pool.get('ir.lang') + language, = Lang.search([('code', '=', lang)]) + language.translatable = True + language.save() + users = User.search([('login', '!=', 'root')]) + User.write(users, { + 'language': language.id, + }) + Module = pool.get('ir.module') + Module.update_list() -def drop_db(): - if db_exist(): - drop(None, DB_NAME, None) +def drop_db(name=DB_NAME): + if db_exist(name): + Database = backend.get('Database') + database = Database(name) + + with Transaction().start(None, 0, close=True, autocommit=True) \ + as transaction: + database.drop(transaction.connection, name) + Pool.stop(name) + Cache.drop(name) -def drop_create(): - if db_exist(): - drop_db() - create_db() +def drop_create(name=DB_NAME, lang='en_US'): + if db_exist(name): + drop_db(name) + create_db(name, lang) doctest_setup = lambda test: drop_create() doctest_teardown = lambda test: drop_db()