Hi list,

WARNING: huge brain dump ahead.

During investigation of https://fedorahosted.org/freeipa/ticket/4305 me and Petr Spaced (CC'ed) came to a conclusion that the IPA realm autodiscovery code used by ipa-client-install is so convoluted, complex and hard to understand that the cost of fixing a bug/adding a behavioral change (there are some other tickets dealing with ipadiscovery, e.g. see https://fedorahosted.org/freeipa/ticket/5270 https://fedorahosted.org/freeipa/ticket/3912 ) can potentially be higher that a more large-scale rewrite of the module and related codebase.

Since we plan to do some general refactoring work anyway, I would like to discuss the possible course of action we may take to tackle this issue. I would like to present the following options we have been discussing so far:

1.) Do a substantial rewrite of existing code ("ipaclient/ipadiscovery.py")

We may take the existing IPADiscovery class and try rewrite it in order to get a more concise and deterministic code, which will:

* rely more on python-dns and answers provided by resolver (e.g. we are directly parsing resolv.conf for available domains when we can ask the resolver to get domains for us) * be more pythonic (replace error codes with thrown exceptions, clean up numerous C-isms etc.) * not try to outsmart user when server/realm/domain is specified beforehand. Currently, even if you specify all three options, there is still some DNS discovery performed, hence bug #4305. I think that one you specify server(s), not magic should be performed and the discovery process should be reduced to checking whether they are IPA servers and pull all other info (like realm) from them.

This may be a considerable effort requiring some time to implement and get right, but IMHO still comparable to the time spent iteratively placing 'if' statements into the existing code and hoping to not break anything. I would even argue it is not worth the effort because we can

2.) Use realmd dbus interface to do DNS discovery

I have attached aquick and dirty script I have slapped together to leverage 'org.freedesktop.realmd.Discover' interface to do IPA realm discovery for us. This has a lot of appeal to me since we are leveraging existing codebase for DNS discovery and will have to handle only cases when the user manually specifies a list of IPA servers for the client.

This however pulls in realmd as a (potentially circular) dependency for ipa client, and when we find bug in the discovery code, we will have to poke upstream (Stef or Sumit I think) to fix it.

So from the long-term point of view, Jan Cholasta's (CC'ed) suggestion to:

3.) Split out IPA discovery portion of realmd to a separate C library shared between IPA and realmd

may be best. Both projects will have shared codebase (maintained either by us or realmd devs), which can be reused also by other people to create their own discovery/enrollment solution. This would however require sustained and concerted efforts of both teams to create the library and possibly rewrite realmd to accommodate this change.

There may be some other options viable for us, if so please mention them in a reply. Also please correct any piece of information I got wrong.

TL;DR: IPA realm/domain discovery is a mess, please suggest a way to fix it.

Martin^3 Babinsky
#!/usr/bin/env python

import dbus
from dns import resolver

bus = dbus.SystemBus()
realmd_name = 'org.freedesktop.realmd'
realmd_path = '/org/freedesktop/realmd'

def discover_realm(domain_name, next_routine):
    proxy = bus.get_object(realmd_name, realmd_path)
    provider = dbus.Interface(proxy, '.'.join([realmd_name, 'Provider']))

    realms = provider.Discover(domain_name, {'server-software': 'ipa'})[1]
    for realm in realms:
         realm_props = dbus.Interface(bus.get_object(realmd_name, realm), 

def print_realm_info():
        while True:
            realm_prop = (yield)

            if realm_prop is not None:
                print "==="
                print "Realm: "
                print realm_prop.Get('org.freedesktop.realmd.Kerberos', 'RealmName')

                print "Domain: "
                print realm_prop.Get('org.freedesktop.realmd.Kerberos', 'DomainName')
    except GeneratorExit:
        print "=== Done ==="

if __name__ == '__main__':
    res = resolver.get_default_resolver()
    client_domain = str(res.domain)

    print "Searching for realms using default domain name {}".format(

    p = print_realm_info()
    discover_realm(client_domain, p)
Manage your subscription for the Freeipa-devel mailing list:
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to