示例#1
0
class LdapControl(UserGroupControl):

    def _configure(self, parser):

        self.exc = ExceptionHandler()

        sub = parser.sub()

        active = parser.add(
            sub, self.active,
            help="Return code shows if LDAP is configured (admins-only)")

        list = parser.add(
            sub, self.list,
            help="List all OMERO users with DNs")
        list.add_style_argument()

        getdn = parser.add(sub, self.getdn, help="Get DN for user on stdout")
        setdn = parser.add(
            sub, self.setdn,
            help="""Enable LDAP login for user (admins only)

Once LDAP login is enabled for a user, the password set via OMERO is
ignored, and any attempt to change it will result in an error. When
you disable LDAP login, the previous password will be in effect, but if the
user never had a password, one will need to be set!""")

        for x in (getdn, setdn):
            self.add_user_and_group_arguments(x)
        setdn.add_argument("choice", action="store",
                           help="Enable/disable LDAP login (true/false)")

        discover = parser.add(
            sub, self.discover,
            help="""Discover DNs for existing OMERO users or groups

This command works in the context of users or groups. Specifying
--groups will only discover groups, that is check which group exists in
the LDAP server and OMERO and has the "ldap" flag disabled - such groups
will be presented to the user. Omitting --groups will apply the same logic
to users.""")
        discover.add_argument(
            "--commands", action="store_true", default=False,
            help="Print setdn commands on standard out")
        discover.add_argument("--groups", action="store_true", default=False,
                              help="Discover LDAP groups, not users.")

        create = parser.add(
            sub, self.create,
            help="Create a local user based on LDAP username (admins only)"
        )
        create.add_argument(
            "username", help="LDAP username of user to be created")

        for x in (active, list, getdn, setdn, discover, create):
            x.add_login_arguments()

    @admin_only
    def active(self, args):
        c = self.ctx.conn(args)
        ildap = c.sf.getLdapService()

        if ildap.getSetting():
            self.ctx.out("Yes")
        else:
            self.ctx.die(1, "No")

    @admin_only
    def list(self, args):
        c = self.ctx.conn(args)
        iadmin = c.sf.getAdminService()

        from omero.rtypes import unwrap
        from omero.util.text import TableBuilder
        list_of_dn_user_maps = unwrap(iadmin.lookupLdapAuthExperimenters())
        if list_of_dn_user_maps is None:
            return

        count = 0
        tb = TableBuilder("#")
        if args.style:
            tb.set_style(args.style)
        tb.cols(["Id", "OmeName", "DN"])
        for map in list_of_dn_user_maps:
            for dn, id in map.items():
                try:
                    exp = iadmin.getExperimenter(id)
                except:
                    self.ctx.err("Bad experimenter: %s" % id)

                tb.row(count, *(id, exp.omeName.val, dn))
                count += 1
        self.ctx.out(str(tb.build()))

    @admin_only
    def getdn(self, args):
        c = self.ctx.conn(args)
        iadmin = c.sf.getAdminService()
        ildap = c.sf.getLdapService()

        dn = None

        if args.user_name:
            [uid, u] = self.find_user_by_name(iadmin, args.user_name,
                                              fatal=True)
            if u and u.getLdap().val:
                name = u.getOmeName().val
                dn = name + ": " + ildap.findDN(name)
        elif args.user_id:
            [uid, u] = self.find_user_by_id(iadmin, args.user_id, fatal=True)
            if u and u.getLdap().val:
                name = u.getOmeName().val
                dn = name + ": " + ildap.findDN(name)
        elif args.group_name:
            [gid, g] = self.find_group_by_name(iadmin, args.group_name,
                                               fatal=True)
            if g and g.getLdap().val:
                name = g.getName().val
                dn = name + ": " + ildap.findGroupDN(name)
        elif args.group_id:
            [gid, g] = self.find_group_by_id(iadmin, args.group_id, fatal=True)
            if g and g.getLdap().val:
                name = g.getName().val
                dn = name + ": " + ildap.findGroupDN(name)

        if dn is not None and dn.strip():
            self.ctx.out(dn)

    @admin_only
    def setdn(self, args):
        c = self.ctx.conn(args)
        iupdate = c.sf.getUpdateService()
        iadmin = c.sf.getAdminService()

        obj = None

        if args.user_name:
            [uid, obj] = self.find_user_by_name(iadmin, args.user_name,
                                                fatal=True)
        elif args.user_id:
            [uid, obj] = self.find_user_by_id(iadmin, args.user_id, fatal=True)
        elif args.group_name:
            [gid, obj] = self.find_group_by_name(iadmin, args.group_name,
                                                 fatal=True)
        elif args.group_id:
            [gid, obj] = self.find_group_by_id(iadmin, args.group_id,
                                               fatal=True)

        if obj is not None:
            obj.setLdap(rbool(args.choice.lower()
                              in ("yes", "true", "t", "1")))
            iupdate.saveObject(obj)

    @admin_only
    def discover(self, args):
        c = self.ctx.conn(args)
        ildap = c.sf.getLdapService()
        elements = {}
        element_name = "users"

        if args.groups:
            element_name = "groups"
            elements = ildap.discoverGroups()
        else:
            elements = ildap.discover()

        if len(elements) > 0:
            self.ctx.out("Following LDAP %s are disabled in OMERO:"
                         % element_name)
            for e in elements:
                if args.groups:
                    if args.commands:
                        self.ctx.out("%s ldap setdn --group-name %s true"
                                     % (sys.argv[0], e.getName().getValue()))
                    else:
                        self.ctx.out("Group=%s\tname=%s"
                                     % (e.getId().getValue(),
                                        e.getName().getValue()))
                else:
                    if args.commands:
                        self.ctx.out("%s ldap setdn --user-name %s true"
                                     % (sys.argv[0],
                                        e.getOmeName().getValue()))
                    else:
                        self.ctx.out("Experimenter=%s\tomeName=%s"
                                     % (e.getId().getValue(),
                                        e.getOmeName().getValue()))

    @admin_only
    def create(self, args):
        c = self.ctx.conn(args)
        ildap = c.sf.getLdapService()
        iadmin = c.sf.getAdminService()

        import omero
        import Ice
        try:
            exp = ildap.createUser(args.username)
            dn = iadmin.lookupLdapAuthExperimenter(exp.id.val)
            self.ctx.out("Added user %s (id=%s) with DN=%s" %
                         (exp.omeName.val, exp.id.val, dn))
        except omero.ValidationException as ve:
            self.ctx.die(132, ve.message)
        except Ice.RequestFailedException as rfe:
            self.ctx.die(133, self.exc.handle_failed_request(rfe))
