Search code examples
authenticationldapfreeradius

Group level authentication with FreeRadius - LDAP - FreeIPA


I am new to radius, and LDAP and am struggling with group level authentication. I want only users in ldap group netadmin to be authenticated (assuming correct credentials).

In the /etc/raddb/users file I have added this line to the top of the file:

DEFAULT LDAP-Group == "cn=netadmin,cn=groups,cn=accounts,dc=redacted,dc=redacted,dc=com", Auth-Type := LDAP

In the /etc/raddb/sites-enabled/default file, at the bottom of the post-auth block, I have added:

# I am not sure if I need the full ldap path to the group object so I try both
if (LDAP-Group == "netadmin") {
    noop
}
elsif (LDAP-Group == "cn=netadmin,cn=groups,cn=accounts,dc=redacted,dc=redacted,dc=com") {
    noop
}
else {
    reject
}

In the /etc/mods-enabled/ldap file, I have modified these lines only within these blocks (nothing else is deleted, no ordering is changed):

ldap {
    server = 'dc2.redacted.redacted.com'
    server = 'dc1.redacted.redacted.com'

    base_dn = 'cn=accounts,dc=redacted,dc=redacted,dc=com'
    user {
        base_dn = "${..base_dn}"
        filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
        scope = 'sub'
    }
    group {
        base_dn = "${..base_dn}"
        filter = '(objectClass=ipausergroup)'
        membership_attribute = 'memberOf'
        scope = 'sub'
    }
}

With this, I run radtest locally using credentials that have worked before I made edits to attempt group authentication. In the radius debug output from the server, there are a few lines that stick out to me:

(0) ldap: Login attempt by "myuser"
(0) ldap: Using user DN from request "uid=myuser,cn=users,cn=accounts,dc=redacted,dc=redacted,dc=com"
(0) ldap: Waiting for bind result...
(0) ldap: Bind successful
(0) ldap: Bind as user "uid=myuser,cn=users,cn=accounts,dc=redacted,dc=redacted,dc=com" was successful
rlm_ldap (ldap): Released connection (2)
Need 3 more connections to reach 10 spares
rlm_ldap (ldap): Opening additional connection (7), 1 of 25 pending slots used
rlm_ldap (ldap): Connecting to ldap://dc2.redacted.redacted.com:389 ldap://dc1.redacted.redacted.com:389
rlm_ldap (ldap): Waiting for bind result...
rlm_ldap (ldap): Bind successful
(0)     [ldap] = ok
(0)   } # Auth-Type LDAP = ok
(0) # Executing section post-auth from file /etc/raddb/sites-enabled/default
(0)   post-auth {
(0)     update {
(0)       No attributes updated
(0)     } # update = noop
(0)     [exec] = noop
(0)     policy remove_reply_message_if_eap {
(0)       if (&reply:EAP-Message && &reply:Reply-Message) {
(0)       if (&reply:EAP-Message && &reply:Reply-Message)  -> FALSE
(0)       else {
(0)         [noop] = noop
(0)       } # else = noop
(0)     } # policy remove_reply_message_if_eap = noop
(0)     if (LDAP-Group == "netadmin") {
(0)     Searching for user in group "netadmin"
rlm_ldap (ldap): Reserved connection (3)
(0)     Using user DN from request "uid=myuser,cn=users,cn=accounts,dc=redacted,dc=redacted,dc=com"
(0)     Checking user object's memberOf attributes
(0)       Performing unfiltered search in "uid=myuser,cn=users,cn=accounts,dc=redacted,dc=redacted,dc=com", scope "base"
(0)       Waiting for search result...
(0)     No group membership attribute(s) found in user object
rlm_ldap (ldap): Released connection (3)
(0)     User is not a member of "netadmin"
(0)     if (LDAP-Group == "netadmin")  -> FALSE

Specifically these lines:

(0)       Performing unfiltered search in "uid=myuser,cn=users,cn=accounts,dc=redacted,dc=redacted,dc=com", scope "base"
(0)       Waiting for search result...
(0)     No group membership attribute(s) found in user object

After using ldapsearch tool, I verified that I have the memberOf attribute with the netadmin group:

ldapsearch -P 3 -x -W -D "uid=myuser,cn=users,cn=accounts,dc=redacted,dc=redacted,dc=com" -b "uid=myuser,cn=users,cn=accounts,dc=redacted,dc=redacted,dc=com" \* +
Enter LDAP Password: 
# extended LDIF
#
# LDAPv3
# base <uid=myuser,cn=users,cn=accounts,dc=redacted,dc=redacted,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: * + 
#

# myuser, users, accounts, redacted.redacted.com
dn: uid=myuser,cn=users,cn=accounts,dc=redacted,dc=redacted,dc=com
memberOf: cn=ipausers,cn=groups,cn=accounts,dc=redacted,dc=redacted,dc=com
...
memberOf: cn=netadmin,cn=groups,cn=accounts,dc=redacted,dc=redacted,dc=com
...
uid: myuser
objectClass: ipaobject
objectClass: person
objectClass: top
objectClass: ipasshuser
objectClass: inetorgperson
objectClass: organizationalperson
objectClass: krbticketpolicyaux
objectClass: krbprincipalaux
objectClass: inetuser
objectClass: posixaccount
objectClass: ipaSshGroupOfPubKeys
objectClass: mepOriginEntry

I expected the server would see this after searching my users object, and looking for the memberOf attribute.

I also investigated further and captured packets with tcpdump and imported into wireshark to compare radtest and ldapsearch. I noticed a few differences between the sessions that stuck out to me:

1) The last bindRequest that radtest sends before searchRequest, uses <ROOT>. Using ldapsearch, the last bindRequest uses uid=myuser,cn=groups,cn=accounts,dc=redacted,dc=redacted,dc=com. BUT I the radius debug log says that it binds as the authenticated user, so I'm confused here.

2) When ldapsearch sends the searchRequest for attribute memberOf using my users DN, it uses a scope of wholeSubtree. When radtest sends the same request, it uses a scope of base. This is confusing as I set scope = 'sub' for both user and group blocks in my mods-available/ldap config.

So what am I missing that is preventing freeradius from seeing the memberOf attribute data to verify that my user is a part of a group?


Solution

  • Alright I was closer than I thought. After discovering through packet capture that there was some weird binding behaviour, I looked at the debug log more closely. I realized that the binding with my username was being released:

    rlm_ldap (ldap): Released connection (2)
    

    Also, the bind that happens for group membership checking does not use my user object DN (I believe this is an anonymous bind):

    rlm_ldap (ldap): Opening additional connection (7), 1 of 25 pending slots used
    rlm_ldap (ldap): Connecting to ldap://<redacted>:389 ldap://<redacted>:389
    rlm_ldap (ldap): Waiting for bind result...
    rlm_ldap (ldap): Bind successful
    

    This helped me fine tune my googling and I came across some form discussion.

    I asked my system admin if we had any generic accounts for this purpose and we did.

    So I included at the top of the ldap block of /etc/mods-enabled/ldap:

        identity = "cn=special_ro_account,....rest_of_dn..."
        password = "xxxxxxxx"
    

    And sure enough, the bind was no longer anonymous when searching for group membership and I was successfully authenticated.