Massaging the behavior of LDAP-Group caching?

classic Classic list List threaded Threaded
5 messages Options
| Threaded
Open this post in threaded view
|

Massaging the behavior of LDAP-Group caching?

Users mailing list
All,

I ran into a problem with LDAP-Group and a DN that it was not able to
find a friendly name for.
I have a function called "group_authz" (loaded from a file in
policy.d) that gets called in the post-auth{} section of my site.
The function just does a few if comparisons against &LDAP-Group[*] and
then updates the reply to the NAS with attributes.

I ran into a situation where one of the groups it pulled from a user's
memberOf list "did not resolve to an object," which then causes
rlm_ldap to return "invalid" and thus rejects the whole attempt.

The group it choked on is something used internally by FreeIPA. It's
not a group I care about, and not user-created (it's not even visible
inside the standard FreeIPA interface). There are actually multiple
groups like this that I presume it will complain about, if it wasn't
failing at the first one.

I was able to work around the problem by trying to match on the full
DN instead of the friendly name, but this is obviously a bit harder to
read in the config, and I'd prefer to use the friendly names if I can
find a way to make it work.

Is there a way to tell LDAP-Group to ignore any DN that it finds that
it can't "resolve", instead of throwing an "invalid"? Or, is there a
way to get the LDAP-Group lookup process to only attempt to resolve
DNs that match a specified base/filter? The base_dn in the group{}
stanza of the ldap module is already set to the portion of the tree I
care about, but LDAP-Group seems to still try to resolve the DNs that
aren't in that base (presumably because it's just reading them from
"memberOf").

If I have to just stick to matching on full DNs, I will... was just
trying to learn if there was a way to deal with this lookup failure
gracefully. :-)

Snippet of log output in the failure state is below... In this case, I
had cacheable_names=yes enabled, but I disabled caching later to test
further (caching itself isn't the problem, it's just the unresoveable
DN).

(0) ldap: Performing search in "cn=users,cn=accounts,dc=foobar,dc=org"
with filter "(uid=admin-person)", scope "sub"
(0) ldap: Waiting for search result...
(0) ldap: User object found at DN
"uid=admin-person,cn=users,cn=accounts,dc=foobar,dc=org"
(0) ldap: Resolving group DN
"cn=admins,cn=groups,cn=accounts,dc=foobar,dc=org" to group name
(0) ldap: Performing unfiltered search in
"cn=admins,cn=groups,cn=accounts,dc=foobar,dc=org", scope "base"
(0) ldap: Waiting for search result...
(0) ldap: Group DN "cn=admins,cn=groups,cn=accounts,dc=foobar,dc=org"
resolves to name "admins"
(0) ldap: Resolving group DN "cn=Replication
Administrators,cn=privileges,cn=pbac,dc=foobar,dc=org" to group name
(0) ldap: Performing unfiltered search in "cn=Replication
Administrators,cn=privileges,cn=pbac,dc=foobar,dc=org", scope "base"
(0) ldap: Waiting for search result...
(0) ldap: Search returned no results
(0) ldap: ERROR: Group DN "cn=Replication
Administrators,cn=privileges,cn=pbac,dc=foobar,dc=org" did not resolve
to an object
rlm_ldap (ldap): Released connection (0)
Need 5 more connections to reach 10 spares
rlm_ldap (ldap): Opening additional connection (5), 1 of 27 pending slots used
rlm_ldap (ldap): Connecting to ldap://ipa1.foobar.org:389
ldap://ipa2.foobar.org:389 ldap://ipa3.foobar.org:389
rlm_ldap (ldap): Waiting for bind result...
rlm_ldap (ldap): Bind successful
(0)     [ldap] = invalid
(0)   } # authorize = invalid
(0) Invalid user (ldap: Group DN "cn=Replication
Administrators,cn=privileges,cn=pbac,dc=foobar,dc=org" did not resolve
to an object): [admin-person] (from client dc-srv-
sw01 port 11526)
(0) Using Post-Auth-Type Reject