示例#2
0
class LdapControl(BaseControl):

    def _configure(self, parser):

        self.exc = ExceptionHandler()

        sub = parser.sub()

        active = parser.add(
            sub, self.active,
            help="Return code shows if LDAP is configured (admins-only)")

        list = parser.add(
            sub, self.list,
            help="List all OMERO users with DNs")
        list.add_style_argument()

        getdn = parser.add(sub, self.getdn, help="Get DN for user on stdout")
        setdn = parser.add(
            sub, self.setdn,
            help="""Set DN for user (admins only)

Once the DN is set for a user, the password set via OMERO is
ignored, and any attempt to change it will result in an error. When
you remove the DN, the previous password will be in effect, but if the
user never had a password, one will need to be set!""")

        for x in (getdn, setdn):
            x.add_argument("username", help="User's OMERO login name")
        setdn.add_argument(
            "dn", help="User's LDAP distinguished name. If empty, LDAP will"
            " be disabled for the user")

        discover = parser.add(
            sub, self.discover,
            help="Discover distinguished names for existing OMERO users")
        discover.add_argument(
            "--commands", action="store_true", default=False,
            help="Print setdn commands on standard out")
        discover.add_argument(
            "--urls", help="Override OMERO omero.ldap.urls setting")
        discover.add_argument(
            "--base", help="Override OMERO omero.ldap.base setting")

        create = parser.add(
            sub, self.create,
            help="Create a local user based on LDAP username (admins only)"
            )
        create.add_argument(
            "username", help="LDAP username of user to be created")

        for x in (active, list, getdn, setdn, discover, create):
            x.add_login_arguments()

    def __import_ldap__(self):
        try:
            import ldap
        except:
            self.ctx.die(155, """Python "ldap"  module is not installed""")
        return ldap

    def active(self, args):
        c = self.ctx.conn(args)
        ildap = c.sf.getLdapService()

        import omero
        try:
            if ildap.getSetting():
                self.ctx.out("Yes")
            else:
                self.ctx.die(1, "No")
        except omero.SecurityViolation:
            self.error_admin_only(fatal=True)

    def list(self, args):
        c = self.ctx.conn(args)
        iadmin = c.sf.getAdminService()

        import omero
        from omero.rtypes import unwrap
        from omero.util.text import TableBuilder
        try:

            list_of_dn_user_maps = unwrap(iadmin.lookupLdapAuthExperimenters())
            if list_of_dn_user_maps is None:
                return

            count = 0
            tb = TableBuilder("#")
            if args.style:
                tb.set_style(args.style)
            tb.cols(["Id", "OmeName", "DN"])
            for map in list_of_dn_user_maps:
                for dn, id in map.items():
                    try:
                        exp = iadmin.getExperimenter(id)
                    except:
                        self.ctx.err("Bad experimenter: %s" % id)

                    tb.row(count, *(id, exp.omeName.val, dn))
                    count += 1
            self.ctx.out(str(tb.build()))

        except omero.SecurityViolation:
            self.error_admin_only(fatal=True)

    def getdn(self, args):
        c = self.ctx.conn(args)
        iadmin = c.sf.getAdminService()

        try:
            exp = iadmin.lookupExperimenter(args.username)
        except:
            self.ctx.die(134, "Unknown user: %s" % args.username)

        dn = iadmin.lookupLdapAuthExperimenter(exp.id.val)
        if dn is not None and dn.strip():
            self.ctx.out(dn)
        else:
            self.ctx.die(136, "DN Not found: %s" % dn)

    def setdn(self, args):
        c = self.ctx.conn(args)
        ildap = c.sf.getLdapService()
        iadmin = c.sf.getAdminService()

        try:
            exp = iadmin.lookupExperimenter(args.username)
        except:
            self.ctx.die(134, "Unknown user: %s" % args.username)

        import omero
        try:
            ildap.setDN(exp.id, args.dn)
        except omero.SecurityViolation:
            self.error_admin_only(fatal=True)

    def discover(self, args):

        import omero
        ldap = self.__import_ldap__()

        c = self.ctx.conn(args)
        iconfig = c.sf.getConfigService()
        iadmin = c.sf.getAdminService()
        iquery = c.sf.getQueryService()

        LDAP_PROPERTIES = """
        omero.ldap.urls
        omero.ldap.username
        omero.ldap.password
        omero.ldap.base
        omero.ldap.user_filter
        omero.ldap.user_mapping
        omero.ldap.group_filter
        omero.ldap.group_mapping
        omero.ldap.new_user_group
        """.split()

        cfg = dict()
        for key in LDAP_PROPERTIES:
            cfg[key.split(".")[-1]] = iconfig.getConfigValue(key)

        urls = args.urls and args.urls or cfg["urls"]
        basedn = args.base and args.base or cfg["base"]

        for url in urls.split(","):

            self.ctx.err("Connecting to %s..." % url)

            ld = ldap.initialize(url)
            ld.simple_bind_s(cfg['username'], cfg['password'])

            user_filter = cfg["user_filter"]
            user_mapping = cfg["user_mapping"]
            user_mapping = user_mapping.split(",")
            omeName_mapping = None
            for um in user_mapping:
                parts = um.split("=")
                if parts[0] == "omeName":
                    omeName_mapping = parts[1]

            from ldap.controls import SimplePagedResultsControl

            cookie = ''
            # This is the limit for Active Directory, 1000. However
            # the LDAP connection has a sizeLimit that overrides
            # this value if the page_size exceeds it so it is safe
            # to enter pretty much anything here when using paged results.
            page_size = 1000

            results = []
            first = True
            page_control = SimplePagedResultsControl(False, page_size, cookie)

            while first or page_control.cookie:
                first = False
                try:
                    msgid = ld.search_ext(
                        basedn, ldap.SCOPE_SUBTREE,
                        user_filter, serverctrls=[page_control]
                    )
                except:
                    self.ctx.die(1, "Failed to execute LDAP search")

                result_type, results, msgid, serverctrls = ld.result3(msgid)
                if serverctrls:
                    page_control.cookie = serverctrls[0].cookie

                user_names = set()
                user_dns = {}
                for dn, entry in results:
                    omeName = entry[omeName_mapping]
                    if isinstance(omeName, (list, tuple)):
                        if len(omeName) == 1:
                            omeName = omeName[0]
                            user_names.add(omeName)
                            user_dns[omeName] = dn
                        else:
                            self.ctx.err("Failed to unwrap omeName: %s" %
                                         omeName)
                            continue

                if not user_names:
                    continue  # Early exit!

                from omero.rtypes import rlist
                from omero.rtypes import rstring
                from omero.rtypes import unwrap
                params = omero.sys.ParametersI()
                params.add("names", rlist([rstring(x) for x in user_names]))
                id_names = unwrap(iquery.projection(
                    "select id, omeName from Experimenter "
                    "where omeName in (:names)", params))

                for eid, omeName in id_names:
                    try:
                        olddn = iadmin.lookupLdapAuthExperimenter(eid)
                        dn = user_dns[omeName]
                    except omero.ApiUsageException:
                        continue  # Unknown user

                    if olddn:
                        if olddn.lower() != dn.lower():
                            self.ctx.err("Found different DN for %s: %s"
                                         % (omeName, olddn))
                        else:
                            self.ctx.dbg("DN already set for %s: %s"
                                         % (omeName, olddn))
                    else:
                        if args.commands:
                            self.ctx.out("%s ldap setdn %s %s"
                                         % (sys.argv[0], omeName, dn))
                        else:
                            self.ctx.out("Experimenter:%s\tomeName=%s\t%s"
                                         % (eid, omeName, dn))

    def create(self, args):
        c = self.ctx.conn(args)
        ildap = c.sf.getLdapService()
        iadmin = c.sf.getAdminService()

        import omero
        import Ice
        try:
            exp = ildap.createUser(args.username)
            dn = iadmin.lookupLdapAuthExperimenter(exp.id.val)
            self.ctx.out("Added user %s (id=%s) with DN=%s" %
                         (exp.omeName.val, exp.id.val, dn))
        except omero.SecurityViolation:
            self.ctx.die(131, "SecurityViolation: Admins only!")
        except omero.ValidationException as ve:
            self.ctx.die(132, ve.message)
        except Ice.RequestFailedException as rfe:
            self.ctx.die(133, self.exc.handle_failed_request(rfe))
