KeePass support

This commit is contained in:
Daniel Dizdarevic 2023-04-28 14:37:24 +02:00 committed by Stefan Bühler
parent 1f28ee3622
commit ff2cddbf65
3 changed files with 47 additions and 1 deletions

View File

@ -88,3 +88,11 @@ This configures [`keyringer`](https://0xacab.org/rhatto/keyringer) (based on GPG
`keyringer` need a "keyring" to search in, and you can (optionally) specify a folder to be
prefixed to the password names created from the realm.
#### keepass
```yaml
keepass: /home/me/mypasswords.kdbx
```
This configures KeePass as password manager; it will prompt for your master password every time.

View File

@ -22,6 +22,11 @@ dependencies = [
"PyYAML",
]
[project.optional-dependencies]
keepass = [
"pykeepass",
]
[project.scripts]
ldaptool = "ldaptool._main:main"
@ -46,5 +51,6 @@ module = [
"ldap",
"ldap.dn",
"ldap.controls.libldap",
"pykeepass",
]
ignore_missing_imports = true

View File

@ -2,6 +2,7 @@ from __future__ import annotations
import abc
import dataclasses
import getpass
import os
import os.path
import shlex
@ -122,6 +123,34 @@ class Keyringer(PasswordManager):
return result.stdout.strip()
@dataclasses.dataclass
class Keepass(PasswordManager):
database: str
@staticmethod
def load(data: typing.Any) -> Keepass:
try:
import pykeepass # make sure dependency is present during config loading
assert pykeepass # so it isn't unused...
except ImportError:
raise Exception(
"Missing (optional) dependency for keepass support - please install (python package for) pykeepass"
)
assert isinstance(
data, str
), "keepass integration expects a single string as configuration with the database location"
return Keepass(database=data)
def get_password(self, password_name: str) -> str:
import pykeepass # already made sure it is avaiable above
password = getpass.getpass(f"KeePass password for database {self.database}: ")
kp = pykeepass.PyKeePass(self.database, password=password)
entry = kp.find_entries(username=password_name, first=True)
return entry.password # type: ignore
@dataclasses.dataclass
class PasswordScript(PasswordManager):
command: list[str]
@ -173,6 +202,10 @@ class Config:
if password_manager:
raise ValueError("Can only set a single password manager")
password_manager = Keyringer.load(data.pop("keyringer"))
if "keepass" in data:
if password_manager:
raise ValueError("Can only set a single password manager")
password_manager = Keepass.load(data.pop("keepass"))
if "password-script" in data:
if password_manager:
raise ValueError("Can only set a single password manager")
@ -189,6 +222,5 @@ class Config:
raise RuntimeError("Can't get password without acccount - should use kerberos instead")
if self.password_manager:
return self.password_manager.get_password(realm.password_name)
import getpass
return getpass.getpass(f"Enter password for {realm.password_name}: ")