"""
This module provides methods allowing to configure the system for smart-card
authentication using the ``authselect`` tool.
It is implemented as a context manager (``Authselect`` class), which
ensures that system configurations are properly set up upon entry and
restored to their original state upon exit.
The module interacts with ``authselect(8)`` to apply the ``sssd`` profile
with specified features (for more information see manual page for
``authselect(8)``).
"""
from os.path import exists
from traceback import format_exc
from SCAutolib import LIB_BACKUP
from SCAutolib import logger
from SCAutolib.utils import run
[docs]class Authselect:
"""
Manages the ``authselect`` configuration of the system for smart card
authentication. This class is designed to be
used as a context manager, ensuring that any changes made to ``authselect``
profiles are automatically backed up and restored to their previous state
upon exiting the context. It configures the
``sssd`` profile with specific features like ``with-smartcard``.
"""
backup_name = LIB_BACKUP.joinpath("SCAutolib_authselect_backup")
def __init__(self, required=False, lock_on_removal=False,
mk_homedir=False, sudo=False):
"""
Initializes the ``Authselect`` object with desired ``authselect``
profile features. By default, it sets the ``with-smartcard``
feature for the ``sssd`` profile and uses the ``--force`` option to
apply changes.
:param required: If ``True``, the ``with-smartcard-required`` option
will be added to the ``authselect`` profile.
:type required: bool
:param lock_on_removal: If ``True``, the
``with-smartcard-lock-on-removal`` option will
be added to the ``authselect`` profile.
:type lock_on_removal: bool
:param mk_homedir: If ``True``, the ``with-mkhomedir``
option will be added to the ``authselect`` profile,
ensuring home directories are created on login.
:type mk_homedir: bool
:param sudo: If ``True``, the ``with-sudo`` option will
be added to the ``authselect`` profile, enabling sudo
integration.
:type sudo: bool
:return: None
:rtype: None
"""
self._options = ["with-smartcard"]
if required:
self._options.append("with-smartcard-required")
if lock_on_removal:
self._options.append("with-smartcard-lock-on-removal")
if mk_homedir:
self._options.append("with-mkhomedir")
if sudo:
self._options.append("with-sudo")
[docs] def _set(self):
"""
Applies the SSSD profile with the selected Authselect profile
features using the ``authselect`` command. It also backs
up the previous Authselect configuration to a default location.
:return: None
:rtype: None
"""
# compose and run Authselect command
cmd = ["authselect", "select", "sssd", *self._options,
"--backup", self.backup_name, "--force"]
run(cmd)
# get modified setup and log it
logger.debug("Current Authselect setting is:")
run(["authselect", "current"], return_code=[0, 2])
logger.debug(f"Original Authselect configuration was backed up with "
f"authselect to default location as : "
f"{str(self.backup_name)}")
logger.debug("Default location is: /var/lib/authselect/backups/")
[docs] def _restore(self):
"""
Restores the Authselect configuration to the state it was in before
the Authselect class context manager applied its changes.
It attempts to restore from the backup file created during ``_set()``.
:return: None
:rtype: None
:raises FileNotFoundError: If the backup file expected for restoration
does not exist.
"""
if exists(f"/var/lib/authselect/backups/{self.backup_name}"):
cmd = ["authselect", "backup-restore", self.backup_name, "--debug"]
run(cmd)
logger.debug("Authselect configuration is restored to:")
run(["authselect", "current"], return_code=[0, 2])
else:
# as _set and _restore should be used in context manager defined in
# this class, it should not happen that backup does not exist except
# something failed, or it's misused
raise FileNotFoundError("Backup file not found. _restore method was"
"probably called in unexpected manner.")
def __enter__(self):
"""
Enters the Authselect calls context manager.
This method calls ``_set()`` to apply the desired Authselect
configuration and returns the instance itself, allowing for ``with``
statement usage.
:return: The ``Authselect`` instance.
:rtype: SCAutolib.models.authselect.Authselect
"""
self._set()
return self
def __exit__(self, ext_type, ext_value, ext_traceback):
"""
Exits the Authselect class context manager.
This method is called automatically when exiting a ``with`` statement.
It attempts to restore the Authselect configuration to its original
state by calling ``_restore()``. If an exception occurred
within the context, it logs the exception details.
:param ext_type: The type of the exception that caused the context to
be exited, or ``None`` if no exception occurred.
:type ext_type: type, optional
:param ext_value: The exception instance that caused the context to be
exited, or ``None``.
:type ext_value: Exception, optional
:param ext_traceback: The traceback object associated with the
exception, or ``None``.
:type ext_traceback: traceback, optional
:return: None
:rtype: None
"""
if ext_type is not None:
logger.error("Exception in authselect context")
logger.error(format_exc())
self._restore()