credentials module
Classes for provisioning credentials like user names and passwords to controls.
The following credential sources are supported:
Freedesktop Secret Service and other keyrings via the python keyring package. See
KeyringReader.TPM2 via tpm2-tools binaries. See
Tpm2Reader.Flat files, either in netrc format or with a single line containing a credential. See
FileReader.Interactive user prompts. See
PromptReader.
For providing credentials in one of various output formats, the
TemporaryCredentials class creates a temporary file and auto-deletes
it again. It is inspired by
systemd’s credentials mechanism. The
supported output formats are listed in Format.
Note: Due to inherent Python limitations, credentials in RAM cannot be safely shredded. That is, as long as the Python process lives, and even thereafter, plaintext credentials may exist in RAM until they are overwritten by another process.
Classes
- class ctlbase.credentials.CredentialReader(**kwargs)
Bases:
BaseReaderA universal credential reader backed by an instance of one of the following classes:
An instance of
PromptReaderis always created as a fallback reader.This class is helpful to read credentials from one of various sources, based on values determined at runtime. For instance, a control can pass its environment configuration values to
__init__(), dynamically creating a backing credential reader.The reader’s
readCredential()method may raise instances ofErrorMessagewith the following message keys:CREDENTIALS_FALLING_BACK – If the backing credential reader failed and the fallback reader is used.
All the message keys from the backing credential reader.
- __init__(**kwargs)
Creates a new credential reader.
- Parameters:
Based on the following keyword arguments, the class of the backing credential reader is determined and instantiated:
keyringServiceor service (str): Required forKeyringReader.commandExecutor(CommandExecutor): Required forTpm2Reader.tpmHandle(str): Required forTpm2Reader.tpmAuth(str): Optional forTpm2Reader.inputFilePath(str): Required forFileReader.hostname(str): Optional forFileReader, depending on the use case.username(str): Required forKeyringReader. Optional forTpm2Reader,FileReaderandPromptReader, depending on the use case.purpose(str): Optional forPromptReader.credentialKeys(dict),msgBuffer(MessageBuffer) andns(str): Optional for all classes.
- Raises:
ValueError – If the class for the backing credential reader could not be determined unambiguously.
- class ctlbase.credentials.KeyringReader(keyringService, username, keyringBackend='keyring.backends.libsecret.Keyring', credentialKeys=None)
Bases:
BaseReaderA credential reader based on the keyring package. The keyring backend defaults to the Freedesktop Secret Service, i.e. the keyring.backends.libsecret.Keyring class. libsecret must be available on the system for that class to work.
The password must be stored under a specific service and user name. The following is the basic command to execute on the command line:
keyring -b=keyring.backends.libsecret.Keyring set <service> <username>
The reader’s
readCredential()method returns a dict with the following keys:PASSWORD, unlesscredentialKeyslists another key instead.
Furthermore, the method may raise an instance of
ErrorMessagewith one of the following message keys:CREDENTIALS_NOT_FOUND – If there is no entry in the keyring with the given service and user name.
- __init__(keyringService, username, keyringBackend='keyring.backends.libsecret.Keyring', credentialKeys=None)
Creates a new credential reader.
- Parameters:
keyringService¶ (str) – The service name under which the password is stored in the keyring. Corresponds to
<service>in the basic command above.username¶ (str) – The user name under which the password is stored in the keyring. Corresponds to
<username>in the basic command above. The user name is also included in the dict returned byreadCredential()under theUSERNAMEkey.keyringBackend¶ (keyring.backend.KeyringBackend) – The keyring backend to use if deviating from the default.
credentialKeys¶ (list[CredentialKey] | tuple[CredentialKey]) – See
credentialKeys.
- class ctlbase.credentials.Tpm2Reader(commandExecutor, tpmHandle, tpmAuth=None, username=None, credentialKeys=None)
Bases:
BaseReaderA credential reader accessing the TPM2 on the local machine. It uses the binaries from tpm2-tools, e.g. tpm2_unseal.
The reader’s
readCredential()method returns a dict with the following keys:PASSWORD, unlesscredentialKeyslists another key instead.
- __init__(commandExecutor, tpmHandle, tpmAuth=None, username=None, credentialKeys=None)
Creates a new credential reader.
- Parameters:
commandExecutor¶ (CommandExecutor) – The command executor for tpm2-tools binaries.
tpmHandle¶ (str) – Handle for the TPM object that represents the password. Example:
0x81000041tpmAuth¶ (str) – Hash and PCR register specfication for authorizing the access to the password. Takes the form
<hash algorithm>:<PCR numbers>where<PCR numbers>is a comma-separated list of numbers from 0 through 23. Example:sha256:0,2,3,7If None, the value ofPCR_AUTH_DEFAULTis assumed.username¶ (str) – The user name to include in the dict returned by
readCredential()under theUSERNAMEkey. This is a mere pass-through as no user name is read from the TPM2.credentialKeys¶ (list[CredentialKey] | tuple[CredentialKey]) – See
credentialKeys.
- PCR_AUTH_DEFAULT = 'pcr:sha256:0,2,3,7'
- class ctlbase.credentials.FileReader(inputFilePath, hostname=None, username=None, credentialKeys=None)
Bases:
BaseReaderA credential reader based on text files. The file must be in netrc format or contain a single line with the credential.
The reader’s
readCredential()method returns a dict with the following keys:PASSWORD, unlesscredentialKeyslists another key instead.
Furthermore, the method may raise an instance of
ErrorMessagewith one of the following message keys:CREDENTIALS_NOT_FOUND – If the input file does not exist or is not readable to the current user.
CREDENTIALS_FORMAT_INVALID – If the input file is in netrc format but the given host name could not be found.
- __init__(inputFilePath, hostname=None, username=None, credentialKeys=None)
- Parameters:
inputFilePath¶ (str) – The path to the input file from which to read the password.
hostname¶ (str) – The hostname of the target entry. Required if the input file is in netrc format.
username¶ (str) – The user name of the target entry. Required if the input file is in netrc format. Regardless of the input file format, the user name is returned in the dict from
readCredential()under theUSERNAMEkey.credentialKeys¶ (list[CredentialKey] | tuple[CredentialKey]) – See
credentialKeys.
- class ctlbase.credentials.PromptReader(username=None, purpose=None, credentialKeys=None)
Bases:
BaseReaderA credential reader prompting the user for a credential on the command line.
The reader’s
readCredential()method returns a dict with the following message keys:PASSWORD, unlesscredentialKeyslists another key instead.
Furthermore, the method may raise an instance of
ErrorMessagewith one of the following message keys:CREDENTIALS_PROMPT_SUPPRESSED – If user prompts are suppressed, i.e.
mayPromptis False.CREDENTIALS_PROMPT_ABORTED – If entering the credential was aborted by the user.
- __init__(username=None, purpose=None, credentialKeys=None)
Creates a new credential reader.
- Parameters:
username¶ (str) – The user name to include in the dict returned by
readCredential()under theUSERNAMEkey. Unlesspurposeis specified, the user name is included in the prompt presented to the user.purpose¶ (str) – A language-agnostic str to present to the user as the purpose of the requested credentials. Example:
HomeServer via SMBcredentialKeys¶ (list[CredentialKey] | tuple[CredentialKey]) – See
credentialKeys.
- class ctlbase.credentials.BaseReader(credentialKeys=None, msgBuffer=None, ns=None)
Base class for credential readers.
- __init__(credentialKeys=None, msgBuffer=None, ns=None)
Creates a new credential reader.
- Parameters:
credentialKeys¶ (list[CredentialKey] | tuple[CredentialKey]) – The credential keys supported by the reader, as a subset of
CredentialKey.msgBuffer¶ (str) – A message buffer for appending all occurring messages. May be None if the reader does not append any messages.
ns¶ (str) – The message namespace to use when appending messages to the message buffer. May be None if the reader does not append any messages.
- abstract async _readCredential(mayPrompt=None, purpose=None) dict[CredentialKey, str]
Implements the logic for reading a set of credentials from an actual source.
The parameters correspond to
mayPromptandpurpose, respectively. Both are optional and may be omitted in the signature.- Returns:
A dict containing the keys listed in
credentialKeys, and the corresponding values read from the source.- Return type:
- async readCredential(mayPrompt=None, purpose=None)
Reads a set of credentials.
Access to the credential source is delegated to
_readCredential().- Parameters:
mayPrompt¶ (bool) – If True, the user may be prompted interactively for missing credentials. If False, an exception is raised in the case of missing credentials.
purpose¶ (str) – A language-agnostic str to present to the user as the purpose of the requested credentials. Example:
HomeServer via SMBOnly relevant when interactively prompting the user for credentials.
- Raises:
ValueError – If the dict returned by
_readCredential()does not contain all the keys listed incredentialKeys.ValueError – If arguments provided in the constructor turn out to be invalid before actually accessing the source.
ErrorMessage – If the credentials could not be read, apart from invalid arguments.
- Returns:
A dict containing the keys listed in
credentialKeys, and the corresponding values read from the source.- Return type:
- credentialKeys: list[CredentialKey] | tuple[CredentialKey]
The credential keys supported by the reader, as a subset of
CredentialKey.
- class ctlbase.credentials.TemporaryCredentials(path, readers, format=Format.PLAIN, mountpoint=None, delete=True, msgBuffer=None, ns=True, mayPrompt=None, purpose=None)
An async context manager temporarily providing a set of credentials. When entering, credentials are read from a credential reader and written to a temporary file in one of the formats listed in
Format. When exiting, the temporary file is deleted again unlessdeleteis set to False.Example usage:
tmp = TemporaryCredentials( '/tmp/smb', PromptReader('hugo', 'HomeServer via SMB'), format=TemporaryCredentials.Format.SMB ) async with tmp: with open(tmp.path) as file: print(file.read())
When entering the context manager, an instance of
ErrorMessagemay be raised with one the following message keys:CREDENTIALS_ALL_FAILED – If all credential readers in
readersfailed.
- class Format(value)
Supported output formats for credentials.
- BASH_LITERAL = '%s'
A bash literal with an associative array, containing one or more keys from
CredentialKeywith the corresponding values, e.g.(['username']='hugo' ['password']='q3o##3jHSNTxw~cr').
- DAVFS = '%s %s %s\n'
DAVFS2 format, i.e. a single line with the mountpoint, the user name and password, separated by whitespace.
- DAVFS2 = '%s %s %s\n'
An alias for DAVFS.
- PLAIN = '%s\n'
A single plaintext password.
- SMB = 'username=%s\npassword=%s\n'
SMB / CIFS mount format, i.e.
username=on the first line andpassword=on the second.
- __init__(path, readers, format=Format.PLAIN, mountpoint=None, delete=True, msgBuffer=None, ns=True, mayPrompt=None, purpose=None)
Creates a new context manager for a set of credentials. At his point, credentials are neither read nor written. This only happens when entering the context manager.
- Parameters:
path¶ (str) – The path under which the temporary file is expected. If only a file name is given, without any path specification, the value of
CREDENTIALS_DIRECTORY_DEFAULTis assumed. If None, the temporary file can only be accessed vianamedTemp.readers¶ (list[BaseReader] | tuple[BaseReader] | BaseReader) – The credential readers to be called in sequence to actually read the credentials. If the first one fails, the second is called and so on until one of them succeeds. For every failing reader, its error message is appended to the message buffer.
format¶ (TemporaryCredentials.Format) – See
format.mountpoint¶ (str) – See
mountpoint.msgBuffer¶ (MessageBuffer) – The message buffer to which all occurring messages are appended. It is propagated to all credential readers given in
readersunless they have a message buffer of their own.ns¶ (str | True | None) – The message namespace to use when appending messages to the message buffer. If True, the namespace is derived from the caller name. See
CallerInspectorfor the discovery algorithm. The namespace is propagated to all credential readers given inreadersunless they have a message namespace of their own. The default namespace of the message buffer is left unchanged. This allows for a separate namespace helpful for security audits and debugging.
- async deleteCredential()
Deletes the temporary file
namedTempalong with its hardlinkpath.Unless
deleteis set to False, this method is called automatically when the context manager exits.- Returns:
True if a temporary file existed and was deleted. False if no temporary file exists.
- Return type:
- delete: bool
- If True, the temporary credentials file is auto-deleted when the context manager exists.The attribute name is borrowed from Python’s
tempfile.NamedTemporaryFile()class.Note: Set to False only for debugging purposes!
Constants and defaults
- class ctlbase.credentials.CredentialKey(value)
Common keys for a set of credentials in their dict representation.
- CRYPTOPHRASE = 'cryptophrase'
- LOGIN = 'username'
- LOGINNAME = 'username'
- PASSWORD = 'password'
- TOTP = 'totp'
- USERNAME = 'username'
- ctlbase.credentials.CREDENTIALS_DIRECTORY_DEFAULT = '/run/reader'