This is an automated email from the ASF dual-hosted git repository. michaelsmolina pushed a commit to branch 5.0 in repository https://gitbox.apache.org/repos/asf/superset.git
commit 5f1a5a1f9848d72f083330282541e86df7ffaae7 Author: Beto Dealmeida <[email protected]> AuthorDate: Tue Mar 4 13:33:53 2025 -0500 fix: skip DB filter when doing OAuth2 (#32486) (cherry picked from commit 813e79fa9fcba502fc55d21a84c0628e1bb42493) --- superset/databases/api.py | 2 +- tests/unit_tests/databases/api_test.py | 70 ++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/superset/databases/api.py b/superset/databases/api.py index f9c1dfd122..f47293e891 100644 --- a/superset/databases/api.py +++ b/superset/databases/api.py @@ -1390,7 +1390,7 @@ class DatabaseRestApi(BaseSupersetModelRestApi): state = decode_oauth2_state(parameters["state"]) # exchange code for access/refresh tokens - database = DatabaseDAO.find_by_id(state["database_id"]) + database = DatabaseDAO.find_by_id(state["database_id"], skip_base_filter=True) if database is None: return self.response_404() diff --git a/tests/unit_tests/databases/api_test.py b/tests/unit_tests/databases/api_test.py index 63d61ce82a..4656ea9b86 100644 --- a/tests/unit_tests/databases/api_test.py +++ b/tests/unit_tests/databases/api_test.py @@ -728,6 +728,76 @@ def test_oauth2_happy_path( assert token.refresh_token == "ZZZ" # noqa: S105 +def test_oauth2_permissions( + mocker: MockerFixture, + session: Session, + client: Any, +) -> None: + """ + Test the OAuth2 endpoint works for users without DB permissions. + + Anyone should be able to authenticate with OAuth2, even if they don't have + permissions to read the database (which is needed to get the OAuth2 config). + """ + from superset.databases.api import DatabaseRestApi + from superset.models.core import Database, DatabaseUserOAuth2Tokens + + DatabaseRestApi.datamodel.session = session + + # create table for databases + Database.metadata.create_all(session.get_bind()) # pylint: disable=no-member + db.session.add( + Database( + database_name="my_db", + sqlalchemy_uri="sqlite://", + uuid=UUID("7c1b7880-a59d-47cd-8bf1-f1eb8d2863cb"), + ) + ) + db.session.commit() + + mocker.patch.object( + SqliteEngineSpec, + "get_oauth2_config", + return_value={"id": "one", "secret": "two"}, + ) + get_oauth2_token = mocker.patch.object(SqliteEngineSpec, "get_oauth2_token") + get_oauth2_token.return_value = { + "access_token": "YYY", + "expires_in": 3600, + "refresh_token": "ZZZ", + } + + state = { + "user_id": 1, + "database_id": 1, + "tab_id": 42, + } + decode_oauth2_state = mocker.patch("superset.databases.api.decode_oauth2_state") + decode_oauth2_state.return_value = state + + mocker.patch("superset.databases.api.render_template", return_value="OK") + + with freeze_time("2024-01-01T00:00:00Z"): + response = client.get( + "/api/v1/database/oauth2/", + query_string={ + "state": "some%2Estate", + "code": "XXX", + }, + ) + + assert response.status_code == 200 + decode_oauth2_state.assert_called_with("some%2Estate") + get_oauth2_token.assert_called_with({"id": "one", "secret": "two"}, "XXX") + + token = db.session.query(DatabaseUserOAuth2Tokens).one() + assert token.user_id == 1 + assert token.database_id == 1 + assert token.access_token == "YYY" # noqa: S105 + assert token.access_token_expiration == datetime(2024, 1, 1, 1, 0) + assert token.refresh_token == "ZZZ" # noqa: S105 + + def test_oauth2_multiple_tokens( mocker: MockerFixture, session: Session,