I appreciate any suggestions!
Cheers,
Braden
-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
| Threaded
Open this post in threaded view
|

Re: Massaging the behavior of LDAP-Group caching?

Alan DeKok-2

On Mar 31, 2021, at 7:08 PM, Braden McGrath via Freeradius-Users <[hidden email]> wrote:
> I ran into a situation where one of the groups it pulled from a user's
> memberOf list "did not resolve to an object," which then causes
> rlm_ldap to return "invalid" and thus rejects the whole attempt.

  It's difficult to know what to do here.  The "right thing" isn't always clear.  Especially when the server has to work across multiple different LDAP servers.

  The simple answer is that FreeIPA is broken, and is returning the wrong things.  It shouldn't be returning memberOf fields which don't resolve.  That just doesn't make any sense.

> I was able to work around the problem by trying to match on the full
> DN instead of the friendly name, but this is obviously a bit harder to
> read in the config, and I'd prefer to use the friendly names if I can
> find a way to make it work.

  Sure.

> Is there a way to tell LDAP-Group to ignore any DN that it finds that
> it can't "resolve", instead of throwing an "invalid"?

  There's no configuration option for that, sorry.

> Or, is there a
> way to get the LDAP-Group lookup process to only attempt to resolve
> DNs that match a specified base/filter? The base_dn in the group{}
> stanza of the ldap module is already set to the portion of the tree I
> care about, but LDAP-Group seems to still try to resolve the DNs that
> aren't in that base (presumably because it's just reading them from
> "memberOf").

  Yes, that's what it's doing.

  The simple answer is to fix FreeIPA.  Or, to use the full DN as you've done.

  Alan DeKok.


-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
| Threaded
Open this post in threaded view
|

Re: Massaging the behavior of LDAP-Group caching?

Users mailing list
(Replies inline)

On Thu, Apr 1, 2021 at 5:40 PM Alan DeKok <[hidden email]> wrote:
> On Mar 31, 2021, at 7:08 PM, Braden McGrath via Freeradius-Users <[hidden email]> wrote:
> > I ran into a situation where one of the groups it pulled from a user's
> > memberOf list "did not resolve to an object," which then causes
> > rlm_ldap to return "invalid" and thus rejects the whole attempt.
>
>   It's difficult to know what to do here.  The "right thing" isn't always clear.  Especially when the server has to work across multiple different LDAP servers.
>
>   The simple answer is that FreeIPA is broken, and is returning the wrong things.  It shouldn't be returning memberOf fields which don't resolve.  That just doesn't make any sense.
I was thinking the same way... I suspect it's something LDAP
permissions-related, where those groups are only used internally by
FreeIPA. If they are "internal," presumably 389DS (the underlying LDAP
server for FreeIPA) doesn't normally expect a "user" (or even a
"service" account, which is what my FR server is using) to query for
details on those groups, hence it is denying access. I need to go play
with ldapsearch to confirm that.

I don't think I want to follow the permission rabbit-hole I'd need to
"unhide" these groups from the FR LDAP credentials, though... I guess
it depends on what other security implications this might have.
Research required.

> > Or, is there a
> > way to get the LDAP-Group lookup process to only attempt to resolve
> > DNs that match a specified base/filter? The base_dn in the group{}
> > stanza of the ldap module is already set to the portion of the tree I
> > care about, but LDAP-Group seems to still try to resolve the DNs that
> > aren't in that base (presumably because it's just reading them from
> > "memberOf").
>
>   Yes, that's what it's doing.
I guess another option would be to comment out membership_attribute,
but this then requires FR to walk through all the groups looking for a
match based on the CN, which is obviously going to be slower than just
pulling the group list from memberOf. But since I know all of the
groups I'd be searching for will be readable, it should never get to a
state where it fails the search (unless I fat-finger the group name in
the FR config).

