diff --git a/bin/hash_db_password.py b/bin/hash_db_password.py index 2aa399f161..e6b5e50edc 100644 --- a/bin/hash_db_password.py +++ b/bin/hash_db_password.py @@ -38,7 +38,11 @@ for user in users: log.info("Hashing password for {0}".format(user.username)) - user.password = generate_password_hash(user.password) + user.password = generate_password_hash( + password=user.password, + method=app.config.get('FAB_PASSWORD_HASH_METHOD', 'scrypt'), + salt_length=app.config.get('FAB_PASSWORD_HASH_SALT_LENGTH', 16), + ) try: db.session.merge(user) db.session.commit() diff --git a/docs/config.rst b/docs/config.rst index fc531ff45b..b5cdad25c4 100755 --- a/docs/config.rst +++ b/docs/config.rst @@ -325,6 +325,16 @@ Use config.py to configure the following parameters. By default it will use SQLL | | validation for AUTH database users. | No | | | Default is False. | | +----------------------------------------+--------------------------------------------+-----------+ +| FAB_PASSWORD_HASH_METHOD | Sets the password hashing method. For the | | +| | supported parameters see | | +| | `generate_password_hash`_. | No | +| | Default: ``'scrypt'``. | | ++----------------------------------------+--------------------------------------------+-----------+ +| FAB_PASSWORD_HASH_SALT_LENGTH | Sets the password hashing salt length. | No | +| | Default: ``16``. | | ++----------------------------------------+--------------------------------------------+-----------+ + +.. _generate_password_hash: https://werkzeug.palletsprojects.com/en/stable/utils/#werkzeug.security.generate_password_hash Note ---- diff --git a/flask_appbuilder/security/manager.py b/flask_appbuilder/security/manager.py index 96d6e9d646..3ca995f2f7 100644 --- a/flask_appbuilder/security/manager.py +++ b/flask_appbuilder/security/manager.py @@ -950,7 +950,15 @@ def reset_password(self, userid, password): The clear text password to reset and save hashed on the db """ user = self.get_user_by_id(userid) - user.password = generate_password_hash(password) + user.password = generate_password_hash( + password=password, + method=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_METHOD", "scrypt" + ), + salt_length=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_SALT_LENGTH", 16 + ), + ) self.update_user(user) def update_user_auth_stat(self, user, success=True): diff --git a/flask_appbuilder/security/mongoengine/manager.py b/flask_appbuilder/security/mongoengine/manager.py index d6eebb71b3..d00515529b 100644 --- a/flask_appbuilder/security/mongoengine/manager.py +++ b/flask_appbuilder/security/mongoengine/manager.py @@ -94,7 +94,15 @@ def add_register_user( if hashed_password: register_user.password = hashed_password else: - register_user.password = generate_password_hash(password) + register_user.password = generate_password_hash( + password=password, + method=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_METHOD", "scrypt" + ), + salt_length=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_SALT_LENGTH", 16 + ), + ) register_user.registration_hash = str(uuid.uuid1()) register_user.save() return register_user @@ -141,7 +149,15 @@ def add_user( if hashed_password: user.password = hashed_password else: - user.password = generate_password_hash(password) + user.password = generate_password_hash( + password=password, + method=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_METHOD", "scrypt" + ), + salt_length=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_SALT_LENGTH", 16 + ), + ) user.save() log.info(c.LOGMSG_INF_SEC_ADD_USER, username) return user diff --git a/flask_appbuilder/security/sqla/apis/user/api.py b/flask_appbuilder/security/sqla/apis/user/api.py index 94f250123d..006d5d7998 100644 --- a/flask_appbuilder/security/sqla/apis/user/api.py +++ b/flask_appbuilder/security/sqla/apis/user/api.py @@ -69,10 +69,26 @@ def pre_update(self, item): item.changed_on = datetime.now() item.changed_by_fk = g.user.id if item.password: - item.password = generate_password_hash(item.password) + item.password = generate_password_hash( + password=item.password, + method=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_METHOD", "scrypt" + ), + salt_length=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_SALT_LENGTH", 16 + ), + ) def pre_add(self, item): - item.password = generate_password_hash(item.password) + item.password = generate_password_hash( + password=item.password, + method=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_METHOD", "scrypt" + ), + salt_length=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_SALT_LENGTH", 16 + ), + ) @expose("/", methods=["POST"]) @protect() diff --git a/flask_appbuilder/security/sqla/manager.py b/flask_appbuilder/security/sqla/manager.py index efb686f0fc..6bff7a2a10 100755 --- a/flask_appbuilder/security/sqla/manager.py +++ b/flask_appbuilder/security/sqla/manager.py @@ -141,7 +141,15 @@ def add_register_user( if hashed_password: register_user.password = hashed_password else: - register_user.password = generate_password_hash(password) + register_user.password = generate_password_hash( + password=password, + method=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_METHOD", "scrypt" + ), + salt_length=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_SALT_LENGTH", 16 + ), + ) register_user.registration_hash = str(uuid.uuid1()) try: self.get_session.add(register_user) @@ -234,7 +242,15 @@ def add_user( if hashed_password: user.password = hashed_password else: - user.password = generate_password_hash(password) + user.password = generate_password_hash( + password=password, + method=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_METHOD", "scrypt" + ), + salt_length=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_SALT_LENGTH", 16 + ), + ) self.get_session.add(user) self.get_session.commit() log.info(c.LOGMSG_INF_SEC_ADD_USER, username) diff --git a/flask_appbuilder/security/views.py b/flask_appbuilder/security/views.py index cb60ae7009..ec8ec444fd 100644 --- a/flask_appbuilder/security/views.py +++ b/flask_appbuilder/security/views.py @@ -446,7 +446,15 @@ def pre_update(self, item: Any) -> None: item.changed_by_fk = g.user.id def pre_add(self, item: Any) -> None: - item.password = generate_password_hash(item.password) + item.password = generate_password_hash( + password=item.password, + method=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_METHOD", "scrypt" + ), + salt_length=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_SALT_LENGTH", 16 + ), + ) class UserStatsChartView(DirectByChartView): diff --git a/tests/test_security_api.py b/tests/test_security_api.py index 17f4a1713f..53b19fbb46 100644 --- a/tests/test_security_api.py +++ b/tests/test_security_api.py @@ -51,7 +51,15 @@ def _create_test_user( user.username = username user.email = email user.roles = roles - user.password = generate_password_hash(password) + user.password = generate_password_hash( + password=password, + method=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_METHOD", "scrypt" + ), + salt_length=self.appbuilder.get_app.config.get( + "FAB_PASSWORD_HASH_SALT_LENGTH", 16 + ), + ) self.session.commit() return user