Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

feat: add hooking point for AUTHORIZE #339

Merged
merged 3 commits into from
Oct 5, 2020
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
1 change: 1 addition & 0 deletions changes/339.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add hooking point for AUTHORIZE with FIRST_COMPLETED requirement.
29 changes: 26 additions & 3 deletions src/ai/backend/gateway/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from ai.backend.common.logging import Logger, BraceStyleAdapter
from ai.backend.common.plugin.hook import (
ALL_COMPLETED,
FIRST_COMPLETED,
PASSED,
)
from .exceptions import (
Expand Down Expand Up @@ -537,9 +538,31 @@ async def authorize(request: web.Request, params: Any) -> web.Response:
raise InvalidAPIParameters('Unsupported authorization type')
log.info('AUTH.AUTHORIZE(d:{0[domain]}, u:{0[username]}, passwd:****, type:{0[type]})', params)
dbpool = request.app['dbpool']
user = await check_credential(
dbpool,
params['domain'], params['username'], params['password'])

# [Hooking point for AUTHORIZE with the FIRST_COMPLETED requirement]
# The hook handlers should accept the whole ``params`` dict, and optional
# ``dbpool`` parameter (if the hook needs to query to database).
# They should return a corresponding Backend.AI user object after performing
# their own authentication steps, like LDAP authentication, etc.
params['dbpool'] = dbpool # hack to execute db commands in the hook (TODO: more general logic)
hook_result = await request.app['hook_plugin_ctx'].dispatch(
'AUTHORIZE',
(params, dbpool),
return_when=FIRST_COMPLETED,
)
if hook_result.status != PASSED:
# Did not pass AUTHORIZED hook
reason = hook_result.reason
raise RejectedByHook(extra_msg=reason)
elif 'user' in ChainMap(*hook_result.result):
# Passed one of AUTHORIZED hook
user = ChainMap(*hook_result.result)['user']
else:
# No AUTHORIZE hook is defined (proceed with normal login)
user = await check_credential(
dbpool,
params['domain'], params['username'], params['password']
)
if user is None:
raise AuthorizationFailed('User credential mismatch.')
if user.get('status') == UserStatus.BEFORE_VERIFICATION:
Expand Down