If I disable membership_attribute and fall back to membership_filter
and the ensuing string of queries, are those still cached by
cacheable_name or cacheable_dn so it doesn't have to run the lookups
for each unlang comparison?

>   The simple answer is to fix FreeIPA.  Or, to use the full DN as you've done.
I'll dig into FreeIPA a little further, but this may be "by design"
and "fixing" might not be worth the headache, especially when using
the full DN works. ;-) I can always set up some variables to make it a
little more readable.

I appreciate all of the support, and thank you and the rest of the FR
contributors for the entire project.
As a RADIUS noob, it's... a bit overwhelming at times, but the
documentation *is* pretty darn thorough. (I've seen much worse from
paid vendors of unrelated products!) It's not FR's fault that the
protocol is complicated and a little strange, and your users are all
trying to do thousands of different things with millions of different
systems. :-)

Regards,
Braden
-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
| Threaded
Open this post in threaded view
|

Re: Massaging the behavior of LDAP-Group caching?

Alan DeKok-2
On Apr 1, 2021, at 7:48 PM, Braden McGrath <[hidden email]> wrote:
> I was thinking the same way... I suspect it's something LDAP
> permissions-related, where those groups are only used internally by
> FreeIPA. If they are "internal," presumably 389DS (the underlying LDAP
> server for FreeIPA) doesn't normally expect a "user" (or even a
> "service" account, which is what my FR server is using) to query for
> details on those groups, hence it is denying access. I need to go play
> with ldapsearch to confirm that.

  Then 389DS shouldn't be returning them.  :(

> If I disable membership_attribute and fall back to membership_filter
> and the ensuing string of queries, are those still cached by
> cacheable_name or cacheable_dn so it doesn't have to run the lookups
> for each unlang comparison?

  The LDAP-Group attribute is cached.  So it won't do DB queries for every unlang operation.  You can check this by running in debug mode.

> I appreciate all of the support, and thank you and the rest of the FR
> contributors for the entire project.

  Thanks.

> As a RADIUS noob, it's... a bit overwhelming at times, but the
> documentation *is* pretty darn thorough. (I've seen much worse from
> paid vendors of unrelated products!) It's not FR's fault that the
> protocol is complicated and a little strange, and your users are all
> trying to do thousands of different things with millions of different
> systems. :-)

  Exactly.  There's no button labelled "do what I want".  :(

  RADIUS does

(WiFi, DSL, Dial-up, VPN) * (EAP-TLS, TTLS, PEAP, PAP, CHAP, MS-CHAP) * (VLAN, IP assignment) * (LDAP, SQL, Active Directory, ...)

  The combination makes life almost impossible.

  For what it's worth, I know that a popular Open Source DNS server looked into implementing DHCP.  After all, they wrote a complex DNS server, how hard can it be to do DHCP?

  They got told to look at FreeRADIUS for policies, not ISC.  After looking at FreeRADIUS, and the complex policies we support, the DNS guys gave up and decided to stick with DNS.

  Doing a complex, fast, policy server is *hard*.  People use DNS, and expect that that they can do the equivalent to "drop in a zone file, and it just works".  This is very, very, far from the truth.

  In other news, we're looking into implementing DNS in v4.  :)  It might be ~3K LoC to do the 99% of DNS that most people need.  Because all of the policies, configuration file reading, and network IO is already abstracted.

  i.e. if you build a complex policy server which plugs into every possible database, then *any* networking protocol is easy.

  Alan DeKok.


-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
| Threaded
Open this post in threaded view
|

Re: Massaging the behavior of LDAP-Group caching?

Users mailing list
I had one very minor thing I ran across during troubleshooting that
hopefully someone can answer, but after that question I'm going to
provide my results of a deeper dive and "final solutions" for the list
archive.

When membership_attribute is set, and cacheable_name = yes, the ldap
module pops this message in debug output during an access-request:
ldap: Adding cacheable user object memberships
ldap:    &control:LDAP-Group += "foo"
  [etc, one line per group]
