Ldap Huntgroup 'Reject' issue
Hi, I've just noticed that there is a little difference in functionality between FR 2.x and 3.21. The config I have, worked fine in v2 but now in v3 it is not doing what I intend. I'm using an Openldap backend which consists of users and groups and I would like to restrict access based on the user-group association in ldap. eg. any user belonging to the Guest group should only be given authenticated access to guest areas (currently restricted to Wifi) while 'normal' users should get standard Wifi access but not access to NAS config shells etc; admin group gets all access with no restrictions My current FR config takes the Huntgroup name and looks at the 'l' values in ldap for a match. This is the tail end of my Authorize file: *I've used <> to indicate comments and it is not part of the config file* DEFAULT Huntgroup-Name == Huntgroup1, Ldap-Group == "<PPP Dialin group>" Service-Type = "Framed-User" DEFAULT Huntgroup-Name == Huntgroup2 <this is the Guest group>, Ldap-Group == "<Guest ldap group>" NAS-Port-Type = "Wireless-802.11", Airespace-QOS-Level = 3 DEFAULT Huntgroup-Name == Huntgroup3, Ldap-Group == "<Regular Wifi group>" NAS-Port-Type = "Wireless-802.11" DEFAULT Huntgroup-Name == Huntgroup4, Ldap-Group == "<Full Admin group>" Service-Type = "NAS-Prompt-User", Idle-Timeout = 600, Cisco-AVPair = "shell:priv-lvl=15" DEFAULT Huntgroup-Name == Huntgroup4, Ldap-Group == "<Net Admin group>" Service-Type = "NAS-Prompt-User", Idle-Timeout = 600, Cisco-AVPair = "shell:priv-lvl=15" DEFAULT Huntgroup-Name == Huntgroup5, Ldap-Group == "<Net Admin group>" Service-Type = "NAS-Prompt-User", Idle-Timeout = 600, STI-Access-Level = 1, APC-Service-Type = 1 DEFAULT Huntgroup-Name == Huntgroup6, Ldap-Group == "<Net Admin group>" Service-Type = "Administrative-User", Idle-Timeout = 600, Cisco-AVPair = "shell:priv-lvl=15" DEFAULT Auth-Type := Reject The Outer-tunnel (default) file contains the following under the Authorize section: authorize { update request { Huntgroup-Name ="%{ldap:ldap:///<ldap path 1>?l?sub?cn=%{Packet-Src-IP-Address}}" Huntgroup-Name +="%{ldap:ldap:///<ldap path 2>?l?sub?cn=%{Packet-Src-IP-Address}}" Huntgroup-Name +="%{ldap:ldap:///<ldap path 3>l?sub?cn=%{Packet-Src-IP-Address}}" Huntgroup-Name +="%{ldap:ldap:///<ldap path 4>?l?sub?cn=%{Packet-Src-IP-Address}}" Huntgroup-Name +="%{ldap:ldap:///<ldap path 5>?l?sub?cn=%{Packet-Src-IP-Address}}" Huntgroup-Name +="%{ldap:ldap:///<ldap path 6>?l?sub?cn=%{Packet-Src-IP-Address}}" } # # Take a User-Name, and perform some checks on it, for spaces and other # invalid characters. If the User-Name appears invalid, reject the # request. # # See policy.d/filter for the definition of the filter_username policy. # filter_username ... The Inner-tunnel file contains this, it's slightly different from the 'Outer' tunnel due to various matching issues I found when there are multiple 'l' values attached to the NAS lookup in ldap - To clarify what I mean is that example:- a Wireless Controller has Huntgroup2, Huntgroup3 and Huntgroup4 set in the 'l' value under different ldap paths, so if it matches <ldap path 3> then look the user up and authenticate - if the huntgroup does not match then try a different path using attributes based on the unlang operators: authorize { update request { Huntgroup-Name ="%{ldap:ldap:///<ldap path 1>?l?sub?cn=%{Packet-Src-IP-Address}}" Huntgroup-Name ="%{ldap:ldap:///<ldap path 2>?l?sub?cn=%{Packet-Src-IP-Address}}" Huntgroup-Name ="%{ldap:ldap:///<ldap path 3>?l?sub?cn=%{Packet-Src-IP-Address}}" Huntgroup-Name :="%{ldap:ldap:///<ldap path 4>?l?sub?cn=%{Packet-Src-IP-Address}}" Huntgroup-Name ="%{ldap:ldap:///<ldap path 5>?l?sub?cn=%{Packet-Src-IP-Address}}" Huntgroup-Name :="%{ldap:ldap:///<ldap path 6>?l?sub?cn=%{Packet-Src-IP-Address}}" } # # Take a User-Name, and perform some checks on it, for spaces and other # invalid characters. If the User-Name appears invalid, reject the # request. # # See policy.d/filter for the definition of the filter_username policy. # filter_username ... This is a partial output from radiusd -X - the user is not found in any of the administrative ldap paths and then hits line 314 which is the line "DEFAULT Auth-Type := Reject" in the authorize file, but then it proceeds to the ldap module and is granted access: (946) auth_log: EXPAND %t (946) auth_log: --> Wed Nov 25 02:26:21 2020 (946) [auth_log] = ok (946) [chap] = noop (946) [mschap] = noop (946) [digest] = noop (946) suffix: Checking for suffix after "@" (946) suffix: No '@' in User-Name = "<guest user>", looking up realm NULL (946) suffix: No such realm "NULL" (946) [suffix] = noop (946) eap: No EAP-Message, not doing EAP (946) [eap] = noop (946) files: Searching for user in group "<Full Admin group>" rlm_ldap (ldap): Reserved connection (204) (946) files: EXPAND (uid=%{%{Stripped-User-Name}:-%{User-Name}}) (946) files: --> (uid=<guest user>) (946) files: Performing search in "<Base DN>" with filter "(uid=<guest user>)", scope "sub" (946) files: Waiting for search result... (946) files: User object found at DN "uid=<guest user>,<Guest user path>" (946) files: Checking user object's memberOf attributes (946) files: Performing unfiltered search in "uid=<guest user>,<Guest user path>", scope "base" (946) files: Waiting for search result... (946) files: Processing memberOf value "<Guest ldap group>" as a DN rlm_ldap (ldap): Released connection (204) (946) files: User is not a member of "<Full Admin group>" (946) files: Searching for user in group "<Net Admin group>" rlm_ldap (ldap): Reserved connection (202) (946) files: Using user DN from request "uid=<guest user>,<Guest user path>" (946) files: Checking user object's memberOf attributes (946) files: Performing unfiltered search in "uid=<guest user>,<Guest user path>", scope "base" (946) files: Waiting for search result... (946) files: Processing memberOf value "<Guest ldap group>" as a DN rlm_ldap (ldap): Released connection (202) (946) files: User is not a member of "<Net Admin group>" (946) files: users: Matched entry DEFAULT at line 314 (946) [files] = ok rlm_ldap (ldap): Reserved connection (203) (946) ldap: EXPAND (uid=%{%{Stripped-User-Name}:-%{User-Name}}) (946) ldap: --> (uid=<guest user>) (946) ldap: Performing search in "<Base DN>" with filter "(uid=<guest user>)", scope "sub" (946) ldap: Waiting for search result... (946) ldap: User object found at DN "uid=<guest user>,<Guest user path>" (946) ldap: Processing user attributes (946) ldap: control:Password-With-Header += 'Wifi<guest user>' rlm_ldap (ldap): Released connection (203) (946) [ldap] = updated (946) [expiration] = noop (946) [logintime] = noop (946) pap: No {...} in Password-With-Header, re-writing to Cleartext-Password (946) pap: Removing &control:Password-With-Header (946) pap: WARNING: Auth-Type already set. Not setting to PAP (946) [pap] = noop (946) if (User-Password) { (946) if (User-Password) -> TRUE (946) if (User-Password) { (946) update control { (946) Auth-Type := ldap (946) } # update control = noop (946) } # if (User-Password) = noop (946) } # authorize = updated (946) Found Auth-Type = ldap (946) # Executing group from file /usr/local/etc/raddb/sites-enabled/default (946) authenticate { rlm_ldap (ldap): Reserved connection (204) (946) ldap: Login attempt by "<guest user>" (946) ldap: Using user DN from request "uid=<guest user>,<Guest user path>" (946) ldap: Waiting for bind result... (946) ldap: Bind successful What needs to be done in order for FR to make a decision based on the evaluation of the authorize file and 'accept' or 'reject' accordingly? Currently I'm going through the 'unlang' and 'SQL-Huntgroup-Howto' in the FR Wiki but I'm unable to work this one out. Perhaps a 'Post-auth' statement is necessary? - currently this is in the 'inner-tunnel' file: # # Access-Reject packets are sent through the REJECT sub-section of the # post-auth section. # # Add the ldap module name (or instance) if you have set # 'edir_account_policy_check = yes' in the ldap module configuration # Post-Auth-Type REJECT { # log failed authentications in SQL, too. -sql attr_filter.access_reject # # Let the outer session know which module failed, and why. # update outer.session-state { &Module-Failure-Message := &request:Module-Failure-Message } } } and this is in the 'default' file: Post-Auth-Type REJECT { # log failed authentications in SQL, too. -sql attr_filter.access_reject # Insert EAP-Failure message if the request was # rejected by policy instead of because of an # authentication failure eap # Remove reply message if the response contains an EAP-Message remove_reply_message_if_eap } Would anyone be able to give me some advice? Many Thanks! Kaya
On Nov 25, 2020, at 3:12 PM, Kaya Saman via Freeradius-Users <freeradius-users@lists.freeradius.org> wrote:
I've just noticed that there is a little difference in functionality between FR 2.x and 3.21. The config I have, worked fine in v2 but now in v3 it is not doing what I intend.
There's a bunch of differences, mostly minor. See raddb/README.rst in v3 for a complete upgrade guide, and a list of what changed.
I'm using an Openldap backend which consists of users and groups and I would like to restrict access based on the user-group association in ldap.
eg. any user belonging to the Guest group should only be given authenticated access to guest areas (currently restricted to Wifi) while 'normal' users should get standard Wifi access but not access to NAS config shells etc; admin group gets all access with no restrictions
My current FR config takes the Huntgroup name and looks at the 'l' values in ldap for a match. This is the tail end of my Authorize file: *I've used <> to indicate comments and it is not part of the config file*
OK... there usually isn't a lot of point in posting the config. But whatever.
The Outer-tunnel (default) file contains the following under the Authorize section:
authorize {
update request { Huntgroup-Name ="%{ldap:ldap:///<ldap path 1>?l?sub?cn=%{Packet-Src-IP-Address}}"
Why? Huntgroups are matched in the huntgroups file. If you want to define your own meaning for attributes, just define your own attributes. See raddb/dictionary for examples. Don't over-load the existing attributes. Things like Huntgroup-Name do *matching*. It's not really appropriate to set a value for them.
The Inner-tunnel file contains this, it's slightly different from the 'Outer' tunnel due to various matching issues I found when there are multiple 'l' values attached to the NAS lookup in ldap - To clarify what I mean is that example:- a Wireless Controller has Huntgroup2, Huntgroup3 and Huntgroup4 set in the 'l' value under different ldap paths, so if it matches <ldap path 3> then look the user up and authenticate
I don't know what you mean by "set in the l value". That's not a standard terminology.
- if the huntgroup does not match then try a different path using attributes based on the unlang operators:
If you're not using the huntgroups file, don't use Huntgroup-Name. If you want to set Huntgroup-Name to something, then you're using it wrong. Use another attribute.
This is a partial output from radiusd -X - the user is not found in any of the administrative ldap paths and then hits line 314 which is the line "DEFAULT Auth-Type := Reject" in the authorize file, but then it proceeds to the ldap module and is granted access:
Probably because the Huntgrop-Name comparisons are checking the ungroups file, and not the extra "Huntrgroup-Name" things you added.
What needs to be done in order for FR to make a decision based on the evaluation of the authorize file and 'accept' or 'reject' accordingly?
FreeRADIUS already makes a decision based on evaluating the "authorize" file.
Currently I'm going through the 'unlang' and 'SQL-Huntgroup-Howto' in the FR Wiki but I'm unable to work this one out. Perhaps a 'Post-auth' statement is necessary? - currently this is in the 'inner-tunnel' file
You don't need to move things to a different section. Instead, stop re-using existing attributes for different functionality. I'd also say to start with a simple example. Add a local attribute in raddb/dictionary, and use that. Maybe even move the "users" file checks to "unlang". Alan DeKok.
Many thanks Alan! On 2020-11-25 20:48, Alan DeKok wrote:
On Nov 25, 2020, at 3:12 PM, Kaya Saman via Freeradius-Users <freeradius-users@lists.freeradius.org> wrote:
The Inner-tunnel file contains this, it's slightly different from the 'Outer' tunnel due to various matching issues I found when there are multiple 'l' values attached to the NAS lookup in ldap - To clarify what I mean is that example:- a Wireless Controller has Huntgroup2, Huntgroup3 and Huntgroup4 set in the 'l' value under different ldap paths, so if it matches <ldap path 3> then look the user up and authenticate I don't know what you mean by "set in the l value". That's not a standard terminology.
I'm going to study and test your advise now so I'll get back later if things don't work, which is a high probability as I'm quite confused now :-S By 'l' value I meant the LocalityName attribute in ldap - for reference: http://www-public.imtbs-tsp.eu/~gardie/LDAP/Classes/Attributes-L.html By doing: authorize { update request { Huntgroup-Name ="%{ldap:ldap:///<ldap path>?l?sub?cn=%{Packet-Src-IP-Address}}" The Huntgroup-Name should equal the ?l? portion within the ldap path given before the Auth := Accept/Reject decision is made. I think this is where I am getting myself confused a little and probably finding it difficult to explain in addition?? In short I want to test the Huntgroup-Name against the ldap LocaliltyName attribute which should match. If they don't then send the Auth := Reject. I'm not sure if there are any examples of this to help me understand better how things work and how they should be implemented?
- if the huntgroup does not match then try a different path using attributes based on the unlang operators: If you're not using the huntgroups file, don't use Huntgroup-Name. If you want to set Huntgroup-Name to something, then you're using it wrong. Use another attribute.
This is a partial output from radiusd -X - the user is not found in any of the administrative ldap paths and then hits line 314 which is the line "DEFAULT Auth-Type := Reject" in the authorize file, but then it proceeds to the ldap module and is granted access: Probably because the Huntgrop-Name comparisons are checking the ungroups file, and not the extra "Huntrgroup-Name" things you added.
What needs to be done in order for FR to make a decision based on the evaluation of the authorize file and 'accept' or 'reject' accordingly? FreeRADIUS already makes a decision based on evaluating the "authorize" file.
Currently I'm going through the 'unlang' and 'SQL-Huntgroup-Howto' in the FR Wiki but I'm unable to work this one out. Perhaps a 'Post-auth' statement is necessary? - currently this is in the 'inner-tunnel' file You don't need to move things to a different section. Instead, stop re-using existing attributes for different functionality.
I'd also say to start with a simple example. Add a local attribute in raddb/dictionary, and use that. Maybe even move the "users" file checks to "unlang".
Alan DeKok.
Best Regards, Kaya
On Nov 25, 2020, at 4:45 PM, Kaya Saman via Freeradius-Users <freeradius-users@lists.freeradius.org> wrote:
By 'l' value I meant the LocalityName attribute in ldap - for reference: http://www-public.imtbs-tsp.eu/~gardie/LDAP/Classes/Attributes-L.html
Ok... that was not clear at all from your message.
By doing:
authorize {
update request { Huntgroup-Name ="%{ldap:ldap:///<ldap path>?l?sub?cn=%{Packet-Src-IP-Address}}"
The Huntgroup-Name should equal the ?l? portion within the ldap path given before the Auth := Accept/Reject decision is made.
Except that Huntgroup-Name already has a meaning. It performance checks in the "huntgroup" file.
I think this is where I am getting myself confused a little and probably finding it difficult to explain in addition??
You want to do a lot, so break it down into little pieces.
In short I want to test the Huntgroup-Name against the ldap LocaliltyName attribute which should match. If they don't then send the Auth := Reject.
No, you don't want to do that. You want to check ANOTHER attribute against the LDAP LocaliltyName. Please do what I said. DON'T use Huntgroup-Name. DO edit raddb/dictionary, and add your own attribute. Perhaps "My-Huntgroup-Name".
I'm not sure if there are any examples of this to help me understand better how things work and how they should be implemented?
I gave fairly clear instructions:
I'd also say to start with a simple example. Add a local attribute in raddb/dictionary, and use that. Maybe even move the "users" file checks to "unlang".
Break the problem down into pieces. If the "authorize" file seems confusing, use basic "unlang" statements. The debug output for "unlang" is very long and descriptive. It will tell you exactly what it's doing, and why. In contrast, the debug for the "authorize" file only shows what matches. It doesn't show why entries *don't* match. Alan DeKok.
Many thanks Alan for the great guidance! :-) I'm starting to understand a lot more now though there is still quite a lot of work to do. As per your instructions I created an Attribute in the dictionary file called 'Ldap-Locality'. I swapped all the cases of 'Huntgroup-Name' out and replaced them with 'Ldap-Locality'. Everything worked fine though the initial issue persists. Currently I am converting the authorize file entries to unlang. I have a few quick questions: 1. Do I need to add the unlang checks to both 'default' and 'inner-tunnel' files? 2. Will FR see more then 1 value in the LocalityName field on the ldap server once the NAS entry is matched in the ldap path? 3. Currently I have added this snippet as a test in 'default': authorize { update request { Ldap-Locality =... Ldap-Locality +=... } if (Ldap-Locality == "<LocalityName_string>") { if (Ldap-Group == "<group path>") { update reply { NAS-Port-Type = "Wireless-802.11", Airespace-QOS-Level = 3 } } } Is the 'update reply' portion correct as I am not seeing the Airespace-QOS-Level in the rad response from radiusd -X output? Regards, Kaya On 2020-11-25 22:04, Alan DeKok wrote:
On Nov 25, 2020, at 4:45 PM, Kaya Saman via Freeradius-Users <freeradius-users@lists.freeradius.org> wrote:
By 'l' value I meant the LocalityName attribute in ldap - for reference: http://www-public.imtbs-tsp.eu/~gardie/LDAP/Classes/Attributes-L.html Ok... that was not clear at all from your message.
By doing:
authorize {
update request { Huntgroup-Name ="%{ldap:ldap:///<ldap path>?l?sub?cn=%{Packet-Src-IP-Address}}"
The Huntgroup-Name should equal the ?l? portion within the ldap path given before the Auth := Accept/Reject decision is made. Except that Huntgroup-Name already has a meaning. It performance checks in the "huntgroup" file.
I think this is where I am getting myself confused a little and probably finding it difficult to explain in addition?? You want to do a lot, so break it down into little pieces.
In short I want to test the Huntgroup-Name against the ldap LocaliltyName attribute which should match. If they don't then send the Auth := Reject. No, you don't want to do that. You want to check ANOTHER attribute against the LDAP LocaliltyName.
Please do what I said. DON'T use Huntgroup-Name. DO edit raddb/dictionary, and add your own attribute. Perhaps "My-Huntgroup-Name".
I'm not sure if there are any examples of this to help me understand better how things work and how they should be implemented? I gave fairly clear instructions:
I'd also say to start with a simple example. Add a local attribute in raddb/dictionary, and use that. Maybe even move the "users" file checks to "unlang". Break the problem down into pieces. If the "authorize" file seems confusing, use basic "unlang" statements. The debug output for "unlang" is very long and descriptive. It will tell you exactly what it's doing, and why.
In contrast, the debug for the "authorize" file only shows what matches. It doesn't show why entries *don't* match.
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
On Nov 25, 2020, at 11:20 PM, Kaya Saman via Freeradius-Users <freeradius-users@lists.freeradius.org> wrote:
Many thanks Alan for the great guidance! :-)
You're welcome. Despite rumours to the contrary, I do help people.
As per your instructions I created an Attribute in the dictionary file called 'Ldap-Locality'. I swapped all the cases of 'Huntgroup-Name' out and replaced them with 'Ldap-Locality'. Everything worked fine though the initial issue persists.
OK.
Currently I am converting the authorize file entries to unlang. I have a few quick questions:
1. Do I need to add the unlang checks to both 'default' and 'inner-tunnel' files?
It depends what you want to do... Generally for 802.1X, the *real* user name isn't visible in the "default" server, but only in the "inner-tunnel" server. So you have to put the rules there. Then, see the "inner-tunnel" server, and look for "use_tunneled_reply". You can copy the attributes from the inner reply to the outer one.
2. Will FR see more then 1 value in the LocalityName field on the ldap server once the NAS entry is matched in the ldap path?
It depends on how you configured it. If you add more than one attribute, then yes, it will see more than one attribute.
3. Currently I have added this snippet as a test in 'default':
authorize {
update request { Ldap-Locality =...
Ldap-Locality +=... } if (Ldap-Locality == "<LocalityName_string>") { if (Ldap-Group == "<group path>") { update reply { NAS-Port-Type = "Wireless-802.11", Airespace-QOS-Level = 3 } } }
Is the 'update reply' portion correct as I am not seeing the Airespace-QOS-Level in the rad response from radiusd -X output?
Read the debug log in DETAIL. It will print out when it runs that "authorize" section. it will print out each "update" section, and each "if" section. DON'T just look at the final Access-Accept. Doing so is an utter waste of time. It's like driving randomly for 3 hours with your eyes closed, then opening them and wondering why you're not home. You have to look at each individual bit along the way to see what's going on. The same goes for the debug output. Read it. ALL of it. Go over it slowly, looking for configuration bits you added. Then, see if it's doing what you think it's doing. Alan DeKok.
participants (2)
-
Alan DeKok -
Kaya Saman