Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 8 additions & 21 deletions slack_bolt/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ def __init__(
# for the OAuth flow
oauth_settings: Optional[OAuthSettings] = None,
oauth_flow: Optional[OAuthFlow] = None,
authorization_test_enabled: bool = True,
# No need to set (the value is used only in response to ssl_check requests)
verification_token: Optional[str] = None,
):
Expand All @@ -93,8 +92,6 @@ def __init__(
:param oauth_settings: The settings related to Slack app installation flow (OAuth flow)
:param oauth_flow: Manually instantiated slack_bolt.oauth.OAuthFlow.
This is always prioritized over oauth_settings.
:param authorization_test_enabled: Set False if you want to skip auth.test calls
for every single incoming request from Slack (default: True)
:param verification_token: Deprecated verification mechanism.
This can used only for ssl_check requests.
"""
Expand Down Expand Up @@ -129,7 +126,6 @@ def __init__(
self._installation_store: Optional[InstallationStore] = installation_store

self._oauth_flow: Optional[OAuthFlow] = None
self._authorization_test_enabled = authorization_test_enabled
if oauth_flow:
self._oauth_flow = oauth_flow
if self._installation_store is None:
Expand Down Expand Up @@ -176,27 +172,18 @@ def _init_middleware_list(self):

if self._oauth_flow is None:
if self._token:
if self._authorization_test_enabled:
self._middleware_list.append(SingleTeamAuthorization())
else:
try:
auth_test_result = self._client.auth_test(token=self._token)
self._middleware_list.append(
SingleTeamAuthorization(
auth_test_result=auth_test_result,
verification_enabled=self._authorization_test_enabled,
)
)
except SlackApiError as err:
raise BoltError(error_auth_test_failure(err.response))
try:
auth_test_result = self._client.auth_test(token=self._token)
self._middleware_list.append(
SingleTeamAuthorization(auth_test_result=auth_test_result)
)
except SlackApiError as err:
raise BoltError(error_auth_test_failure(err.response))
else:
raise BoltError(error_token_required())
else:
self._middleware_list.append(
MultiTeamsAuthorization(
installation_store=self._installation_store,
verification_enabled=self._authorization_test_enabled,
)
MultiTeamsAuthorization(installation_store=self._installation_store)
)
self._middleware_list.append(IgnoringSelfEvents())
self._middleware_list.append(UrlVerification())
Expand Down
14 changes: 2 additions & 12 deletions slack_bolt/app/async_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ def __init__(
# for the OAuth flow
oauth_settings: Optional[AsyncOAuthSettings] = None,
oauth_flow: Optional[AsyncOAuthFlow] = None,
authorization_test_enabled: bool = True,
# No need to set (the value is used only in response to ssl_check requests)
verification_token: Optional[str] = None,
):
Expand All @@ -101,8 +100,6 @@ def __init__(
:param oauth_settings: The settings related to Slack app installation flow (OAuth flow)
:param oauth_flow: Manually instantiated slack_bolt.oauth.async_oauth_flow.AsyncOAuthFlow.
This is always prioritized over oauth_settings.
:param authorization_test_enabled: Set False if you want to skip auth.test calls
for every single incoming request from Slack (default: True)
:param verification_token: Deprecated verification mechanism.
This can used only for ssl_check requests.
"""
Expand Down Expand Up @@ -134,8 +131,6 @@ def __init__(
# NOTE: the token here can be None
self._async_client = create_async_web_client(token)

self._authorization_test_enabled = authorization_test_enabled

self._async_installation_store: Optional[
AsyncInstallationStore
] = installation_store
Expand Down Expand Up @@ -188,18 +183,13 @@ def _init_async_middleware_list(self):
)
if self._async_oauth_flow is None:
if self._token:
self._async_middleware_list.append(
AsyncSingleTeamAuthorization(
verification_enabled=self._authorization_test_enabled
)
)
self._async_middleware_list.append(AsyncSingleTeamAuthorization())

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid depending on a specific event loop here, we don't do a blocking operation here (NOTE: __init__ is not an async function. We cannot have await here).

else:
raise BoltError(error_token_required())
else:
self._async_middleware_list.append(
AsyncMultiTeamsAuthorization(
installation_store=self._async_installation_store,
verification_enabled=self._authorization_test_enabled,
installation_store=self._async_installation_store
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,12 @@ class AsyncMultiTeamsAuthorization(AsyncAuthorization):
installation_store: AsyncInstallationStore
verification_enabled: bool

def __init__(
self,
installation_store: AsyncInstallationStore,
verification_enabled: bool = True,
):
def __init__(self, installation_store: AsyncInstallationStore):
"""Multi-workspace authorization.

:param installation_store: The module offering find/save operations of installation data.
:param verification_enabled:
Calls auth.test for every single incoming request from Slack if True (Default: True)
"""
self.installation_store = installation_store
self.verification_enabled = verification_enabled
self.logger = get_bolt_logger(AsyncMultiTeamsAuthorization)

async def async_process(
Expand All @@ -50,36 +43,23 @@ async def async_process(
if bot is None:
return _build_error_response()

if self.verification_enabled:
auth_result = await req.context.client.auth_test(token=bot.bot_token)
if auth_result:
req.context["authorization_result"] = AuthorizationResult(
enterprise_id=auth_result.get("enterprise_id", None),
team_id=auth_result.get("team_id", None),
bot_user_id=auth_result.get("user_id", None),
bot_id=auth_result.get("bot_id", None),
bot_token=bot.bot_token,
)
# TODO: bot -> user token
req.context["token"] = bot.bot_token
req.context["client"] = create_async_web_client(bot.bot_token)
return await next()
else:
# Just in case
self.logger.error("auth.test API call result is unexpectedly None")
return _build_error_response()
else:
auth_result = await req.context.client.auth_test(token=bot.bot_token)
if auth_result:
req.context["authorization_result"] = AuthorizationResult(
enterprise_id=bot.enterprise_id,
team_id=bot.team_id,
bot_user_id=bot.bot_user_id,
bot_id=bot.bot_id,
enterprise_id=auth_result.get("enterprise_id", None),
team_id=auth_result.get("team_id", None),
bot_user_id=auth_result.get("user_id", None),
bot_id=auth_result.get("bot_id", None),
bot_token=bot.bot_token,
)
# TODO: bot -> user token
req.context["token"] = bot.bot_token
req.context["client"] = create_async_web_client(bot.bot_token)
return await next()
else:
# Just in case
self.logger.error("auth.test API call result is unexpectedly None")
return _build_error_response()

except SlackApiError as e:
self.logger.error(f"Failed to authorize with the given token ({e})")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,8 @@


class AsyncSingleTeamAuthorization(AsyncAuthorization):
def __init__(self, *, verification_enabled: bool = True):
"""Single-workspace authorization.

:param verification_enabled:
Calls auth.test for every single incoming request from Slack if True (Default: True)
"""
self.verification_enabled = verification_enabled
def __init__(self):
"""Single-workspace authorization."""
self.auth_result: Optional[AsyncSlackResponse] = None
self.logger = get_bolt_logger(AsyncSingleTeamAuthorization)

Expand All @@ -32,20 +27,12 @@ async def async_process(
return await next()

try:
if not self.verification_enabled:
if self.auth_result is None:
self.auth_result = await req.context.client.auth_test()
req.context["authorization_result"] = _to_authorization_result(
auth_test_result=self.auth_result,
bot_token=req.context.client.token,
request_user_id=req.context.user_id,
)
return await next()
if self.auth_result is None:
self.auth_result = await req.context.client.auth_test()

auth_result = await req.context.client.auth_test()
if auth_result:
if self.auth_result:
req.context["authorization_result"] = _to_authorization_result(
auth_test_result=auth_result,
auth_test_result=self.auth_result,
bot_token=req.context.client.token,
request_user_id=req.context.user_id,
)
Expand Down
40 changes: 11 additions & 29 deletions slack_bolt/middleware/authorization/multi_teams_authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,12 @@ class MultiTeamsAuthorization(Authorization):
installation_store: InstallationStore
verification_enabled: bool

def __init__(
self, installation_store: InstallationStore, verification_enabled: bool = True,
):
def __init__(self, installation_store: InstallationStore):
"""Multi-workspace authorization.

:param installation_store: The module offering find/save operations of installation data.
:param verification_enabled:
Calls auth.test for every single incoming request from Slack if True (Default: True)
"""
self.installation_store = installation_store
self.verification_enabled = verification_enabled
self.logger = get_bolt_logger(MultiTeamsAuthorization)

def process(
Expand All @@ -40,36 +35,23 @@ def process(
if bot is None:
return _build_error_response()

if self.verification_enabled:
auth_result = req.context.client.auth_test(token=bot.bot_token)
if auth_result:
req.context["authorization_result"] = AuthorizationResult(
enterprise_id=auth_result.get("enterprise_id", None),
team_id=auth_result.get("team_id", None),
bot_user_id=auth_result.get("user_id", None),
bot_id=auth_result.get("bot_id", None),
bot_token=bot.bot_token,
)
# TODO: bot -> user token
req.context["token"] = bot.bot_token
req.context["client"] = create_web_client(bot.bot_token)
return next()
else:
# Just in case
self.logger.error("auth.test API call result is unexpectedly None")
return _build_error_response()
else:
auth_result = req.context.client.auth_test(token=bot.bot_token)
if auth_result:
req.context["authorization_result"] = AuthorizationResult(
enterprise_id=bot.enterprise_id,
team_id=bot.team_id,
bot_user_id=bot.bot_user_id,
bot_id=bot.bot_id,
enterprise_id=auth_result.get("enterprise_id", None),
team_id=auth_result.get("team_id", None),
bot_user_id=auth_result.get("user_id", None),
bot_id=auth_result.get("bot_id", None),
bot_token=bot.bot_token,
)
# TODO: bot -> user token
req.context["token"] = bot.bot_token
req.context["client"] = create_web_client(bot.bot_token)
return next()
else:
# Just in case
self.logger.error("auth.test API call result is unexpectedly None")
return _build_error_response()

except SlackApiError as e:
self.logger.error(f"Failed to authorize with the given token ({e})")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,12 @@


class SingleTeamAuthorization(Authorization):
def __init__(
self,
*,
auth_test_result: Optional[SlackResponse] = None,
verification_enabled: bool = True,
):
def __init__(self, *, auth_test_result: Optional[SlackResponse] = None):
"""Single-workspace authorization.

:param auth_test_result: The initial `auth.test` API call result.
:param verification_enabled:
Calls auth.test for every single incoming request from Slack if True (Default: True)
"""
self.auth_test_result = auth_test_result
self.verification_enabled = verification_enabled
self.logger = get_bolt_logger(SingleTeamAuthorization)

def process(
Expand All @@ -36,20 +28,13 @@ def process(
if _is_no_auth_required(req):
return next()

if not self.verification_enabled:
# Skip calling auth.test every time the app receives requests
req.context["authorization_result"] = _to_authorization_result(
auth_test_result=self.auth_test_result,
bot_token=req.context.client.token,
request_user_id=req.context.user_id,
)
return next()

try:
auth_result = req.context.client.auth_test()
if auth_result:
if not self.auth_test_result:
self.auth_test_result = req.context.client.auth_test()

if self.auth_test_result:
req.context["authorization_result"] = _to_authorization_result(
auth_test_result=auth_result,
auth_test_result=self.auth_test_result,
bot_token=req.context.client.token,
request_user_id=req.context.user_id,
)
Expand Down
17 changes: 10 additions & 7 deletions tests/adapter_tests/test_bottle.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
from time import time
from typing import Optional
from urllib.parse import quote

from slack_sdk.signature import SignatureVerifier
Expand All @@ -16,22 +17,16 @@
signing_secret = "secret"
valid_token = "xoxb-valid"
mock_api_server_base_url = "http://localhost:8888"
web_client = WebClient(token=valid_token, base_url=mock_api_server_base_url,)
app = App(client=web_client, signing_secret=signing_secret,)
handler = SlackRequestHandler(app)


@app.event("app_mention")
def event_handler():
pass


@app.shortcut("test-shortcut")
def shortcut_handler(ack):
ack()


@app.command("/hello-world")
def command_handler(ack):
ack()

Expand All @@ -42,16 +37,24 @@ def command_handler(ack):

@post("/slack/events")
def slack_events():
return handler.handle(request, response)
return TestBottle.handler.handle(request, response)


class TestBottle:
signature_verifier = SignatureVerifier(signing_secret)
handler: Optional[SlackRequestHandler] = None

def setup_method(self):
self.old_os_env = remove_os_env_temporarily()
setup_mock_web_api_server(self)

web_client = WebClient(token=valid_token, base_url=mock_api_server_base_url,)
app = App(client=web_client, signing_secret=signing_secret,)
TestBottle.handler = SlackRequestHandler(app)
app.event("app_mention")(event_handler)
app.shortcut("test-shortcut")(shortcut_handler)
app.command("/hello-world")(command_handler)

def teardown_method(self):
cleanup_mock_web_api_server(self)
restore_os_env(self.old_os_env)
Expand Down
Loading