SSO:  An easier way to join your CentOS 5 Openfire server to an AD Domain

Version 3

    The official documentation for SSO in Openfire is at SSO Configuration. Please read that document first to understand the concepts used.

     

    Many of the SSO Documents already out there describe using ktpass.exe and related tools in order to generate the keytab for a service.  This can be unwieldy, and does not scale -- if you want to install other kerberized services (such as Apache/HTTP), remapping a user to a different princ with ktpass.exe will increase the kvno, and render your previous service useless.

     

    The answer is to integrate your server more tightly into the Active Directory, and advancements in Samba make this possible (without making you 100% dependent on Samba!).

     

    The process is relatively straightforward with a modern OS.  For this example, I am using CentOS 5.  My machine, openfire.example.com, is in my network DMZ, communicating with kdc.example.local, which is behind my firewall.  My domain name is EXAMPLE.LOCAL.

     

    Required software packages (that are not installed by default):

    cyrus-sasl-gssapi

    samba

    samba-common

    openfire

     

    The most important part of any native Kerberos communication is correct DNS -- you need to ensure that forward and reverse DNS for your Openfire server is correct, and that the hosts file and hostname on the machine agree with it.  DNS configuration is an exercise left to the reader, but /etc/hosts on openfire.example.com reads:

     

    127.0.0.1               localhost localhost.localdomain
    172.17.5.5              openfire openfire.example.com
    

     

     

    In my environment, we elect to use DNS to locate our domain controllers, so the krb5.conf is straightforward and short:

     

     

     

     

     

    [logging]
     default = FILE:/var/log/krb5libs.log
     kdc = FILE:/var/log/krb5kdc.log
     admin_server = FILE:/var/log/kadmind.log
     
    [libdefaults]
     default_realm = EXAMPLE.LOCAL
     dns_lookup_realm = true
     dns_lookup_kdc = true
     
    [domain_realm]
     .example.com = EXAMPLE.LOCAL
     
    [appdefaults]
     pam = {
       debug = false
       ticket_lifetime = 36000
       renew_lifetime = 36000
       forwardable = true
       krb4_convert = false
       validate = true
     }
    

     

     

    At this point, you should be able to use kinit to get credentials for a user from your AD domain.  If you can't, stop and think about what you did wrong.

     

     

    Keytab population

    In order to properly populate the server keytab with principals, we are going to utilize Samba.  If you don't plan on using Samba for anything else, this is easy.  Delete everything from /etc/samba/smb.conf and replace with the following:

    workgroup = EXAMPLE
    security = ads
    realm = example.local
    use kerberos keytab = true
    password server = kdc.example.local kdc2.example.local
    

     

     

    Unfortunately, Samba doesn't support DNS lookups of KDCs (that I have found), so two of my KDCs are hard-coded here.

     

    Now, we can utilize the "net" command to join the server to the domain, and populate the keytab, using a domain administrator login.  You can replace "Administrator" with any user that is a domain or enterprise admin.

     

     

    net -UAdministrator ads join
    

     

     

    It will prompt you for the password, churn butter for a bit, and report success!  If it does not, the most common issues are DNS related -- go back and re-check your forward and reverse DNS, and ensure that there are no conflicting entries in /etc/hosts.

     

    Doing this, however, only got us our host principals.  We need to request a new principal for the XMPP service from the domain controller:

    net -UAdministrator ads keytab add xmpp
    

     

     

    Now, you can use klist to confirm that you were able to join the domain and receive the principals:

    [root@openfire ~]# klist -k /etc/krb5.keytab
    Keytab name: FILE:/etc/krb5.keytab
    KVNO Principal
    ---- --------------------------------------------------------------------------
       2 host/openfire.example.com@EXAMPLE.LOCAL
       2 host/openfire.example.com@EXAMPLE.LOCAL
       2 host/openfire.example.com@EXAMPLE.LOCAL
       2 host/openfire@EXAMPLE.LOCAL
       2 host/openfire@EXAMPLE.LOCAL
       2 host/openfire@EXAMPLE.LOCAL
       2 openfire$@EXAMPLE.LOCAL
       2 openfire$@EXAMPLE.LOCAL
       2 openfire$@EXAMPLE.LOCAL
       2 xmpp/openfire.example.com@EXAMPLE.LOCAL
       2 xmpp/openfire.example.com@EXAMPLE.LOCAL
       2 xmpp/openfire.example.com@EXAMPLE.LOCAL
       2 xmpp/openfire@EXAMPLE.LOCAL
       2 xmpp/openfire@EXAMPLE.LOCAL
       2 xmpp/openfire@EXAMPLE.LOCAL
    

     

     

    While this is all fine and dandy, /etc/krb5.keytab is only readable by root (as it should be!) -- we will need to extract just the xmpp princ to another keytab that is readable by the daemon user.  To do this, use ktutil to rkt /etc/krb5.keytab, delent everything but the xmpp principals, and wkt /opt/openfire/krb5.xmpp.keytab.  Then, change ownership of the keytab to match whatever user you run Openfire as.  In the end, it should look like this:

     

     

    [root@openfire-test ~]# klist -k /opt/openfire/krb5.xmpp.keytab
    Keytab name: FILE:/opt/openfire/krb5.xmpp.keytab
    KVNO Principal
    ---- --------------------------------------------------------------------------
       2 xmpp/openfire.example.com@EXAMPLE.LOCAL
       2 xmpp/openfire.example.com@EXAMPLE.LOCAL
       2 xmpp/openfire.example.com@EXAMPLE.LOCAL
       2 xmpp/openfire@EXAMPLE.LOCAL
       2 xmpp/openfire@EXAMPLE.LOCAL
       2 xmpp/openfire@EXAMPLE.LOCAL
    
    

     

     

     

     

    Configure Openfire's GSSAPI

    We deviate slightly from documents presented by others here, as there is one small change we need to make.  Since the xmpp service principal is only a service principal, and not mapped to an actual user account, we need to ensure that Java never attempts to treat it like a user account.  In order to assure that, we have to add an additional line to gss.conf -- isInitiator.

    com.sun.security.jgss.accept {
        com.sun.security.auth.module.Krb5LoginModule
        required
        storeKey=true
        keyTab="/opt/openfire/krb5.xmpp.keytab"
        doNotPrompt=true
        useKeyTab=true
        realm="EXAMPLE.LOCAL"
        principal="xmpp/openfire.example.com@EXAMPLE.LOCAL"
        debug=true
        isInitiator=false;
    };
    

     

     

    The rest of the configuration is the same as has already been laid out in other documents, such as SSO Configuration