Active Directory group check via winbind + rlm_unix, not LDAP

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Active Directory group check via winbind + rlm_unix, not LDAP

Eloy Paris
Hello,

I have a pretty common requirement: authenticate wireless users against
Active Directory and prevent SSID cross-connections, i.e. users in group
A can only connect to SSID A and users in group B can only connect to
SSID B.

I have seen plenty of messages in the archives about how to accomplish
this. The authentication part is easy and has excellent documentation,
e.g.

http://deployingradius.com/documents/configuration/active_directory.html

The group checking part is also well understood and documented
(rlm_ldap), and whoever asks apparently gets told to use LDAP. At least
I could not find anything on the alternate approach described here
(apologies if this is old news).

I decided to look into a different approach, which does not involve
LDAP -- since the machine already has winbind running (for ntlm_auth),
why not to use the Name Service Switch and rlm_unix to check for group
membership and avoid usind LDAP altogether? Group membership information
is already available if one has added "winbind" to "passwd" and "group"
in /etc/nsswitch.conf.

I apparently got this to work and wanted to share the solution in the
hope that it will be helpful to someone, but also to ask if anyone sees
any issues with the approach:

First, I configured winbind for ntlm_auth use by FreeRADIUS, as
explained elsewhere. Then, I verified that the system can see Active
Directory users and groups as if they were Unix users and groups:

shell$ id DOMAIN\\username
uid=10017(DOMAIN\username) gid=10002(DOMAIN\domain users) groups=10002(DOMAIN\domain users),10024(DOMAIN\computer-lab-monitoring),10008(DOMAIN\domain admins),10034(DOMAIN\vdi teachers),10010(DOMAIN\teachers),10026(DOMAIN\vdi users),10011(DOMAIN\teacher assistants),10074(DOMAIN\schema admins)

Then, I put this logic, which is similar to what one would normally use
if LDAP and Ldap-Groups were in use, in the post-authentication section
of my sites-enabled/default:

        if (NAS-Port-Type == Wireless-802.11) {
                if (Called-Station-Id =~ /.*:SSID-A/i) {
                        # Can't do 'if (Group != "xxxxx")' because !=
                        # operator doesn't work for group checking. Careful
                        # with the number of backslashes.
                        if (!(Group == "DOMAIN\\\\group A") ) {
                                update reply {
                                        Reply-Message = "User not allowed to join this wireless network"
                                }
                                reject
                        }

                }
                elsif (Called-Station-Id =~ /.*:SSID-B/i) {
                        if (!(Group == "DOMAIN\\\\group B") ) {
                                update reply {
                                        Reply-Message = "User not allowed to join this wireless network"
                                }
                                reject
                        }
                }
        }

This works if the EAP identity is "DOMAIN\username". However, I don't
want to make things unnecessarily complicated for my users so I want
them to be able to enter just "username" when they configure their
devices.

The main issue to address, however, is that if the identity is entered
as "username" (not "DOMAIN\username"), the group check will fail because
the Unix user ID for users that are known to the system via winbind is
"DOMAIN\username", not "username" (see output from the "id" command
above).

"Not a problem", I thought, "I'll just manipulate User-Name before
anything happens and prefix it with "DOMAIN\". Turns out that was a bad
idea because that made User-Name different than the EAP identity hidden
in the EAP message, which caused the "rlm_eap: identity does not match
User-Name, setting from EAP identity" message that has bitten so many
people before.

The solution I came up with was to still manipulate the User-Name but
towards the end, in the post-auth section, instead of at the beginning.
This way EAP uses the right identity, but the rlm_unix Group check uses
the correct "DOMAIN\username" User-Name.

The final configuration looks like this:

        if (NAS-Port-Type == Wireless-802.11) {
                # If User-Name doesn't contain our domain then add it.
                # It's needed for the Group check to use the correct
                # username.
                if (User-Name !~ /DOMAIN\\\\/i) {
                        update request {
                                User-Name := "DOMAIN\\\\%{User-Name}"
                        }
                }

                if (Called-Station-Id =~ /.*:SSID-A/i) {
                        # Can't do 'if (Group != "xxxxx")' because !=
                        # operator doesn't work for group checking. Careful
                        # with the number of backslashes.
                        if (!(Group == "DOMAIN\\\\group A") ) {
                                update reply {
                                        Reply-Message = "User not allowed to join this wireless network"
                                }
                                reject
                        }

                }
                elsif (Called-Station-Id =~ /.*:SSID-B/i) {
                        if (!(Group == "DOMAIN\\\\group B") ) {
                                update reply {
                                        Reply-Message = "User not allowed to join this wireless network"
                                }
                                reject
                        }
                }
        }

I do not know about the performance impact but this should not require
additional network traffic to check for group membership because winbind
caches this information.

