diff --git a/docs/en_US/release_notes_5_4.rst b/docs/en_US/release_notes_5_4.rst index 3e356e863..ac696a1ff 100644 --- a/docs/en_US/release_notes_5_4.rst +++ b/docs/en_US/release_notes_5_4.rst @@ -20,6 +20,7 @@ New features Housekeeping ************ +| `Issue #6225 `_ - Updated Flask-Security-Too to the latest v4. Bug fixes ********* diff --git a/requirements.txt b/requirements.txt index ebdb1b21e..3ed3f7800 100644 --- a/requirements.txt +++ b/requirements.txt @@ -29,7 +29,7 @@ psycopg2==2.8.* python-dateutil==2.* SQLAlchemy==1.3.* itsdangerous<=1.1.0 -Flask-Security-Too==3.* +Flask-Security-Too==4.* bcrypt==3.* cryptography==3.* sshtunnel==0.* diff --git a/web/migrations/versions/c465fee44968_.py b/web/migrations/versions/c465fee44968_.py new file mode 100644 index 000000000..07459675d --- /dev/null +++ b/web/migrations/versions/c465fee44968_.py @@ -0,0 +1,57 @@ + +"""empty message + +Revision ID: c465fee44968 +Revises: d0bc9f32b2b9 +Create Date: 2021-06-04 14:42:12.843116 + +""" +from pgadmin.model import db, User +import uuid + + +# revision identifiers, used by Alembic. +revision = 'c465fee44968' +down_revision = 'd0bc9f32b2b9' +branch_labels = None +depends_on = None + + +def upgrade(): + db.engine.execute("ALTER TABLE user RENAME TO user_old") + + db.engine.execute(""" + CREATE TABLE user ( + id INTEGER NOT NULL, + username VARCHAR(256) NOT NULL, + email VARCHAR(256), + password VARCHAR(256), + active BOOLEAN NOT NULL, + confirmed_at DATETIME, + masterpass_check VARCHAR(256), + auth_source VARCHAR(256) NOT NULL DEFAULT 'internal', + fs_uniquifier NOT NULL UNIQUE, + PRIMARY KEY (id), + UNIQUE (username, auth_source, fs_uniquifier), + CHECK (active IN (0, 1)) + ); + """) + + user_old = db.engine.execute( + 'select id, username, email, password, active, ' + 'confirmed_at, masterpass_check, auth_source ' + 'from user_old') + + db.engine.execute(User.__table__.insert(), [ + { + **row, + 'fs_uniquifier': uuid.uuid4().hex + } for row in user_old + ]) + + db.engine.execute("DROP TABLE user_old") + + +def downgrade(): + # pgAdmin only upgrades, downgrade not implemented. + pass diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py index 6e395f42f..dfc034c93 100644 --- a/web/pgadmin/__init__.py +++ b/web/pgadmin/__init__.py @@ -305,7 +305,7 @@ def create_app(app_name=None): if current_user.is_authenticated: user_id = current_user.id else: - user = user_datastore.get_user(config.DESKTOP_USER) + user = user_datastore.find_user(email=config.DESKTOP_USER) if user is not None: user_id = user.id user_language = Preferences.raw_value( @@ -697,7 +697,7 @@ def create_app(app_name=None): abort(401) if not config.SERVER_MODE and not current_user.is_authenticated: - user = user_datastore.get_user(config.DESKTOP_USER) + user = user_datastore.find_user(email=config.DESKTOP_USER) # Throw an error if we failed to find the desktop user, to give # the sysadmin a hint. We'll continue to try to login anyway as # that'll through a nice 500 error for us. diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py index edbd491e7..d6cf78cac 100644 --- a/web/pgadmin/browser/__init__.py +++ b/web/pgadmin/browser/__init__.py @@ -32,7 +32,7 @@ from flask_security.recoverable import reset_password_token_status, \ from flask_security.signals import reset_password_instructions_sent from flask_security.utils import config_value, do_flash, get_url, \ get_message, slash_url_suffix, login_user, send_mail, logout_user -from flask_security.views import _security, _commit, _ctx +from flask_security.views import _security, view_commit, _ctx from werkzeug.datastructures import MultiDict import config @@ -1144,7 +1144,7 @@ if hasattr(config, 'SECURITY_CHANGEABLE') and config.SECURITY_CHANGEABLE: has_error = True if request.json is None and not has_error: - after_this_request(_commit) + after_this_request(view_commit) do_flash(*get_message('PASSWORD_CHANGE')) old_key = get_crypt_key()[1] @@ -1310,7 +1310,7 @@ if hasattr(config, 'SECURITY_RECOVERABLE') and config.SECURITY_RECOVERABLE: has_error = True if not has_error: - after_this_request(_commit) + after_this_request(view_commit) do_flash(*get_message('PASSWORD_RESET')) login_user(user) return redirect(get_url(_security.post_reset_view) or diff --git a/web/pgadmin/model/__init__.py b/web/pgadmin/model/__init__.py index bd90077b7..3afef96eb 100644 --- a/web/pgadmin/model/__init__.py +++ b/web/pgadmin/model/__init__.py @@ -20,6 +20,7 @@ things: from flask_security import UserMixin, RoleMixin from flask_sqlalchemy import SQLAlchemy +import uuid ########################################################################## # @@ -29,7 +30,7 @@ from flask_sqlalchemy import SQLAlchemy # ########################################################################## -SCHEMA_VERSION = 29 +SCHEMA_VERSION = 30 ########################################################################## # @@ -76,6 +77,9 @@ class User(db.Model, UserMixin): roles = db.relationship('Role', secondary=roles_users, backref=db.backref('users', lazy='dynamic')) auth_source = db.Column(db.String(16), unique=True, nullable=False) + # fs_uniquifier is required by flask-security-too >= 4. + fs_uniquifier = db.Column(db.String(255), unique=True, nullable=False, + default=(lambda _: uuid.uuid4().hex)) class Setting(db.Model):