Re: [EXT] Fetching memberOf attribute

Matvey Teplov via Freeradius-Users <[email protected]>
Newsgroups gmane.comp.freeradius.user
Message-ID <AM0P191MB0337002772075D9F482DAD01E799A@AM0P191MB0337.EURP191.PROD.OUTLOOK.COM>
Hi Brian,

Thank you for the pushing to the right direction - I reshaped the ldap group section including filters and it worked like a charm. For the record in mods-available/ldap:

ldap {
    server = 'abc.abc'
    identity = 'CN=ServiceAccount,DC=Users,DC=abc,DC=abc'
    password = '123456789'
    base_dn = 'DC=abc,DC=abc'

    user {
        base_dn = "${..base_dn}"
        filter = "(&(objectClass=user)(sAMAccountName=%{&User-Name}))"
        scope = 'sub'
        uid_attribute = "sAMAccountName"
        attribute {
                      memberOf := "session-state:LDAP-Group"
                }
        }

  group {
    base_dn = "${..base_dn}"
    filter = '(objectClass=group)'
    name_attribute = cn
    # use magic AD search to get all groups
    membership_filter = "(member:1.2.840.113556.1.4.1941:=%{control:Ldap-UserDN})"
    membership_attribute = 'memberOf'
    # enable cache module
    cacheable_dn = 'yes'
    cache_attribute = "${..:instance}-LDAP-Group"
  }

    options {
        chase_referrals = no
        rebind = yes
        ldap_debug = 2147483647
        timeout = 10
        timelimit = 3
        net_timeout = 1
        idle = 60
    }

    tls {
        start_tls = no
    }
}

The LDAP queries are happening in the authorize section after the proxy call (sites-available/default) and will yield a list of groups in the control:ldap-LDAP-Group attribute:

authorize {
    preprocess
    auth_log
    chap
#   suffix

if (&request:User-Name) {
    update session-state {
        Persisted-User-Name := "%{request:User-Name}"
    }
}

    update control {
        Proxy-To-Realm := "radius_server"
    }

        ldap
}

So, when you will be getting it in the post-auth section, you can go over it with the foreach loop:

        foreach &control:ldap-LDAP-Group {
                if ("%{Foreach-Variable-0}" == "CN=Radius_ReadOnly_Group,DC=Groups,DC=abc,DC=abc") {
                        update reply {
                                Reply-Message := "Authorized as RO user"
                                }
                        update control {
                                Auth-Type := Accept
                                }
                        }

                if ("%{Foreach-Variable-0}" == "CN=Radius_ReadWrite_Group,DC=Groups,DC=abc,DC=abc") {
                        update reply {
                                Reply-Message := "Authorized as RW user"
                                }
                        update control {
                                Auth-Type := Accept
                                }
                        }

                if ("%{Foreach-Variable-0}" == "CN=Radius_Admin_Group,DC=Groups,DC=abc,DC=abc") {
                        update reply {
                                Reply-Message := "Authorized as Admin"
                                }
                        update control {
                                Auth-Type := Accept
                                }
                        }
                }


The problem I still have is how to send the Reject back if the loop conditions are not met, because before I go into it, I set Reject explicitly:

        update {
                reply:Reply-Message := "Unauthorized - No group found"
                control:Auth-Type := "Reject"
                }

but it is still returning accept:

(0) # Executing section post-auth from file /etc/freeradius/3.0/sites-enabled/default
(0)   post-auth {
(0)     update {
(0)       reply:Reply-Message := "Unauthorized - No group found"
(0)       control:Auth-Type := Reject
(0)     } # update = noop
(0)     foreach &control:ldap-LDAP-Group {
(0)     } # foreach &control:ldap-LDAP-Group = noop
(0)   } # post-auth = noop
(0) Login OK: [generic-ms-user] (from client localhost port 1)
(0) Sent Access-Accept Id 116 from 127.0.0.1:1825 to 127.0.0.1:50310 length 0
(0)   Reply-Message := "Unauthorized - No group found"
(0) Finished request

The strange thing is that the message is being set, but the update still says "noop". Does anyone have a clue?

Best regards Matvey Teplov
+31 62 705 12 73

________________________________
From: Freeradius-Users <freeradius-users-bounces+matvey.teplov=nomios.nl@lists.freeradius.org> on behalf of Matvey Teplov via Freeradius-Users <[email protected]>
Sent: 15 May 2025 15:23
To: Brian Julin <[email protected]>; [email protected] <[email protected]>
Cc: Matvey Teplov <[email protected]>
Subject: Re: [EXT] Fetching memberOf attribute

Hi Brian,

How do you define ldap_ad-LDAP-Group?

Best regards Matvey Teplov
+31 62 705 12 73
________________________________
From: Brian Julin <[email protected]>
Sent: 15 May 2025 15:02
To: [email protected] <[email protected]>
Cc: Matvey Teplov <[email protected]>
Subject: Re: [EXT] Fetching memberOf attribute

[You don't often get email from [email protected]. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]

Matvey Teplov via Freeradius-Users <[email protected]> wrote:

> Hi Guys,

> I cannot get the ldap module to fetch a memberOf attribute from AD - it is not putting it
> as a filter parameter in the LDAP search packet. I need this list later to search through for
> port-authentication phase through the groups in session-state:LDAP-Group[*]'s to identify
> which ones are present and return a proper VSA. The LDAP configuration is as follows:

We use this, because it searches the group membership hierarchy so nested groups work:

    user {
     ...
      filter = "(&(objectClass=user)(sAMAccountName=%{Stripped-User-Name}))"
      scope = 'sub'
    }
    group {
     ...
      scope = 'sub'
      filter = '(objectCategory=group)'
      membership_filter = "(member:1.2.840.113556.1.4.1941:=%{&control:Ldap-UserDN})"
     ...
   }

You can thank Microsoft for the ugly OID, as far as I know it has no textual alias.

then:

if (&ldap_ad-LDAP-Group[*] ==  "whatever")

...that statement will be true if any one of the users groups, including groups inherited from other groups, is "whatever", no need for a for loop unless you need to do something fancy.

Do note that if you have a lot of groups in the OU the search will not be especially efficient, it will even rummage through your printers and whatnot.  We made a new OU for the top level RADIUS groups and then could put groups from our other OUs inside those groups to reduce the scope of the search to just users.


-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.