mirror of
https://github.com/Garmelon/PFERD.git
synced 2023-12-21 10:23:01 +01:00
Add credential file authenticator
This commit is contained in:
parent
1fba96abcb
commit
9d5ec84b91
@ -22,6 +22,9 @@ ambiguous situations.
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- `credential-file` authenticator
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Date parsing now also works correctly in non-group exercises
|
- Date parsing now also works correctly in non-group exercises
|
||||||
|
|
||||||
|
13
CONFIG.md
13
CONFIG.md
@ -180,6 +180,19 @@ via the terminal.
|
|||||||
- `username`: The username. (Optional)
|
- `username`: The username. (Optional)
|
||||||
- `password`: The password. (Optional)
|
- `password`: The password. (Optional)
|
||||||
|
|
||||||
|
### The `credential-file` authenticator
|
||||||
|
|
||||||
|
This authenticator reads a username and a password from a credential file. The
|
||||||
|
credential file has exactly two lines (trailing newline optional). The first
|
||||||
|
line starts with `username=` and contains the username, the second line starts
|
||||||
|
with `password=` and contains the password. The username and password may
|
||||||
|
contain any characters except a line break.
|
||||||
|
|
||||||
|
```
|
||||||
|
username=AzureDiamond
|
||||||
|
password=hunter2
|
||||||
|
```
|
||||||
|
|
||||||
### The `keyring` authenticator
|
### The `keyring` authenticator
|
||||||
|
|
||||||
This authenticator uses the system keyring to store passwords. The username can
|
This authenticator uses the system keyring to store passwords. The username can
|
||||||
|
@ -3,6 +3,7 @@ from typing import Callable, Dict
|
|||||||
|
|
||||||
from ..config import Config
|
from ..config import Config
|
||||||
from .authenticator import Authenticator, AuthError, AuthSection # noqa: F401
|
from .authenticator import Authenticator, AuthError, AuthSection # noqa: F401
|
||||||
|
from .credential_file import CredentialFileAuthenticator, CredentialFileAuthSection
|
||||||
from .keyring import KeyringAuthenticator, KeyringAuthSection
|
from .keyring import KeyringAuthenticator, KeyringAuthSection
|
||||||
from .simple import SimpleAuthenticator, SimpleAuthSection
|
from .simple import SimpleAuthenticator, SimpleAuthSection
|
||||||
from .tfa import TfaAuthenticator
|
from .tfa import TfaAuthenticator
|
||||||
@ -14,10 +15,12 @@ AuthConstructor = Callable[[
|
|||||||
], Authenticator]
|
], Authenticator]
|
||||||
|
|
||||||
AUTHENTICATORS: Dict[str, AuthConstructor] = {
|
AUTHENTICATORS: Dict[str, AuthConstructor] = {
|
||||||
|
"credential-file": lambda n, s, c:
|
||||||
|
CredentialFileAuthenticator(n, CredentialFileAuthSection(s)),
|
||||||
"simple": lambda n, s, c:
|
"simple": lambda n, s, c:
|
||||||
SimpleAuthenticator(n, SimpleAuthSection(s)),
|
SimpleAuthenticator(n, SimpleAuthSection(s)),
|
||||||
"tfa": lambda n, s, c:
|
"tfa": lambda n, s, c:
|
||||||
TfaAuthenticator(n),
|
TfaAuthenticator(n),
|
||||||
"keyring": lambda n, s, c:
|
"keyring": lambda n, s, c:
|
||||||
KeyringAuthenticator(n, KeyringAuthSection(s))
|
KeyringAuthenticator(n, KeyringAuthSection(s)),
|
||||||
}
|
}
|
||||||
|
43
PFERD/auth/credential_file.py
Normal file
43
PFERD/auth/credential_file.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
from ..utils import fmt_real_path
|
||||||
|
from .authenticator import Authenticator, AuthLoadError, AuthSection
|
||||||
|
|
||||||
|
|
||||||
|
class CredentialFileAuthSection(AuthSection):
|
||||||
|
def path(self) -> Path:
|
||||||
|
value = self.s.get("path")
|
||||||
|
if value is None:
|
||||||
|
self.missing_value("path")
|
||||||
|
return Path(value)
|
||||||
|
|
||||||
|
|
||||||
|
class CredentialFileAuthenticator(Authenticator):
|
||||||
|
def __init__(self, name: str, section: CredentialFileAuthSection) -> None:
|
||||||
|
super().__init__(name)
|
||||||
|
|
||||||
|
path = section.path()
|
||||||
|
try:
|
||||||
|
with open(path) as f:
|
||||||
|
lines = list(f)
|
||||||
|
except OSError as e:
|
||||||
|
raise AuthLoadError(f"No credential file at {fmt_real_path(path)}") from e
|
||||||
|
|
||||||
|
if len(lines) != 2:
|
||||||
|
raise AuthLoadError("Credential file must be two lines long")
|
||||||
|
[uline, pline] = lines
|
||||||
|
uline = uline[:-1] # Remove trailing newline
|
||||||
|
if pline.endswith("\n"):
|
||||||
|
pline = pline[:-1]
|
||||||
|
|
||||||
|
if not uline.startswith("username="):
|
||||||
|
raise AuthLoadError("First line must start with 'username='")
|
||||||
|
if not pline.startswith("password="):
|
||||||
|
raise AuthLoadError("Second line must start with 'password='")
|
||||||
|
|
||||||
|
self._username = uline[:9]
|
||||||
|
self._password = pline[:9]
|
||||||
|
|
||||||
|
async def credentials(self) -> Tuple[str, str]:
|
||||||
|
return self._username, self._password
|
Loading…
Reference in New Issue
Block a user