mirror of
https://github.com/Garmelon/PFERD.git
synced 2023-12-21 10:23:01 +01:00
Use system keyring service for password auth
This commit is contained in:
@ -3,8 +3,19 @@ General authenticators useful in many situations
|
||||
"""
|
||||
|
||||
import getpass
|
||||
import logging
|
||||
from typing import Optional, Tuple
|
||||
|
||||
from .logging import PrettyLogger
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
PRETTY = PrettyLogger(LOGGER)
|
||||
|
||||
try:
|
||||
import keyring
|
||||
except ImportError:
|
||||
PRETTY.warning("Keyring module not found, KeyringAuthenticator won't work!")
|
||||
|
||||
|
||||
class TfaAuthenticator:
|
||||
# pylint: disable=too-few-public-methods
|
||||
@ -123,3 +134,81 @@ class UserPassAuthenticator:
|
||||
if self._given_username is not None and self._given_password is not None:
|
||||
self._given_username = None
|
||||
self._given_password = None
|
||||
|
||||
|
||||
class KeyringAuthenticator(UserPassAuthenticator):
|
||||
"""
|
||||
An authenticator for username-password combinations that stores the
|
||||
password using the system keyring service and prompts the user for missing
|
||||
information.
|
||||
"""
|
||||
|
||||
def get_credentials(self) -> Tuple[str, str]:
|
||||
"""
|
||||
Returns a tuple (username, password). Prompts user for username or
|
||||
password when necessary.
|
||||
"""
|
||||
|
||||
if self._username is None and self._given_username is not None:
|
||||
self._username = self._given_username
|
||||
|
||||
if self._password is None and self._given_password is not None:
|
||||
self._password = self._given_password
|
||||
|
||||
if self._username is not None and self._password is None:
|
||||
self._load_password()
|
||||
|
||||
if self._username is None or self._password is None:
|
||||
print(f"Enter credentials ({self._reason})")
|
||||
|
||||
username: str
|
||||
if self._username is None:
|
||||
username = input("Username: ")
|
||||
self._username = username
|
||||
else:
|
||||
username = self._username
|
||||
|
||||
if self._password is None:
|
||||
self._load_password()
|
||||
|
||||
password: str
|
||||
if self._password is None:
|
||||
password = getpass.getpass(prompt="Password: ")
|
||||
self._password = password
|
||||
self._save_password()
|
||||
else:
|
||||
password = self._password
|
||||
|
||||
return (username, password)
|
||||
|
||||
def _load_password(self) -> None:
|
||||
"""
|
||||
Loads the saved password associated with self._username from the system
|
||||
keyring service (or None if not password has been saved yet) and stores
|
||||
it in self._password.
|
||||
"""
|
||||
self._password = keyring.get_password("pferd-ilias", self._username)
|
||||
|
||||
def _save_password(self) -> None:
|
||||
"""
|
||||
Saves self._password to the system keyring service and associates it
|
||||
with self._username.
|
||||
"""
|
||||
keyring.set_password("pferd-ilias", self._username, self._password)
|
||||
|
||||
def invalidate_credentials(self) -> None:
|
||||
"""
|
||||
Marks the credentials as invalid. If only a username was supplied in
|
||||
the constructor, assumes that the username is valid and only the
|
||||
password is invalid. If only a password was supplied in the
|
||||
constructor, assumes that the password is valid and only the username
|
||||
is invalid. Otherwise, assumes that username and password are both
|
||||
invalid.
|
||||
"""
|
||||
|
||||
try:
|
||||
keyring.delete_password("pferd-ilias", self._username)
|
||||
except keyring.errors.PasswordDeleteError:
|
||||
pass
|
||||
|
||||
super().invalidate_credentials()
|
||||
|
@ -2,7 +2,8 @@
|
||||
Synchronizing files from ILIAS instances (https://www.ilias.de/).
|
||||
"""
|
||||
|
||||
from .authenticators import IliasAuthenticator, KitShibbolethAuthenticator
|
||||
from .authenticators import (IliasAuthenticator, KitShibbolethAuthenticator,
|
||||
KeyringKitShibbolethAuthenticator)
|
||||
from .crawler import (IliasCrawler, IliasCrawlerEntry, IliasDirectoryFilter,
|
||||
IliasElementType)
|
||||
from .downloader import (IliasDownloader, IliasDownloadInfo,
|
||||
|
@ -37,8 +37,12 @@ class KitShibbolethAuthenticator(IliasAuthenticator):
|
||||
Authenticate via KIT's shibboleth system.
|
||||
"""
|
||||
|
||||
def __init__(self, username: Optional[str] = None, password: Optional[str] = None) -> None:
|
||||
self._auth = UserPassAuthenticator("KIT ILIAS Shibboleth", username, password)
|
||||
def __init__(self, authenticator: Optional[UserPassAuthenticator] = None) -> None:
|
||||
if authenticator:
|
||||
self._auth = authenticator
|
||||
else:
|
||||
self._auth = UserPassAuthenticator("KIT ILIAS Shibboleth")
|
||||
|
||||
self._tfa_auth = TfaAuthenticator("KIT ILIAS Shibboleth")
|
||||
|
||||
def authenticate(self, sess: requests.Session) -> None:
|
||||
|
Reference in New Issue
Block a user