From 76962667a35d03b9dabed123b7cd761e08708b0e Mon Sep 17 00:00:00 2001 From: allegroai <> Date: Tue, 9 Jul 2019 00:04:43 +0300 Subject: [PATCH] Add fixed user list support --- server/service_repo/auth/auth.py | 13 ++++++++- server/service_repo/auth/fixed_user.py | 38 ++++++++++++++++++++++++++ server/services/auth.py | 8 +++++- 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 server/service_repo/auth/fixed_user.py diff --git a/server/service_repo/auth/auth.py b/server/service_repo/auth/auth.py index 8ea6c33..49ead13 100644 --- a/server/service_repo/auth/auth.py +++ b/server/service_repo/auth/auth.py @@ -1,5 +1,6 @@ import base64 import jwt +from mongoengine import Q from database.errors import translate_errors_context from database.model.company import Company @@ -11,6 +12,7 @@ from timing_context import TimingContext from .payload import Payload, Token, Basic, AuthType from .identity import Identity +from .fixed_user import FixedUser log = config.logger(__file__) @@ -54,8 +56,17 @@ def authorize_credentials(auth_data, service, action, call_data_items): log.exception('malformed credentials') raise errors.unauthorized.BadCredentials(str(e)) + query = Q(credentials__match=Credentials(key=access_key, secret=secret_key)) + + if FixedUser.enabled(): + fixed_user = FixedUser.get_by_username(access_key) + if fixed_user: + if secret_key != fixed_user.password: + raise errors.unauthorized.InvalidCredentials('bad username or password') + query = Q(id=fixed_user.user_id) + with TimingContext("mongo", "user_by_cred"), translate_errors_context('authorizing request'): - user = User.objects(credentials__match=Credentials(key=access_key, secret=secret_key)).first() + user = User.objects(query).first() if not user: raise errors.unauthorized.InvalidCredentials('failed to locate provided credentials') diff --git a/server/service_repo/auth/fixed_user.py b/server/service_repo/auth/fixed_user.py new file mode 100644 index 0000000..803b305 --- /dev/null +++ b/server/service_repo/auth/fixed_user.py @@ -0,0 +1,38 @@ +import hashlib +from functools import lru_cache +from typing import Sequence, TypeVar + +import attr + +from config import config + +T = TypeVar("T", bound="FixedUser") + + +@attr.s(auto_attribs=True) +class FixedUser: + username: str + password: str + name: str + + def __attrs_post_init__(self): + self.user_id = hashlib.md5(f"{self.username}:{self.password}".encode()).hexdigest() + + @classmethod + def enabled(self): + return config.get("apiserver.auth.fixed_users.enabled", False) + + @classmethod + @lru_cache() + def from_config(cls) -> Sequence[T]: + return [cls(**user) for user in config.get("apiserver.auth.fixed_users.users", [])] + + @classmethod + @lru_cache() + def get_by_username(cls, username) -> T: + return next( + (user for user in cls.from_config() if user.username == username), None + ) + + def __hash__(self): + return hash(self.user_id) diff --git a/server/services/auth.py b/server/services/auth.py index 87dd20c..322c7e2 100644 --- a/server/services/auth.py +++ b/server/services/auth.py @@ -20,7 +20,8 @@ from config import config from database.errors import translate_errors_context from database.model.auth import User from service_repo import APICall, endpoint -from service_repo.auth import Token, AuthType +from service_repo.auth import Token +from service_repo.auth.fixed_user import FixedUser log = config.logger(__file__) @@ -167,3 +168,8 @@ def update(call, company_id, _): call.result.data_model = UpdateResponse( updated=result.modified_count, fields=fields ) + + +@endpoint("auth.fixed_users_mode") +def fixed_users_mode(call: APICall, *_, **__): + call.result.data = dict(enabled=FixedUser.enabled())