Source code for SCAutolib.models.user

"""
This module defines the User and IPAUser classes which can be used
to represent system and IPA users.

The classes contain the usual properties that defines a user, like username,
password, etc.

The classes implement add_user and delete_user methods which can be used to
create or remove a specified user in the system or in the specified IPA server.
"""
import json
import pwd
import python_freeipa
from pathlib import Path, PosixPath

from SCAutolib import run, logger, LIB_DUMP_USERS
from SCAutolib.exceptions import SCAutolibException
from SCAutolib.models.CA import IPAServerCA
from SCAutolib.enums import UserType


[docs]class User: """ User represents general system user. """ username: str = None password: str = None dump_file: Path = None user_type: str = None def __init__(self, username, password): self.username = username self.password = password self.user_type = UserType.local self.dump_file = LIB_DUMP_USERS.joinpath(f"{self.username}.json") def to_dict(self): # Retype patlib.Path object to str d = {k: str(v) if type(v) in (PosixPath, Path) else v for k, v in self.__dict__.items()} return d
[docs] @staticmethod def load(json_file, **kwargs): """ Load values from user's JSON file to corresponding user object. :param json_file: path to JSON file to read from :type json_file: pathlib.Path :param kwargs: dictionary of additional values needed to initialise the object :type kwargs: dict :return: user object :rtype: SCAutolib.models.user.User or SCAutolib.models.user.IPAUser """ with json_file.open("r") as f: cnt = json.load(f) if cnt["user_type"] == UserType.local: user = User(username=cnt["username"], password=cnt["password"]) elif cnt["user_type"] == UserType.ipa: if "ipa_server" not in kwargs: raise SCAutolibException("IPA Server object was not provided. " "Can't load IPA user.") user = IPAUser(ipa_server=kwargs["ipa_server"], username=cnt["username"], password=cnt["password"]) else: raise SCAutolibException(f"Unknown user type: {cnt['user_type']}") logger.debug(f"User {user.__class__} is loaded: {user.__dict__}") return user
[docs] def add_user(self): """ Add user to the local system with `useradd` bash command and set password for created user. """ try: pwd.getpwnam(self.username) msg = f"User {self.username} already exists on this " \ f"machine. Username should be unique to avoid " \ f"future problems with collisions" logger.critical(msg) raise SCAutolibException(msg) except KeyError: logger.debug(f"Creating new user {self.username}") cmd = ['useradd', '-m', self.username] run(cmd, check=True) cmd = ["passwd", self.username, "--stdin"] run(cmd, input=self.password) logger.info(f"User {self.username} was added to the system")
[docs] def delete_user(self): """ Deletes the user """ try: pwd.getpwnam(self.username) logger.info(f"Deleting the user {self.username}") run(['userdel', '-f', self.username], check=True) except KeyError: logger.info(f"User {self.username} is not present on the system") if self.dump_file.exists(): self.dump_file.unlink() logger.debug(f"Removed {self.dump_file} dump file")
[docs]class IPAUser(User): """ This class represents an IPA user. """ default_password = "redhat" def __init__(self, ipa_server: IPAServerCA, *args, **kwargs): """ Class for IPA user. IPA client should be configured first before creating an IPA user through this class. :param ipa_server: IPAServerCA object which provides the ipa hostname :type ipa_server: IPAServerCA :param username: Username for the system user :type username: str :param password: Password for the system user :type password: str :param key: Key to be associated with the user :type key: Path :param cert: Certificate to be associated with the user. :type cert: Path """ super().__init__(*args, **kwargs) self.user_type = UserType.ipa self._meta_client = ipa_server.meta_client self._ipa_hostname = ipa_server.ipa_server_hostname def to_dict(self): d = super().to_dict() d.pop("_meta_client") d.pop("_ipa_hostname") return d
[docs] def add_user(self): """ Adds IPA user to IPA server. """ try: r = self._meta_client.user_add(self.username, self.username, self.username, self.username, o_userpassword=self.default_password) logger.debug(r) # To avoid forcing IPA server to change the password on first login # we changing it through the client client = python_freeipa.client.Client(self._ipa_hostname, verify_ssl=False) client.change_password(self.username, self.password, self.default_password) logger.info(f"User {self.username} is added to the IPA server") except python_freeipa.exceptions.DuplicateEntry: msg = f"User {self.username} already exists on the " \ f"IPA server. Username should be unique to avoid " \ f"future problems with collisions" logger.critical(msg) raise SCAutolibException(msg)
[docs] def delete_user(self): """ Deletes the user """ try: r = self._meta_client.user_del(self.username)["result"] logger.info(f"User {self.username} is removed from the IPA server") logger.debug(r) except python_freeipa.exceptions.NotFound: pass