Another possible advantage is redundancy -- I understand the LDAP method
does not allow for multiple LDAP servers. Using winbindd (I theorize, I
am not sure about this) provides redundancy because the group membership
comes from the domain controller, which is found using DNS lookups --
if a controller goes down then another (hopefully) takes its place and
winbindd will be able to find it with no configuration changes.

This approach seemed simple to me -- no additional configuration other
than manipulating the User-Name in the post-authentication phase.

Things can also be made to work if the user chooses to configure the
supplicant with "DOMAIN\user" as the identity -- in this case one needs
to configure "with_ntdomain_hack = yes" in modules/mschap, create an
empty "DOMAIN" realm in proxy.conf, and enable the ntdomain realm in the
authorize section of sites-enabled/inner-tunnel. Doing this will allow
both "DOMAIN\user" and just "user" to work.

Any thoughts, gotchas or hidden traps with this approach? I have tested
this in pre-deployment and it works. I will start testing this in
production to see if users have any issues.

Cheers,

Eloy Paris.-

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

Re: Active Directory group check via winbind + rlm_unix, not LDAP

A.L.M.Buxey
Hi,

> I apparently got this to work and wanted to share the solution in the
> hope that it will be helpful to someone, but also to ask if anyone sees
> any issues with the approach:

interesting solution

>                 if (User-Name !~ /DOMAIN\\\\/i) {
>                         update request {
>                                 User-Name := "DOMAIN\\\\%{User-Name}"
>                         }
>                 }

you shouldnt play with User-Name - use a temporary/local RADIUS attribute instead

> Another possible advantage is redundancy -- I understand the LDAP method
> does not allow for multiple LDAP servers. Using winbindd (I theorize, I

yes, it does (allow multiple servers)

> am not sure about this) provides redundancy because the group membership
> comes from the domain controller, which is found using DNS lookups --
> if a controller goes down then another (hopefully) takes its place and
> winbindd will be able to find it with no configuration changes.

no. it rarely falls over nicely to the next server. winbindd is rubbish
(i know, we use it)

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

Re: Active Directory group check via winbind + rlm_unix, not LDAP

Mathieu Simon (Lists)
Hi

Am 01.09.2014 13:42, schrieb [hidden email]:

>> am not sure about this) provides redundancy because the group
>> membership
>> comes from the domain controller, which is found using DNS lookups --
>> if a controller goes down then another (hopefully) takes its place and
>> winbindd will be able to find it with no configuration changes.
>
> no. it rarely falls over nicely to the next server. winbindd is rubbish
> (i know, we use it)

Which I unfortunately have to confirm, it doesn't fail over neither
quickly nor
that nicely, it may take its time to fail over which might take enough
time for
the user to get a authentication error...

Usually a LDAP lookup for the group membership is very quick and can be
balanced.
(even though AD's LDAP isn't one of the fastest LDAP servers)

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

Re: Active Directory group check via winbind + rlm_unix, not LDAP

Phil Mayers
In reply to this post by A.L.M.Buxey
On 01/09/14 12:42, [hidden email] wrote:

> no. it rarely falls over nicely to the next server. winbindd is rubbish
> (i know, we use it)

We find it does fail over, but it's slow to detect a dead server - tens
of seconds, which is too slow to be useful in a wireless environment
with high client and reauth counts.
-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Active Directory group check via winbind + rlm_unix, not LDAP

Eloy Paris
In reply to this post by A.L.M.Buxey
Hello,

On Mon, Sep 01, 2014 at 11:42:33AM +0000, [hidden email] wrote:

[...]

> >                 if (User-Name !~ /DOMAIN\\\\/i) {
> >                         update request {
> >                                 User-Name := "DOMAIN\\\\%{User-Name}"
> >                         }
> >                 }
>
> you shouldnt play with User-Name - use a temporary/local RADIUS attribute instead

I'm all for that, but then how can the "Group == 'xxxxx'" check be done
against this temporary/local attribute? The group check is always done
against the User-Name attribute, isn't it?

> > Another possible advantage is redundancy -- I understand the LDAP method
> > does not allow for multiple LDAP servers. Using winbindd (I theorize, I
>
> yes, it does (allow multiple servers)

Good to know; thanks!

Cheers,

Eloy Paris.-

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

Re: Active Directory group check via winbind + rlm_unix, not LDAP

Alan DeKok-2
Eloy Paris wrote:
> I'm all for that, but then how can the "Group == 'xxxxx'" check be done
> against this temporary/local attribute? The group check is always done
> against the User-Name attribute, isn't it?

  Use Stripped-User-Name.  That's what it's for.  Everything in the
server that needs a stripped user name uses that.  Changing
Stripped-User-Name won't affect EAP.

  Alan DeKok.
-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
Loading...