class UserControl(UserGroupControl): def _configure(self, parser): self.exc = ExceptionHandler() parser.add_login_arguments() sub = parser.sub() add = parser.add(sub, self.add, help="Add user") add.add_argument("--ignore-existing", action="store_true", default=False, help="Do not fail if user already exists") add.add_argument("-m", "--middlename", help="Middle name, if available") add.add_argument("-e", "--email") add.add_argument("-i", "--institution") # Capitalized since conflict with main values add.add_argument("-a", "--admin", action="store_true", help="Whether the user should be an admin") add.add_argument("username", help="User's login name") add.add_argument("firstname", help="User's first name") add.add_argument("lastname", help="User's last name") self.add_group_arguments(add, " to join") password_group = add.add_mutually_exclusive_group() password_group.add_argument("-P", "--userpassword", help="Password for user") password_group.add_argument("--no-password", action="store_true", default=False, help="Create user with empty password") list = parser.add(sub, self.list, help="List information about all users") info = parser.add( sub, self.info, "List information about the user(s). Default to the context user") self.add_user_arguments(info) for x in (list, info): x.add_style_argument() x.add_group_print_arguments() x.add_user_sorting_arguments() listgroups = parser.add( sub, self.listgroups, "List the groups of the user. Default to the context user") self.add_user_arguments(listgroups) listgroups.add_style_argument() listgroups.add_user_print_arguments() listgroups.add_group_sorting_arguments() password = parser.add(sub, self.password, help="Set user's password") password.add_argument("username", nargs="?", help="Username if not the current user") email = parser.add(sub, self.email, help="List users' email addresses") email.add_argument("-n", "--names", action="store_true", default=False, help="Print user names along with email addresses") email.add_argument("-1", "--one", action="store_true", default=False, help="Print one user per line") email.add_argument("-i", "--ignore", action="store_true", default=False, help="Ignore users without email addresses") email.add_argument( "--all", action="store_true", default=False, help="Include all users, including deactivated accounts") joingroup = parser.add(sub, self.joingroup, "Join one or more groups") self.add_id_name_arguments(joingroup, "user. Default to the current user") group = self.add_group_arguments(joingroup, " to join") group.add_argument("--as-owner", action="store_true", default=False, help="Join the group(s) as an owner") leavegroup = parser.add(sub, self.leavegroup, "Leave one or more groups") self.add_id_name_arguments(leavegroup, "user. Default to the current user") group = self.add_group_arguments(leavegroup, " to leave") group.add_argument("--as-owner", action="store_true", default=False, help="Leave the owner list of the group(s)") for x in (email, password, list, add, joingroup, leavegroup): x.add_login_arguments() def format_name(self, exp): record = "" fn = _(exp.firstName) mn = " " if _(exp.middleName): mn = " %s " % _(exp.middleName) ln = _(exp.lastName) record += "%s%s%s" % (fn, mn, ln) return record def email(self, args): c = self.ctx.conn(args) a = c.sf.getAdminService() r = a.getSecurityRoles() skipped = [] records = [] for exp in a.lookupExperimenters(): # Handle users without email if not _(exp.email): if not args.ignore: skipped.append(exp) continue # Handle deactivated users if not args.all: groups = exp.linkedExperimenterGroupList() group_ids = [x.id.val for x in groups] if r.userGroupId not in group_ids: continue record = "" if args.names: record += '"%s"' % self.format_name(exp) record += " <%s>" % _(exp.email) else: record += _(exp.email) records.append(record) if args.one: for record in records: self.ctx.out(record) else: self.ctx.out(", ".join(records)) if skipped: self.ctx.err("Missing email addresses:") for s in skipped: self.ctx.err(self.format_name(s)) def password(self, args): import omero from omero.rtypes import rstring client = self.ctx.conn(args) own_name = self.ctx.get_event_context().userName admin = client.sf.getAdminService() # tickets 3202, 5841 own_pw = self._ask_for_password(" for your user (%s)" % own_name, strict=False) try: client.sf.setSecurityPassword(own_pw) self.ctx.out("Verified password.\n") except omero.SecurityViolation as sv: import traceback self.ctx.die(456, "SecurityViolation: Bad credentials") self.ctx.dbg(traceback.format_exception(None, e, sys.exc_info()[2])) if args.username: try: e = admin.lookupExperimenter(args.username) except omero.ApiUsageException: self.ctx.die(457, "Unknown user: %s" % args.username) return # Never reached self.ctx.out("Changing password for %s (id:%s)" % (args.username, e.id.val)) else: self.ctx.out("Changing password for %s" % own_name) pw = self._ask_for_password(" to be set") pw = rstring(pw) if args.username: admin.changeUserPassword(args.username, pw) else: admin.changePassword(pw) self.ctx.out("Password changed") def list(self, args): c = self.ctx.conn(args) a = c.sf.getAdminService() users = a.lookupExperimenters() self.output_users_list(a, users, args) def info(self, args): c = self.ctx.conn(args) a = c.sf.getAdminService() [uids, users] = self.list_users(a, args, use_context=True) self.output_users_list(a, users, args) def listgroups(self, args): c = self.ctx.conn(args) admin = c.sf.getAdminService() [uids, groups] = self.list_users(admin, args, use_context=True) if len(uids) != 1: self.ctx.die(516, 'Too many user arguments') groups = admin.containedGroups(uids[0]) self.output_groups_list(groups, args) @admin_only(AdminPrivilegeModifyUser, AdminPrivilegeModifyGroupMembership) def add(self, args): email = args.email login = args.username first = args.firstname middle = args.middlename last = args.lastname inst = args.institution pasw = args.userpassword import omero from omero.rtypes import rbool, rstring from omero_model_ExperimenterI import ExperimenterI as Exp from omero_model_ExperimenterGroupI import ExperimenterGroupI as Grp c = self.ctx.conn(args) e = Exp() e.omeName = rstring(login) e.firstName = rstring(first) e.lastName = rstring(last) e.middleName = rstring(middle) e.email = rstring(email) e.institution = rstring(inst) e.ldap = rbool(False) # Fail-fast if no-password is passed and the server does not accept # empty passwords configService = c.getSession().getConfigService() password_required = configService.getConfigValue( "omero.security.password_required").lower() if args.no_password and password_required != 'false': self.ctx.die( 502, "Server does not allow user creation with empty" " passwords") # Check user existence admin = c.getSession().getAdminService() try: usr = admin.lookupExperimenter(login) if usr: if args.ignore_existing: self.ctx.out("User exists: %s (id=%s)" % (login, usr.id.val)) return else: self.ctx.die( 3, "User exists: %s (id=%s)" % (login, usr.id.val)) except omero.ApiUsageException: pass # Apparently no such user exists [gid, groups] = self.list_groups(admin, args, use_context=False) roles = admin.getSecurityRoles() groups.append(Grp(roles.userGroupId, False)) if args.admin: groups.append(Grp(roles.systemGroupId, False)) group = groups.pop(0) try: if args.no_password: id = admin.createExperimenter(e, group, groups) self.ctx.out("Added user %s (id=%s) without password" % (login, id)) else: if pasw is None: pasw = self._ask_for_password(" for your new user (%s)" % login, strict=True) id = admin.createExperimenterWithPassword( e, rstring(pasw), group, groups) self.ctx.out("Added user %s (id=%s) with password" % (login, id)) except omero.ValidationException as ve: # Possible, though unlikely after previous check if self.exc.is_constraint_violation(ve): self.ctx.die(66, "User already exists: %s" % login) else: self.ctx.die(67, "Unknown ValidationException: %s" % ve.message) except omero.SecurityViolation as se: self.ctx.die(68, "Security violation: %s" % se.message) def parse_userid(self, a, args): if args.id: user = getattr(args, "id", None) return self.find_user_by_id(a, user, fatal=True) elif args.name: user = getattr(args, "name", None) return self.find_user_by_name(a, user, fatal=True) else: user = self.ctx.get_event_context().userName return self.find_user_by_name(a, user, fatal=True) def filter_groups(self, groups, uid, owner=False, join=True): for group in list(groups): if owner: uid_list = self.getownerids(group) relation = "owner of" else: uid_list = self.getuserids(group) relation = "in" if join: if uid in uid_list: self.ctx.out("%s is already %s group %s" % (uid, relation, group.id.val)) groups.remove(group) else: if uid not in uid_list: self.ctx.out("%s is not %s group %s" % (uid, relation, group.id.val)) groups.remove(group) return groups def joingroup(self, args): c = self.ctx.conn(args) a = c.sf.getAdminService() uid, username = self.parse_userid(a, args) [gid, groups] = self.list_groups(a, args, use_context=False) groups = self.filter_groups(groups, uid, args.as_owner, True) for group in groups: if args.as_owner: self.addownersbyid(a, group, [uid]) else: self.addusersbyid(a, group, [uid]) def leavegroup(self, args): c = self.ctx.conn(args) a = c.sf.getAdminService() uid, username = self.parse_userid(a, args) [gid, groups] = self.list_groups(a, args, use_context=False) groups = self.filter_groups(groups, uid, args.as_owner, False) for group in list(groups): if args.as_owner: self.removeownersbyid(a, group, [uid]) else: self.removeusersbyid(a, group, [uid])
class GroupControl(UserGroupControl): def _configure(self, parser): self.exc = ExceptionHandler() PERM_TXT = """ Group permissions come in several styles: * private (rw----) [DEFAULT] * read-only (rwr---) * read-annotate (rwra--) [Previously known as 'collaborative'] * read-write (rwrw--) In private groups, only group owners and system administrators will be able to view someone else's data. In read-only groups, other group members can see data but not annotate or modify it. In read-annotate groups, annotation is permitted by group members. In read-write groups, all group members can behave as if they co-own all the data. Changing a group to private unlinks data from other users' containers and unlinks other users' annotations from data. The change to private will fail if different users' data is too closely related to be separated. More information is available at: https://docs.openmicroscopy.org/latest/omero/sysadmins/\ server-permissions.html """ parser.add_login_arguments() sub = parser.sub() add = parser.add(sub, self.add, "Add a new group with given permissions " + PERM_TXT) add.add_argument("--ignore-existing", action="store_true", default=False, help="Do not fail if user already exists") add.add_argument("name", help="Name of the group") self.add_permissions_arguments(add) perms = parser.add(sub, self.perms, "Modify a group's permissions " + PERM_TXT) self.add_id_name_arguments(perms, "group") self.add_permissions_arguments(perms) list = parser.add(sub, self.list, help="List information about all groups") info = parser.add( sub, self.info, "List information about the group(s). Default to the context" " group") self.add_group_arguments(info) for x in (list, info): x.add_style_argument() x.add_user_print_arguments() x.add_group_sorting_arguments() listusers = parser.add(sub, self.listusers, "List users of the current group") self.add_group_arguments(listusers) listusers.add_style_argument() listusers.add_group_print_arguments() listusers.add_user_sorting_arguments() copyusers = parser.add( sub, self.copyusers, "Copy the users of one" " group to another group") copyusers.add_argument("from_group", help="ID or name of the source" " group whose users will be copied") copyusers.add_argument("to_group", help="ID or name of the target" " group which will have new users added") copyusers.add_argument("--as-owner", action="store_true", default=False, help="Copy the group owners only") adduser = parser.add(sub, self.adduser, "Add one or more users to a group") self.add_id_name_arguments(adduser, "group") group = self.add_user_arguments(adduser, action=" to add to the group") group.add_argument("--as-owner", action="store_true", default=False, help="Add the users as owners of the group") removeuser = parser.add(sub, self.removeuser, "Remove one or more users from a group") self.add_id_name_arguments(removeuser, "group") group = self.add_user_arguments(removeuser, action=" to remove from the group") group.add_argument("--as-owner", action="store_true", default=False, help="Remove the users from the group owner list") for x in (add, perms, list, copyusers, adduser, removeuser): x.add_login_arguments() def add_permissions_arguments(self, parser): group = parser.add_mutually_exclusive_group() group.add_argument( "--perms", help="Group permissions set as string, e.g. 'rw----' ") group.add_argument("--type", help="Group permissions set symbolically", default="private", choices=list(defaultperms.keys())) def parse_perms(self, args): from omero_model_PermissionsI import PermissionsI as Perms perms = getattr(args, "perms", None) if not perms: perms = defaultperms[args.type] try: return Perms(perms) except ValueError as ve: self.ctx.die(505, str(ve)) @admin_only(AdminPrivilegeModifyGroup) def add(self, args): import omero from omero.rtypes import rbool, rstring from omero_model_ExperimenterGroupI import ExperimenterGroupI as Grp perms = self.parse_perms(args) c = self.ctx.conn(args) g = Grp() g.name = rstring(args.name) g.ldap = rbool(False) g.details.permissions = perms admin = c.getSession().getAdminService() try: grp = admin.lookupGroup(args.name) if grp: if args.ignore_existing: self.ctx.out("Group exists: %s (id=%s)" % (args.name, grp.id.val)) return else: self.ctx.die( 3, "Group exists: %s (id=%s)" % (args.name, grp.id.val)) except omero.ApiUsageException: pass # Apparently no such group exists try: id = admin.createGroup(g) self.ctx.out("Added group %s (id=%s) with permissions %s" % (args.name, id, perms)) except omero.ValidationException as ve: # Possible, though unlikely after previous check if self.exc.is_constraint_violation(ve): self.ctx.die(66, "Group already exists: %s" % args.name) else: self.ctx.die(67, "Unknown ValidationException: %s" % ve.message) except omero.SecurityViolation as se: self.ctx.die(68, "Security violation: %s" % se.message) except omero.ServerError as se: self.ctx.die(4, "%s: %s" % (type(se), se.message)) def perms(self, args): import omero perms = self.parse_perms(args) c = self.ctx.conn(args) a = c.sf.getAdminService() gid, g = self.parse_groupid(a, args) old_perms = str(g.details.permissions) if old_perms == str(perms): self.ctx.out("Permissions for group %s (id=%s) already %s" % (g.name.val, gid, perms)) else: try: chmod = omero.cmd.Chmod2( targetObjects={'ExperimenterGroup': [gid]}, permissions=str(perms)) c.submit(chmod) self.ctx.out("Changed permissions for group %s (id=%s) to %s" % (g.name.val, gid, perms)) except omero.CmdError as ce: import traceback self.ctx.dbg(traceback.format_exc()) self.ctx.die( 504, "Cannot change permissions for group %s" " (id=%s) to %s: %s" % (g.name.val, gid, perms, ce.err)) def list(self, args): c = self.ctx.conn(args) groups = c.sf.getAdminService().lookupGroups() self.output_groups_list(groups, args) def info(self, args): c = self.ctx.conn(args) a = c.sf.getAdminService() [gid, groups] = self.list_groups(a, args, use_context=True) self.output_groups_list(groups, args) def listusers(self, args): c = self.ctx.conn(args) admin = c.sf.getAdminService() [gids, groups] = self.list_groups(admin, args, use_context=True) if len(gids) != 1: self.ctx.die(516, 'Too many group arguments') users = admin.containedExperimenters(gids[0]) self.output_users_list(admin, users, args) def parse_groupid(self, a, args): if args.id: group = getattr(args, "id", None) return self.find_group_by_id(a, group, fatal=True) elif args.name: group = getattr(args, "name", None) return self.find_group_by_name(a, group, fatal=True) else: self.error_no_input_group(fatal=True) def filter_users(self, uids, group, owner=False, join=True): if owner: uid_list = self.getownerids(group) relation = "owner of" else: uid_list = self.getuserids(group) relation = "in" for uid in list(uids): if join: if uid in uid_list: self.ctx.out("%s is already %s group %s" % (uid, relation, group.id.val)) uids.remove(uid) else: if uid not in uid_list: self.ctx.out("%s is not %s group %s" % (uid, relation, group.id.val)) uids.remove(uid) return uids def copyusers(self, args): c = self.ctx.conn(args) a = c.sf.getAdminService() f_gid, f_grp = self.find_group(a, args.from_group, fatal=True) t_gid, t_grp = self.find_group(a, args.to_group, fatal=True) if args.as_owner: uids = self.getownerids(f_grp) else: uids = self.getuserids(f_grp) uids = self.filter_users(uids, t_grp, args.as_owner, True) if args.as_owner: self.addownersbyid(a, t_grp, uids) self.ctx.out("Owners of %s copied to %s" % (args.from_group, args.to_group)) else: self.addusersbyid(a, t_grp, uids) self.ctx.out("Users of %s copied to %s" % (args.from_group, args.to_group)) def adduser(self, args): c = self.ctx.conn(args) a = c.sf.getAdminService() group = self.parse_groupid(a, args)[1] [uids, users] = self.list_users(a, args, use_context=False) uids = self.filter_users(uids, group, args.as_owner, True) if args.as_owner: self.addownersbyid(a, group, uids) else: self.addusersbyid(a, group, uids) def removeuser(self, args): c = self.ctx.conn(args) a = c.sf.getAdminService() group = self.parse_groupid(a, args)[1] [uids, users] = self.list_users(a, args, use_context=False) uids = self.filter_users(uids, group, args.as_owner, False) if args.as_owner: self.removeownersbyid(a, group, uids) else: self.removeusersbyid(a, group, uids)