From 8c32da7f19ef613b136288a1a8f9a4ab06433c09 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sat, 15 May 2021 18:24:03 +0200 Subject: [PATCH] Let authenticators provide username and password separately --- CONFIG.md | 2 +- PFERD/authenticator.py | 8 +++++++ PFERD/authenticators/simple.py | 42 ++++++++++++++++++---------------- PFERD/crawlers/ilias.py | 2 +- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index 11c4282..ca6d92b 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -93,7 +93,7 @@ auth = auth:example ## The `auth:*` sections Sections whose names start with `auth:` are used to configure authenticators. An -authenticator provides login credentials to one or more crawlers. +authenticator provides a username and a password to one or more crawlers. Authenticators work similar to crawlers: A section represents an authenticator instance, whose name is the rest of the section name. The type is specified by diff --git a/PFERD/authenticator.py b/PFERD/authenticator.py index b2f6164..7475e2a 100644 --- a/PFERD/authenticator.py +++ b/PFERD/authenticator.py @@ -42,6 +42,14 @@ class Authenticator(ABC): async def credentials(self) -> Tuple[str, str]: pass + async def username(self) -> str: + username, _ = await self.credentials() + return username + + async def password(self) -> str: + _, password = await self.credentials() + return password + def invalidate_credentials(self) -> None: """ Tell the authenticator that some or all of its credentials are invalid. diff --git a/PFERD/authenticators/simple.py b/PFERD/authenticators/simple.py index 6ce6265..f21661c 100644 --- a/PFERD/authenticators/simple.py +++ b/PFERD/authenticators/simple.py @@ -24,44 +24,46 @@ class SimpleAuthenticator(Authenticator): ) -> None: super().__init__(name, section, config, conductor) - self.username = section.username() - self.password = section.password() + self._username = section.username() + self._password = section.password() - self.username_fixed = self.username is not None - self.password_fixed = self.password is not None + self._username_fixed = self.username is not None + self._password_fixed = self.password is not None async def credentials(self) -> Tuple[str, str]: - if self.username is not None and self.password is not None: - return self.username, self.password + if self._username is not None and self._password is not None: + return self._username, self._password async with self.conductor.exclusive_output(): - if self.username is None: - self.username = await ainput("Username: ") + if self._username is None: + self._username = await ainput("Username: ") else: print(f"Username: {self.username}") - if self.password is None: - self.password = await agetpass("Password: ") + if self._password is None: + self._password = await agetpass("Password: ") - return self.username, self.password + # Intentionally returned inside the context manager so we know + # they're both not None + return self._username, self._password def invalidate_credentials(self) -> None: - if self.username_fixed and self.password_fixed: + if self._username_fixed and self._password_fixed: raise AuthException("Configured credentials are invalid") - if not self.username_fixed: - self.username = None - if not self.password_fixed: - self.password = None + if not self._username_fixed: + self._username = None + if not self._password_fixed: + self._password = None def invalidate_username(self) -> None: - if self.username_fixed: + if self._username_fixed: raise AuthException("Configured username is invalid") else: - self.username = None + self._username = None def invalidate_password(self) -> None: - if self.password_fixed: + if self._password_fixed: raise AuthException("Configured password is invalid") else: - self.password = None + self._password = None diff --git a/PFERD/crawlers/ilias.py b/PFERD/crawlers/ilias.py index ed3fd9c..2352945 100644 --- a/PFERD/crawlers/ilias.py +++ b/PFERD/crawlers/ilias.py @@ -177,7 +177,7 @@ class KitShibbolethLogin: if not self._tfa_auth: raise RuntimeError("No 'tfa_auth' present but you use two-factor authentication!") - _, tfa_token = await self._tfa_auth.credentials() + tfa_token = await self._tfa_auth.password() # Searching the form here so that this fails before asking for # credentials rather than after asking.