ldap: Skipping caching group objects as directive
'group.membership_filter' is not set

But later, when actually running an unlang compare against
&LDAP-Group[*],  FR says:
User found. Matched cached membership

The comments in the ldap config imply that membership_filter and
membership_attribute aren't normally used simultaneously. :)
I wasn't seeing additional queries during the actual unlang
comparison, so I trust the message that it "Matched cached
membership," but that leaves me confused about what "skipping caching
group objects as directive 'group.membership_filter' is not set"
meant.

Anyway, here's my attempt at "Wisdom of the Ancients" (see
https://xkcd.com/979/), in case anybody else is trying to tie
FreeRADIUS to FreeIPA / 389DS...
On Fri, Apr 2, 2021 at 7:08 AM Alan DeKok <[hidden email]> wrote:

>
> On Apr 1, 2021, at 7:48 PM, Braden McGrath <[hidden email]> wrote:
> > I was thinking the same way... I suspect it's something LDAP
> > permissions-related, where those groups are only used internally by
> > FreeIPA. If they are "internal," presumably 389DS (the underlying LDAP
> > server for FreeIPA) doesn't normally expect a "user" (or even a
> > "service" account, which is what my FR server is using) to query for
> > details on those groups, hence it is denying access. I need to go play
> > with ldapsearch to confirm that.
>
>   Then 389DS shouldn't be returning them.  :(

FreeIPA / 389DS returns the "unfiltered" contents of a DN's "memberOf"
attribute, even if the LDAP bind account in use doesn't have the
ability to directly access each of the individual DNs listed in that
attribute.
In other words, it will *return* the list of everything a user is a
"memberOf," but it won't necessarily allow you to pull more details
about each of those DNs (like the friendly name). I don't know enough
about LDAP to know if this is "correct" behavior for the memberOf
attribute or not, but it's how 389DS seems to work. :)

By default, an account able to bind to a FreeIPA server *can* pull all
of the groups and users out of the "cn=accounts,dn=example,dn=org"
tree. But, FreeIPA uses other sub-trees (cn=pbac and cn=hbac and
probably a few more) in order to store its own permissions and other
Magic, and a typical bind account with no extra privileges does _not_
have the ability to read those other sub-trees and return the actual
names of the groups. A test with ldapsearch will get you a result of
"0 Success" with a "numResponses: 1" but no actual LDAP Entries (i.e.
no usable data) in the response.

FR will Have A Bad Time if it attempts to query those permission
groups for short names and gets blank stares from FreeIPA/389DS LDAP
server. So, you need to be able to read them *if* you are using
friendly/short name matches. (You can ignore all of this if you match
on the full DN, because FR doesn't waste its time trying to turn the
contents in memberOf into friendly names if it seems like you're doing
a full DN match.)

Long story short, as long as you don't mind the bind account you're
using having *read* access to the names and other details of those
FreeIPA permissions / etc, you can add a "Role" of your own naming in
FreeIPA, grant it the permission "RBAC Readers" (this is a predefined
permission in FreeIPA), and then assign that role to your LDAP bind
account(s). The bind account will then be able to read all of the
names on these otherwise "hidden" permission groups, and things should
work. ;)

If you don't want the bind account to have permissions to read
about... permissions, the other option is to comment out
membership_attribute and use membership_filter *instead*. In this
case, FR walks through the group tree, and checks to make sure the
user is in each of the groups. In many cases this is probably slower.
However, if the user has a lot of these hidden FreeIPA permission
groups (which are not part of the normal user-defined groups
container/tree, and hence wouldn't be walked when using
membership_attribute), and you do _not_ have many user-created groups,
the membership_filter may actually have *fewer* LDAP queries involved.

Personally, I'm just leaving my config with full DN matches, but I
also granted the above role on the bind account in case I ever need to
move to friendly name matches in the future.
Good luck!
-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html