示例#3
0
class LdapControl(UserGroupControl):
    def _configure(self, parser):

        self.exc = ExceptionHandler()

        sub = parser.sub()

        active = parser.add(
            sub,
            self.active,
            help="Return code shows if LDAP is configured (admins-only)")

        list = parser.add(sub, self.list, help="List all OMERO users with DNs")
        list.add_style_argument()

        getdn = parser.add(sub, self.getdn, help="Get DN for user on stdout")
        setdn = parser.add(
            sub,
            self.setdn,
            help="""Enable or disable LDAP login for user (admins only)

Once LDAP login is enabled for a user, the password set via OMERO is
ignored, and any attempt to change it will result in an error. When
you disable LDAP login, the previous password will be in effect, but if the
user never had a password, one will need to be set!""")

        for x in (getdn, setdn):
            self.add_user_and_group_arguments(x)
        setdn.add_argument("choice",
                           action="store",
                           help="Enable/disable LDAP login (true/false)")

        discover = parser.add(
            sub,
            self.discover,
            help="""Discover DNs for existing OMERO users or groups

This command works in the context of users or groups. Specifying
--groups will only discover groups, that is check which group exists in
the LDAP server and OMERO and has the "ldap" flag disabled - such groups
will be presented to the user. Omitting --groups will apply the same logic
to users.""")
        discover.add_argument("--commands",
                              action="store_true",
                              default=False,
                              help="Print setdn commands on standard out")
        discover.add_argument("--groups",
                              action="store_true",
                              default=False,
                              help="Discover LDAP groups, not users.")

        create = parser.add(
            sub,
            self.create,
            help="Create a local user based on LDAP username (admins only)")
        create.add_argument("username",
                            help="LDAP username of user to be created")

        for x in (active, list, getdn, setdn, discover, create):
            x.add_login_arguments()

    @admin_only(full_admin=False)  # IConfig privilege
    def active(self, args):
        c = self.ctx.conn(args)
        ildap = c.sf.getLdapService()

        if ildap.getSetting():
            self.ctx.out("Yes")
        else:
            self.ctx.die(1, "No")

    def list(self, args):
        c = self.ctx.conn(args)
        iadmin = c.sf.getAdminService()

        from omero.rtypes import unwrap
        from omero.util.text import TableBuilder
        list_of_dn_user_maps = unwrap(iadmin.lookupLdapAuthExperimenters())
        if list_of_dn_user_maps is None:
            return

        count = 0
        tb = TableBuilder("#")
        if args.style:
            tb.set_style(args.style)
        tb.cols(["Id", "OmeName", "DN"])
        for map in list_of_dn_user_maps:
            for dn, id in list(map.items()):
                try:
                    exp = iadmin.getExperimenter(id)
                except:
                    self.ctx.err("Bad experimenter: %s" % id)

                tb.row(count, *(id, exp.omeName.val, dn))
                count += 1
        self.ctx.out(str(tb.build()))

    @admin_only(full_admin=False)  # ILdap privilege
    def getdn(self, args):
        c = self.ctx.conn(args)
        iadmin = c.sf.getAdminService()
        ildap = c.sf.getLdapService()

        dn = None

        if args.user_name:
            [uid, u] = self.find_user_by_name(iadmin,
                                              args.user_name,
                                              fatal=True)
            if u and u.getLdap().val:
                name = u.getOmeName().val
                dn = name + ": " + ildap.findDN(name)
        elif args.user_id:
            [uid, u] = self.find_user_by_id(iadmin, args.user_id, fatal=True)
            if u and u.getLdap().val:
                name = u.getOmeName().val
                dn = name + ": " + ildap.findDN(name)
        elif args.group_name:
            [gid, g] = self.find_group_by_name(iadmin,
                                               args.group_name,
                                               fatal=True)
            if g and g.getLdap().val:
                name = g.getName().val
                dn = name + ": " + ildap.findGroupDN(name)
        elif args.group_id:
            [gid, g] = self.find_group_by_id(iadmin, args.group_id, fatal=True)
            if g and g.getLdap().val:
                name = g.getName().val
                dn = name + ": " + ildap.findGroupDN(name)

        if dn is not None and dn.strip():
            self.ctx.out(dn)

    @admin_only(AdminPrivilegeModifyGroup)
    def update_group(self, iupdate, group):
        iupdate.saveObject(group)

    @admin_only(AdminPrivilegeModifyUser)
    def update_user(self, iupdate, user):
        iupdate.saveObject(user)

    @admin_only(full_admin=False)  # See update_user/update_group
    def setdn(self, args):
        c = self.ctx.conn(args)
        iupdate = c.sf.getUpdateService()
        iadmin = c.sf.getAdminService()

        obj = None

        if args.user_name:
            [uid, obj] = self.find_user_by_name(iadmin,
                                                args.user_name,
                                                fatal=True)
        elif args.user_id:
            [uid, obj] = self.find_user_by_id(iadmin, args.user_id, fatal=True)
        elif args.group_name:
            [gid, obj] = self.find_group_by_name(iadmin,
                                                 args.group_name,
                                                 fatal=True)
        elif args.group_id:
            [gid, obj] = self.find_group_by_id(iadmin,
                                               args.group_id,
                                               fatal=True)

        if obj is not None:
            from omero.model import Experimenter, ExperimenterGroup
            obj.setLdap(rbool(args.choice.lower() in ("yes", "true", "t",
                                                      "1")))
            if isinstance(obj, ExperimenterGroup):
                self.update_group(iupdate, obj)
            elif isinstance(obj, Experimenter):
                self.update_user(iupdate, obj)

    @admin_only(full_admin=False)  # ILdap privilege
    def discover(self, args):
        c = self.ctx.conn(args)
        ildap = c.sf.getLdapService()
        elements = {}
        element_name = "users"

        if args.groups:
            element_name = "groups"
            elements = ildap.discoverGroups()
        else:
            elements = ildap.discover()

        if len(elements) > 0:
            self.ctx.out("Following LDAP %s are disabled in OMERO:" %
                         element_name)
            for e in elements:
                if args.groups:
                    if args.commands:
                        self.ctx.out("%s ldap setdn --group-name %s true" %
                                     (sys.argv[0], e.getName().getValue()))
                    else:
                        self.ctx.out(
                            "Group=%s\tname=%s" %
                            (e.getId().getValue(), e.getName().getValue()))
                else:
                    if args.commands:
                        self.ctx.out("%s ldap setdn --user-name %s true" %
                                     (sys.argv[0], e.getOmeName().getValue()))
                    else:
                        self.ctx.out(
                            "Experimenter=%s\tomeName=%s" %
                            (e.getId().getValue(), e.getOmeName().getValue()))

    @admin_only(AdminPrivilegeModifyUser, AdminPrivilegeModifyGroupMembership)
    def create(self, args):
        c = self.ctx.conn(args)
        ildap = c.sf.getLdapService()
        iadmin = c.sf.getAdminService()

        import omero
        import Ice
        try:
            exp = ildap.createUser(args.username)
            dn = iadmin.lookupLdapAuthExperimenter(exp.id.val)
            self.ctx.out("Added user %s (id=%s) with DN=%s" %
                         (exp.omeName.val, exp.id.val, dn))
        except omero.ValidationException as ve:
            self.ctx.die(132, ve.message)
        except Ice.RequestFailedException as rfe:
            self.ctx.die(133, self.exc.handle_failed_request(rfe))
