diff --git a/data/migrations/versions/87d86e3d4c2c_add_superuser_and_restricted_user_.py b/data/migrations/versions/87d86e3d4c2c_add_superuser_and_restricted_user_.py index 6ed309acc1..a85f344423 100644 --- a/data/migrations/versions/87d86e3d4c2c_add_superuser_and_restricted_user_.py +++ b/data/migrations/versions/87d86e3d4c2c_add_superuser_and_restricted_user_.py @@ -39,6 +39,18 @@ def upgrade(op, tables, tester): ), ) + # insert new actions to log + op.bulk_insert( + tables.logentrykind, + [ + {"name": "add_superuser"}, + {"name": "remove_superuser"}, + {"name": "change_namespace_repo_visiblity"}, + {"name": "add_restricted_user"}, + {"name": "remove_restricted_user"}, + ], + ) + def downgrade(op, tables, tester): with op.batch_alter_table("user") as batch_op: diff --git a/data/model/user.py b/data/model/user.py index 2749fc2e2a..b637991050 100644 --- a/data/model/user.py +++ b/data/model/user.py @@ -1472,12 +1472,12 @@ def get_quay_user_from_federated_login_name(username): return get_namespace_user_by_user_id(user_id) if user_id else None -def convert_user_to_superuser(username): +def add_superuser(user): """ Converts the requested user to a superuser. """ with db_transaction(): - user = db_for_update(User.select().where(User.username == username)).get() + user = db_for_update(User.select().where(User.id == user.id)).get() user.is_restricted_user = False user.is_superuser = True for robot in db_for_update( @@ -1490,12 +1490,12 @@ def convert_user_to_superuser(username): return user -def convert_superuser_to_user(username, restricted=False): +def del_superuser(user, restricted=False): """ Converts the requested superuser to a normal user. """ with db_transaction(): - user = db_for_update(User.select().where(User.username == username)).get() + user = db_for_update(User.select().where(User.id == user.id)).get() user.is_restricted_user = restricted user.is_superuser = False for robot in db_for_update( @@ -1508,6 +1508,38 @@ def convert_superuser_to_user(username, restricted=False): return user +def add_restricted_user(user): + """ + Marks the user as restricted. + """ + with db_transaction(): + user = db_for_update(User.select().where(User.id == user.id)).get() + user.is_restricted_user = True + for robot in db_for_update( + _list_entity_robots(user.username, include_metadata=False, include_token=False) + ): + robot.is_restricted_user = True + robot.save() + user.save() + return user + + +def del_restricted_user(user): + """ + Marks the user as unrestricted. + """ + with db_transaction(): + user = db_for_update(User.select().where(User.id == user.id)).get() + user.is_restricted_user = False + for robot in db_for_update( + _list_entity_robots(user.username, include_metadata=False, include_token=False) + ): + robot.is_restricted_user = False + robot.save() + user.save() + return user + + class LoginWrappedDBUser(UserMixin): def __init__(self, user_uuid, db_user=None): self._uuid = user_uuid diff --git a/endpoints/api/superuser.py b/endpoints/api/superuser.py index 59ea4010cc..46a05f4000 100644 --- a/endpoints/api/superuser.py +++ b/endpoints/api/superuser.py @@ -768,21 +768,38 @@ def put(self, username): config_provider.save_config(config_object) if "is_superuser" in user_data: - if is_superuser: + if user_data["is_superuser"]: + pre_oci_model.add_superuser(username) + usermanager.register_superuser(username) log_action( - "make_superuser", + "add_superuser", username, {"username": username, "authorized_user": authed_user.username}, ) - pre_oci_model.make_superuser(username) - usermanager.register_superuser(username) - if is_superuser == False: + else: + pre_oci_model.del_superuser(username, features.RESTRICTED_USERS) + usermanager.remove_superuser(username) log_action( "remove_superuser", username, {"username": username, "authorized_user": authed_user.username}, ) + if "is_restricted_user" in user_data: + if user_data["is_restricted_user"]: + pre_oci_model.add_restricted_user(username) + log_action( + "add_restricted_user", + username, + {"username": username, "authorized_user": authed_user.username}, + ) + else: + pre_oci_model.del_restricted_user(username) + log_action( + "remove_restricted_user", + username, + {"username": username, "authorized_user": authed_user.username}, + ) return_value = user.to_dict() if user_data.get("password") is not None: password = user_data.get("password") diff --git a/endpoints/api/superuser_models_interface.py b/endpoints/api/superuser_models_interface.py index ce00b5bf5c..993cdf51bc 100644 --- a/endpoints/api/superuser_models_interface.py +++ b/endpoints/api/superuser_models_interface.py @@ -223,7 +223,21 @@ def to_dict(self): } -class User(namedtuple("User", ["username", "email", "verified", "enabled", "robot", "quotas"])): +class User( + namedtuple( + "User", + [ + "username", + "email", + "verified", + "enabled", + "robot", + "quotas", + "is_superuser", + "is_restricted_user", + ], + ) +): """ User represents a single user. @@ -232,8 +246,6 @@ class User(namedtuple("User", ["username", "email", "verified", "enabled", "robo :type verified: boolean :type enabled: boolean :type robot: User - :type is_superuser: boolean - :type is_restricted_user: boolean """ def to_dict(self): @@ -258,7 +270,9 @@ def to_dict(self): return user_data -class Organization(namedtuple("Organization", ["username", "email", "quotas"])): +class Organization( + namedtuple("Organization", ["username", "email", "quotas", "is_restricted_usedr"]) +): """ Organization represents a single org. @@ -355,6 +369,30 @@ def update_enabled(self, username, enabled): Returns None. """ + @abstractmethod + def add_superuser(self, username): + """ + Sets user as superuser. + """ + + @abstractmethod + def del_superuser(self, username): + """ + Removes user as superuser. + """ + + @abstractmethod + def add_restricted_user(self, username): + """ + Sets user as restricted. + """ + + @abstractmethod + def del_restricted_user(self, username): + """ + Removes restrictions from user. + """ + @abstractmethod def take_ownership(self, namespace, authed_user): """ @@ -422,33 +460,3 @@ def get_repository_build(self, uuid): """ Returns RepositoryBuild. """ - - @abstractmethod - def make_superuser(self, username): - """ - Converts a user to a superuser. - """ - - @abstractmethod - def remove_superuser(self, username, restricted=False): - """ - Removes superuser privileges from superuser. - """ - - @abstractmethod - def change_namespace_push_visibility(self, namespace): - """ - Changes the namespace wide push visiblity to either public or private. - """ - - @abstractmethod - def add_restricted_user(self, username): - """ - Adds a restricted namespace. - """ - - @abstractmethod - def remove_restricted_user(self, username): - """ - Removes restrictions on namespace. - """ diff --git a/endpoints/api/superuser_models_pre_oci.py b/endpoints/api/superuser_models_pre_oci.py index 7f6422d0ec..7a307523e5 100644 --- a/endpoints/api/superuser_models_pre_oci.py +++ b/endpoints/api/superuser_models_pre_oci.py @@ -34,7 +34,16 @@ def _create_user(user): quotas = _get_namespace_quotas(user) - return User(user.username, user.email, user.verified, user.enabled, user.robot, quotas) + return User( + user.username, + user.email, + user.verified, + user.enabled, + user.robot, + quotas, + user.is_superuser, + user.is_restricted_user, + ) def _create_key(key): @@ -199,6 +208,22 @@ def update_enabled(self, username, enabled): user = model.user.get_nonrobot_user(username) model.user.update_enabled(user, bool(enabled)) + def add_superuser(self, username): + user = model.user.get_nonrobot_user(username) + model.user.add_superuser(user) + + def del_superuser(self, username, restricted): + user = model.user.get_nonrobot_user(username) + model.user.del_superuser(user, restricted=restricted) + + def add_restricted_user(self, username): + user = model.user.get_nonrobot_user(username) + model.user.add_restricted_user(user) + + def del_restricted_user(self, username): + user = model.user.get_nonrobot_user(username) + model.user.del_restricted_user(user) + def update_email(self, username, email, auto_verify): user = model.user.get_nonrobot_user(username) model.user.update_email(user, email, auto_verify) diff --git a/util/config/superusermanager.py b/util/config/superusermanager.py index 333a14c7a4..8da1e6fa12 100644 --- a/util/config/superusermanager.py +++ b/util/config/superusermanager.py @@ -22,21 +22,14 @@ class ConfigUserManager(UserManager): """ def __init__(self, app): - self.super_usernames = [ - user.username for user in User.select().where(User.is_superuser == True) - ] + self.super_usernames = [] # super_usernames_str = ",".join(super_usernames) # self._super_max_length = len(super_usernames_str) + MAX_USERNAME_LENGTH + 1 # self._superusers_array = Array("c", self._super_max_length, lock=True) # self._superusers_array.value = super_usernames_str.encode("utf8") - restricted_usernames_whitelist = [ - user.username - for user in User.select().where( - (User.is_restricted_user == False) & (User.robot == False) - ) - ] or [] + restricted_usernames_whitelist = [] if restricted_usernames_whitelist: restricted_usernames_whitelist_str = ",".join(restricted_usernames_whitelist)