mirror of
https://github.com/clearml/clearml-server
synced 2025-01-31 10:56:48 +00:00
87 lines
3.0 KiB
Python
87 lines
3.0 KiB
Python
import base64
|
|
import jwt
|
|
|
|
from database.errors import translate_errors_context
|
|
from database.model.company import Company
|
|
from database.utils import get_options
|
|
from database.model.auth import User, Entities, Credentials
|
|
from apierrors import errors
|
|
from config import config
|
|
from timing_context import TimingContext
|
|
|
|
from .payload import Payload, Token, Basic, AuthType
|
|
from .identity import Identity
|
|
|
|
|
|
log = config.logger(__file__)
|
|
|
|
entity_keys = set(get_options(Entities))
|
|
|
|
verify_user_tokens = config.get("apiserver.auth.verify_user_tokens", True)
|
|
|
|
|
|
def get_auth_func(auth_type):
|
|
if auth_type == AuthType.bearer_token:
|
|
return authorize_token
|
|
elif auth_type == AuthType.basic:
|
|
return authorize_credentials
|
|
raise errors.unauthorized.BadAuthType()
|
|
|
|
|
|
def authorize_token(jwt_token, *_, **__):
|
|
""" Validate token against service/endpoint and requests data (dicts).
|
|
Returns a parsed token object (auth payload)
|
|
"""
|
|
try:
|
|
return Token.from_encoded_token(jwt_token)
|
|
|
|
except jwt.exceptions.InvalidKeyError as ex:
|
|
raise errors.unauthorized.InvalidToken('jwt invalid key error', reason=ex.args[0])
|
|
except jwt.InvalidTokenError as ex:
|
|
raise errors.unauthorized.InvalidToken('invalid jwt token', reason=ex.args[0])
|
|
except ValueError as ex:
|
|
log.exception('Failed while processing token: %s' % ex.args[0])
|
|
raise errors.unauthorized.InvalidToken('failed processing token', reason=ex.args[0])
|
|
|
|
|
|
def authorize_credentials(auth_data, service, action, call_data_items):
|
|
""" Validate credentials against service/action and request data (dicts).
|
|
Returns a new basic object (auth payload)
|
|
"""
|
|
try:
|
|
access_key, _, secret_key = base64.b64decode(auth_data.encode()).decode('latin-1').partition(':')
|
|
except Exception as e:
|
|
log.exception('malformed credentials')
|
|
raise errors.unauthorized.BadCredentials(str(e))
|
|
|
|
with TimingContext("mongo", "user_by_cred"), translate_errors_context('authorizing request'):
|
|
user = User.objects(credentials__match=Credentials(key=access_key, secret=secret_key)).first()
|
|
|
|
if not user:
|
|
raise errors.unauthorized.InvalidCredentials('failed to locate provided credentials')
|
|
|
|
with TimingContext("mongo", "company_by_id"):
|
|
company = Company.objects(id=user.company).only('id', 'name').first()
|
|
|
|
if not company:
|
|
raise errors.unauthorized.InvalidCredentials('invalid user company')
|
|
|
|
identity = Identity(user=user.id, company=user.company, role=user.role,
|
|
user_name=user.name, company_name=company.name)
|
|
|
|
basic = Basic(user_key=access_key, identity=identity)
|
|
|
|
return basic
|
|
|
|
|
|
def authorize_impersonation(user, identity, service, action, call_data_items):
|
|
""" Returns a new basic object (auth payload)"""
|
|
if not user:
|
|
raise ValueError('missing user')
|
|
|
|
company = Company.objects(id=user.company).only('id', 'name').first()
|
|
if not company:
|
|
raise errors.unauthorized.InvalidCredentials('invalid user company')
|
|
|
|
return Payload(auth_type=None, identity=identity)
|