示例#4
0
class LdapControl(BaseControl):
    def _configure(self, parser):

        self.exc = ExceptionHandler()

        sub = parser.sub()

        active = parser.add(
            sub,
            self.active,
            help="Return code shows if LDAP is configured (admins-only)")

        list = parser.add(sub, self.list, help="List all OMERO users with DNs")
        list.add_style_argument()

        getdn = parser.add(sub, self.getdn, help="Get DN for user on stdout")
        setdn = parser.add(sub,
                           self.setdn,
                           help="""Set DN for user (admins only)

Once the DN is set for a user, the password set via OMERO is
ignored, and any attempt to change it will result in an error. When
you remove the DN, the previous password will be in effect, but if the
user never had a password, one will need to be set!""")

        for x in (getdn, setdn):
            x.add_argument("username", help="User's OMERO login name")
        setdn.add_argument(
            "dn",
            help="User's LDAP distinguished name. If empty, LDAP will"
            " be disabled for the user")

        discover = parser.add(
            sub,
            self.discover,
            help="Discover distinguished names for existing OMERO users")
        discover.add_argument("--commands",
                              action="store_true",
                              default=False,
                              help="Print setdn commands on standard out")
        discover.add_argument("--urls",
                              help="Override OMERO omero.ldap.urls setting")
        discover.add_argument("--base",
                              help="Override OMERO omero.ldap.base setting")

        create = parser.add(
            sub,
            self.create,
            help="Create a local user based on LDAP username (admins only)")
        create.add_argument("username",
                            help="LDAP username of user to be created")

        for x in (active, list, getdn, setdn, discover, create):
            x.add_login_arguments()

    def __import_ldap__(self):
        try:
            import ldap
        except:
            self.ctx.die(155, """Python "ldap"  module is not installed""")
        return ldap

    def active(self, args):
        c = self.ctx.conn(args)
        ildap = c.sf.getLdapService()

        import omero
        try:
            if ildap.getSetting():
                self.ctx.out("Yes")
            else:
                self.ctx.die(1, "No")
        except omero.SecurityViolation:
            self.error_admin_only(fatal=True)

    def list(self, args):
        c = self.ctx.conn(args)
        iadmin = c.sf.getAdminService()

        import omero
        from omero.rtypes import unwrap
        from omero.util.text import TableBuilder
        try:

            list_of_dn_user_maps = unwrap(iadmin.lookupLdapAuthExperimenters())
            if list_of_dn_user_maps is None:
                return

            count = 0
            tb = TableBuilder("#")
            if args.style:
                tb.set_style(args.style)
            tb.cols(["Id", "OmeName", "DN"])
            for map in list_of_dn_user_maps:
                for dn, id in map.items():
                    try:
                        exp = iadmin.getExperimenter(id)
                    except:
                        self.ctx.err("Bad experimenter: %s" % id)

                    tb.row(count, *(id, exp.omeName.val, dn))
                    count += 1
            self.ctx.out(str(tb.build()))

        except omero.SecurityViolation:
            self.error_admin_only(fatal=True)

    def getdn(self, args):
        c = self.ctx.conn(args)
        iadmin = c.sf.getAdminService()

        try:
            exp = iadmin.lookupExperimenter(args.username)
        except:
            self.ctx.die(134, "Unknown user: %s" % args.username)

        dn = iadmin.lookupLdapAuthExperimenter(exp.id.val)
        if dn is not None and dn.strip():
            self.ctx.out(dn)
        else:
            self.ctx.die(136, "DN Not found: %s" % dn)

    def setdn(self, args):
        c = self.ctx.conn(args)
        ildap = c.sf.getLdapService()
        iadmin = c.sf.getAdminService()

        try:
            exp = iadmin.lookupExperimenter(args.username)
        except:
            self.ctx.die(134, "Unknown user: %s" % args.username)

        import omero
        try:
            ildap.setDN(exp.id, args.dn)
        except omero.SecurityViolation:
            self.error_admin_only(fatal=True)

    def discover(self, args):

        import omero
        ldap = self.__import_ldap__()

        c = self.ctx.conn(args)
        iconfig = c.sf.getConfigService()
        iadmin = c.sf.getAdminService()
        iquery = c.sf.getQueryService()

        LDAP_PROPERTIES = """
        omero.ldap.urls
        omero.ldap.username
        omero.ldap.password
        omero.ldap.base
        omero.ldap.user_filter
        omero.ldap.user_mapping
        omero.ldap.group_filter
        omero.ldap.group_mapping
        omero.ldap.new_user_group
        """.split()

        cfg = dict()
        for key in LDAP_PROPERTIES:
            cfg[key.split(".")[-1]] = iconfig.getConfigValue(key)

        urls = args.urls and args.urls or cfg["urls"]
        basedn = args.base and args.base or cfg["base"]

        for url in urls.split(","):

            self.ctx.err("Connecting to %s..." % url)

            ld = ldap.initialize(url)
            ld.simple_bind_s(cfg['username'], cfg['password'])

            user_filter = cfg["user_filter"]
            user_mapping = cfg["user_mapping"]
            user_mapping = user_mapping.split(",")
            omeName_mapping = None
            for um in user_mapping:
                parts = um.split("=")
                if parts[0] == "omeName":
                    omeName_mapping = parts[1]

            from ldap.controls import SimplePagedResultsControl

            cookie = ''
            # This is the limit for Active Directory, 1000. However
            # the LDAP connection has a sizeLimit that overrides
            # this value if the page_size exceeds it so it is safe
            # to enter pretty much anything here when using paged results.
            page_size = 1000

            results = []
            first = True
            page_control = SimplePagedResultsControl(False, page_size, cookie)

            while first or page_control.cookie:
                first = False
                try:
                    msgid = ld.search_ext(basedn,
                                          ldap.SCOPE_SUBTREE,
                                          user_filter,
                                          serverctrls=[page_control])
                except:
                    self.ctx.die(1, "Failed to execute LDAP search")

                result_type, results, msgid, serverctrls = ld.result3(msgid)
                if serverctrls:
                    page_control.cookie = serverctrls[0].cookie

                user_names = set()
                user_dns = {}
                for dn, entry in results:
                    omeName = entry[omeName_mapping]
                    if isinstance(omeName, (list, tuple)):
                        if len(omeName) == 1:
                            omeName = omeName[0]
                            user_names.add(omeName)
                            user_dns[omeName] = dn
                        else:
                            self.ctx.err("Failed to unwrap omeName: %s" %
                                         omeName)
                            continue

                if not user_names:
                    continue  # Early exit!

                from omero.rtypes import rlist
                from omero.rtypes import rstring
                from omero.rtypes import unwrap
                params = omero.sys.ParametersI()
                params.add("names", rlist([rstring(x) for x in user_names]))
                id_names = unwrap(
                    iquery.projection(
                        "select id, omeName from Experimenter "
                        "where omeName in (:names)", params))

                for eid, omeName in id_names:
                    try:
                        olddn = iadmin.lookupLdapAuthExperimenter(eid)
                        dn = user_dns[omeName]
                    except omero.ApiUsageException:
                        continue  # Unknown user

                    if olddn:
                        if olddn.lower() != dn.lower():
                            self.ctx.err("Found different DN for %s: %s" %
                                         (omeName, olddn))
                        else:
                            self.ctx.dbg("DN already set for %s: %s" %
                                         (omeName, olddn))
                    else:
                        if args.commands:
                            self.ctx.out("%s ldap setdn %s %s" %
                                         (sys.argv[0], omeName, dn))
                        else:
                            self.ctx.out("Experimenter:%s\tomeName=%s\t%s" %
                                         (eid, omeName, dn))

    def create(self, args):
        c = self.ctx.conn(args)
        ildap = c.sf.getLdapService()
        iadmin = c.sf.getAdminService()

        import omero
        import Ice
        try:
            exp = ildap.createUser(args.username)
            dn = iadmin.lookupLdapAuthExperimenter(exp.id.val)
            self.ctx.out("Added user %s (id=%s) with DN=%s" %
                         (exp.omeName.val, exp.id.val, dn))
        except omero.SecurityViolation:
            self.ctx.die(131, "SecurityViolation: Admins only!")
        except omero.ValidationException as ve:
            self.ctx.die(132, ve.message)
        except Ice.RequestFailedException as rfe:
            self.ctx.die(133, self.exc.handle_failed_request(rfe))