Skip to content

Commit 72b8e8b

Browse files
shubhamraj-gitpotiuk
authored andcommitted
[providers-fab/v1-5] Invalidate user session on password reset (apache#45139)
* session expire on pass change * fix statis checks * add tests (cherry picked from commit cf401c4) Co-authored-by: Shubham Raj <[email protected]>
1 parent 7a07994 commit 72b8e8b

File tree

3 files changed

+65
-2
lines changed

3 files changed

+65
-2
lines changed

providers/src/airflow/providers/fab/auth_manager/cli_commands/utils.py

+12
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@
2626

2727
import airflow
2828
from airflow.configuration import conf
29+
from airflow.exceptions import AirflowConfigException
30+
from airflow.www.app import isabs, make_url
2931
from airflow.www.extensions.init_appbuilder import init_appbuilder
32+
from airflow.www.extensions.init_session import init_airflow_session_interface
3033
from airflow.www.extensions.init_views import init_plugins
3134

3235
if TYPE_CHECKING:
@@ -38,6 +41,7 @@ def _return_appbuilder(app: Flask) -> AirflowAppBuilder:
3841
"""Return an appbuilder instance for the given app."""
3942
init_appbuilder(app)
4043
init_plugins(app)
44+
init_airflow_session_interface(app)
4145
return app.appbuilder # type: ignore[attr-defined]
4246

4347

@@ -49,4 +53,12 @@ def get_application_builder() -> Generator[AirflowAppBuilder, None, None]:
4953
with flask_app.app_context():
5054
# Enable customizations in webserver_config.py to be applied via Flask.current_app.
5155
flask_app.config.from_pyfile(webserver_config, silent=True)
56+
flask_app.config["SQLALCHEMY_DATABASE_URI"] = conf.get("database", "SQL_ALCHEMY_CONN")
57+
url = make_url(flask_app.config["SQLALCHEMY_DATABASE_URI"])
58+
if url.drivername == "sqlite" and url.database and not isabs(url.database):
59+
raise AirflowConfigException(
60+
f'Cannot use relative path: `{conf.get("database", "SQL_ALCHEMY_CONN")}` to connect to sqlite. '
61+
"Please use absolute path such as `sqlite:////tmp/airflow.db`."
62+
)
63+
flask_app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
5264
yield _return_appbuilder(flask_app)

providers/src/airflow/providers/fab/auth_manager/security_manager/override.py

+1
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,7 @@ def reset_user_sessions(self, user: User) -> None:
576576
session_details = interface.serializer.loads(want_bytes(s.data))
577577
if session_details.get("_user_id") == user.id:
578578
session.delete(s)
579+
session.commit()
579580
else:
580581
self._cli_safe_flash(
581582
"Since you are using `securecookie` session backend mechanism, we cannot prevent "

providers/tests/fab/auth_manager/cli_commands/test_utils.py

+52-2
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,69 @@
1616
# under the License.
1717
from __future__ import annotations
1818

19+
import os
20+
1921
import pytest
2022

23+
import airflow
24+
from airflow.configuration import conf
25+
from airflow.exceptions import AirflowConfigException
26+
from airflow.www.extensions.init_appbuilder import AirflowAppBuilder
27+
from airflow.www.session import AirflowDatabaseSessionInterface
28+
2129
from tests_common.test_utils.compat import ignore_provider_compatibility_error
30+
from tests_common.test_utils.config import conf_vars
2231

2332
with ignore_provider_compatibility_error("2.9.0+", __file__):
2433
from airflow.providers.fab.auth_manager.cli_commands.utils import get_application_builder
2534

26-
from airflow.www.extensions.init_appbuilder import AirflowAppBuilder
27-
2835
pytestmark = pytest.mark.db_test
2936

3037

38+
@pytest.fixture
39+
def flask_app():
40+
"""Fixture to set up the Flask app with the necessary configuration."""
41+
# Get the webserver config file path
42+
webserver_config = conf.get_mandatory_value("webserver", "config_file")
43+
44+
with get_application_builder() as appbuilder:
45+
flask_app = appbuilder.app
46+
47+
# Load webserver configuration
48+
flask_app.config.from_pyfile(webserver_config, silent=True)
49+
50+
yield flask_app
51+
52+
3153
class TestCliUtils:
3254
def test_get_application_builder(self):
55+
"""Test that get_application_builder returns an AirflowAppBuilder instance."""
3356
with get_application_builder() as appbuilder:
3457
assert isinstance(appbuilder, AirflowAppBuilder)
58+
59+
def test_sqlalchemy_uri_configured(self, flask_app):
60+
"""Test that the SQLALCHEMY_DATABASE_URI is correctly set in the Flask app."""
61+
sqlalchemy_uri = conf.get("database", "SQL_ALCHEMY_CONN")
62+
63+
# Assert that the SQLAlchemy URI is correctly set
64+
assert sqlalchemy_uri == flask_app.config["SQLALCHEMY_DATABASE_URI"]
65+
66+
def test_relative_path_sqlite_raises_exception(self):
67+
"""Test that a relative SQLite path raises an AirflowConfigException."""
68+
# Directly simulate the configuration for relative SQLite path
69+
with conf_vars({("database", "SQL_ALCHEMY_CONN"): "sqlite://relative/path"}):
70+
with pytest.raises(AirflowConfigException, match="Cannot use relative path"):
71+
with get_application_builder():
72+
pass
73+
74+
def test_static_folder_exists(self, flask_app):
75+
"""Test that the static folder is correctly configured in the Flask app."""
76+
static_folder = os.path.join(os.path.dirname(airflow.__file__), "www", "static")
77+
assert flask_app.static_folder == static_folder
78+
79+
def test_database_auth_backend_in_session(self, flask_app):
80+
"""Test that the database is used for session management when AUTH_BACKEND is set to 'database'."""
81+
with get_application_builder() as appbuilder:
82+
flask_app = appbuilder.app
83+
# Ensure that the correct session interface is set (for 'database' auth backend)
84+
assert isinstance(flask_app.session_interface, AirflowDatabaseSessionInterface)

0 commit comments

Comments
 (0)