diff options
author | Devaev Maxim <[email protected]> | 2019-04-27 05:16:00 +0300 |
---|---|---|
committer | Devaev Maxim <[email protected]> | 2019-04-27 05:16:00 +0300 |
commit | 493d160a6e87120b9f57493cc594f487ef140e90 (patch) | |
tree | 12344ac01b7d36a6055b4d22849e335decee2df6 /kvmd | |
parent | 3476f52da9728995c978394748cec812d554ec2f (diff) |
single-shot auth using headers
Diffstat (limited to 'kvmd')
-rw-r--r-- | kvmd/apps/kvmd/auth.py | 19 | ||||
-rw-r--r-- | kvmd/apps/kvmd/server.py | 22 | ||||
-rw-r--r-- | kvmd/plugins/auth/__init__.py | 2 | ||||
-rw-r--r-- | kvmd/plugins/auth/htpasswd.py | 2 | ||||
-rw-r--r-- | kvmd/plugins/auth/http.py | 2 |
5 files changed, 34 insertions, 13 deletions
diff --git a/kvmd/apps/kvmd/auth.py b/kvmd/apps/kvmd/auth.py index d90202c3..0753f176 100644 --- a/kvmd/apps/kvmd/auth.py +++ b/kvmd/apps/kvmd/auth.py @@ -47,33 +47,40 @@ class AuthManager: ) -> None: self.__internal_service = get_auth_service_class(internal_type)(**internal_kwargs) - get_logger().info("Using internal login service %r", self.__internal_service.PLUGIN_NAME) + get_logger().info("Using internal auth service %r", self.__internal_service.PLUGIN_NAME) self.__external_service: Optional[BaseAuthService] = None if external_type: self.__external_service = get_auth_service_class(external_type)(**external_kwargs) - get_logger().info("Using external login service %r", self.__external_service.PLUGIN_NAME) + get_logger().info("Using external auth service %r", self.__external_service.PLUGIN_NAME) self.__internal_users = internal_users self.__tokens: Dict[str, str] = {} # {token: user} - async def login(self, user: str, passwd: str) -> Optional[str]: + async def authorize(self, user: str, passwd: str) -> bool: if user not in self.__internal_users and self.__external_service: service = self.__external_service else: service = self.__internal_service - if (await service.login(user, passwd)): + ok = (await service.authorize(user, passwd)) + if ok: + get_logger().info("Authorized user %r via auth service %r", user, service.PLUGIN_NAME) + else: + get_logger().error("Got access denied for user %r from auth service %r", user, service.PLUGIN_NAME) + return ok + + async def login(self, user: str, passwd: str) -> Optional[str]: + if (await self.authorize(user, passwd)): for (token, token_user) in self.__tokens.items(): if user == token_user: return token token = secrets.token_hex(32) self.__tokens[token] = user - get_logger().info("Logged in user %r via login service %r", user, service.PLUGIN_NAME) + get_logger().info("Logged in user %r", user) return token else: - get_logger().error("Access denied for user %r from login service %r", user, service.PLUGIN_NAME) return None def logout(self, token: str) -> None: diff --git a/kvmd/apps/kvmd/server.py b/kvmd/apps/kvmd/server.py index b9497d17..c8e686db 100644 --- a/kvmd/apps/kvmd/server.py +++ b/kvmd/apps/kvmd/server.py @@ -82,11 +82,11 @@ except ImportError: from aiohttp.helpers import AccessLogger # type: ignore # pylint: disable=ungrouped-imports -_ATTR_KVMD_USER = "kvmd_user" +_ATTR_KVMD_AUTH_INFO = "kvmd_auth_info" def _format_P(request: aiohttp.web.BaseRequest, *_, **__) -> str: # type: ignore # pylint: disable=invalid-name - return (getattr(request, _ATTR_KVMD_USER, None) or "-") + return (getattr(request, _ATTR_KVMD_AUTH_INFO, None) or "-") AccessLogger._format_P = staticmethod(_format_P) # type: ignore # pylint: disable=protected-access @@ -148,6 +148,9 @@ _ATTR_EXPOSED_METHOD = "exposed_method" _ATTR_EXPOSED_PATH = "exposed_path" _ATTR_SYSTEM_TASK = "system_task" +_HEADER_AUTH_USER = "X-KVMD-User" +_HEADER_AUTH_PASSWD = "X-KVMD-Passwd" + _COOKIE_AUTH_TOKEN = "auth_token" @@ -156,12 +159,23 @@ def _exposed(http_method: str, path: str, auth_required: bool=True) -> Callable: async def wrap(self: "Server", request: aiohttp.web.Request) -> aiohttp.web.Response: try: if auth_required: + user = request.headers.get(_HEADER_AUTH_USER, "") + passwd = request.headers.get(_HEADER_AUTH_PASSWD, "") token = request.cookies.get(_COOKIE_AUTH_TOKEN, "") - if token: + + if user: + user = valid_user(user) + setattr(request, _ATTR_KVMD_AUTH_INFO, "%s (xhdr)" % (user)) + if not (await self._auth_manager.authorize(user, valid_passwd(passwd))): + raise ForbiddenError("Forbidden") + + elif token: user = self._auth_manager.check(valid_auth_token(token)) if not user: + setattr(request, _ATTR_KVMD_AUTH_INFO, "- (token)") raise ForbiddenError("Forbidden") - setattr(request, _ATTR_KVMD_USER, user) + setattr(request, _ATTR_KVMD_AUTH_INFO, "%s (token)" % (user)) + else: raise UnauthorizedError("Unauthorized") diff --git a/kvmd/plugins/auth/__init__.py b/kvmd/plugins/auth/__init__.py index 3bc40372..18f7ed6b 100644 --- a/kvmd/plugins/auth/__init__.py +++ b/kvmd/plugins/auth/__init__.py @@ -28,7 +28,7 @@ from .. import get_plugin_class # ===== class BaseAuthService(BasePlugin): - async def login(self, user: str, passwd: str) -> bool: + async def authorize(self, user: str, passwd: str) -> bool: raise NotImplementedError # pragma: nocover async def cleanup(self) -> None: diff --git a/kvmd/plugins/auth/htpasswd.py b/kvmd/plugins/auth/htpasswd.py index 4c2c5e35..3e7e52d9 100644 --- a/kvmd/plugins/auth/htpasswd.py +++ b/kvmd/plugins/auth/htpasswd.py @@ -44,6 +44,6 @@ class Plugin(BaseAuthService): "file": Option("/etc/kvmd/htpasswd", type=valid_abs_path_exists, unpack_as="path"), } - async def login(self, user: str, passwd: str) -> bool: + async def authorize(self, user: str, passwd: str) -> bool: htpasswd = passlib.apache.HtpasswdFile(self.__path) return htpasswd.check_password(user, passwd) diff --git a/kvmd/plugins/auth/http.py b/kvmd/plugins/auth/http.py index 18ecaae6..edd7ab96 100644 --- a/kvmd/plugins/auth/http.py +++ b/kvmd/plugins/auth/http.py @@ -69,7 +69,7 @@ class Plugin(BaseAuthService): "timeout": Option(5.0, type=valid_float_f01), } - async def login(self, user: str, passwd: str) -> bool: + async def authorize(self, user: str, passwd: str) -> bool: session = self.__ensure_session() try: async with session.request( |