import/export: Fix deprecated authentication method for Slack.

The query string parameter authentication method is now deprecated for
newly created Slack applications since the 24th of February[1].  This
causes Slack imports to fail, claiming that the token has none of the
required scopes.

Two methods can be used to solve this problem: either include the
authentication token in the header of an HTTP GET request, or include
it in the body of an HTTP POST request. The former is preferred, as
the code was already written to use HTTP GET requests.

Change the way the parameters are passed to the "requests.get" method
calls, to pass the token via the `Authorization` header.

[1] https://api.slack.com/changelog/2020-11-no-more-tokens-in-querystrings-for-newly-created-apps

Fixes: #17408.
This commit is contained in:
Cyril Pletinckx 2021-03-04 15:58:20 +01:00 committed by Alex Vandiver
parent 6b34ba048d
commit ba7da6d5c0
2 changed files with 14 additions and 8 deletions

View File

@ -1349,7 +1349,9 @@ def check_token_access(token: str) -> None:
if token.startswith("xoxp-"):
logging.info("This is a Slack user token, which grants all rights the user has!")
elif token.startswith("xoxb-"):
data = requests.get("https://slack.com/api/team.info", {"token": token})
data = requests.get(
"https://slack.com/api/team.info", headers={"Authorization": "Bearer {}".format(token)}
)
has_scopes = set(data.headers.get("x-oauth-scopes", "").split(","))
required_scopes = set(["emoji:read", "users:read", "users:read.email", "team:read"])
missing_scopes = required_scopes - has_scopes
@ -1366,7 +1368,10 @@ def check_token_access(token: str) -> None:
def get_slack_api_data(slack_api_url: str, get_param: str, **kwargs: Any) -> Any:
if not kwargs.get("token"):
raise AssertionError("Slack token missing in kwargs")
data = requests.get(slack_api_url, kwargs)
token = kwargs.pop("token")
data = requests.get(
slack_api_url, headers={"Authorization": "Bearer {}".format(token)}, **kwargs
)
if data.status_code == requests.codes.ok:
result = data.json()

View File

@ -60,14 +60,15 @@ class MockResponse:
# This method will be used by the mock to replace requests.get
def mocked_requests_get(*args: str) -> MockResponse:
if args == ("https://slack.com/api/users.list", {"token": "xoxp-valid-token"}):
return MockResponse({"ok": True, "members": "user_data"}, 200)
elif args == ("https://slack.com/api/users.list", {"token": "xoxp-invalid-token"}):
return MockResponse({"ok": False, "error": "invalid_auth"}, 200)
else:
def mocked_requests_get(*args: str, headers: Dict[str, str]) -> MockResponse:
if args != ("https://slack.com/api/users.list",):
return MockResponse(None, 404)
if (headers.get("Authorization") != "Bearer xoxp-valid-token"):
return MockResponse({"ok": False, "error": "invalid_auth"}, 200)
return MockResponse({"ok": True, "members": "user_data"}, 200)
class SlackImporter(ZulipTestCase):
@mock.patch("requests.get", side_effect=mocked_requests_get)