RADIUS with LDAP: changing LDAP filter based on RADIUS request
Sylvain Robitaille
syl at alcor.concordia.ca
Mon Jun 9 22:54:20 CEST 2008
Background:
We're using FreeRADIUS-2.0.3 with an OpenLDAP backend, on two separate
systems for authentication and authorization of users to our wireless
network and a lesser-used VPN service. I would like to be able to modify
the LDAP query filter based on (for example) which NAS device sent the
RADIUS request so that (again, for example) a different filter might be
used to search for wireless users than for VPN users.
In an effort to be able to setup a "dynamic" LDAP query filter, I have
tried adding a string-type attribute to our local dictionary file,
to hold the filter that would be updated on-the-fly:
ATTRIBUTE CU-LDAP-Filter 3000 string
The radiusd.conf file then has ldap module instances (one per LDAP
server) with the following reference to this attribute:
ldap ldap_host1 {
server = "ldap_host1"
identity = "cn=...,ou=...,dc=concordia,dc=ca"
password = "**SANITIZED**"
basedn = "ou=people,dc=concordia,dc=ca"
filter = "%{CU-LDAP-Filter}"
base_filter = "(objectclass=ConcordiaPerson)"
...
}
ldap ldap_host2 {
server = "ldap_host2"
identity = "cn=...,ou=...,dc=concordia,dc=ca"
password = "**SANITIZED**"
basedn = "ou=people,dc=concordia,dc=ca"
filter = "%{CU-LDAP-Filter}"
base_filter = "(objectclass=ConcordiaPerson)"
...
}
I'm presently testing with the radeapclient client (on localhost), so am
testing with the following configured into sites-enabled/default:
authorize {
...
switch "%{NAS-IP-Address}" {
case 192.168.198.20 {
# test
update control {
CU-LDAP-Filter = "(&(cn=%{%{Stripped-User-Name}:-%{User-Name}})(***LDAP QUERY1 TRIMMED FOR BREVITY***))"
}
}
case 127.0.0.1 {
# test
update control {
CU-LDAP-Filter = "(&(cn=%{%{Stripped-User-Name}:-%{User-Name}})(***LDAP QUERY2 TRIMMED FOR BREVITY***))"
}
}
...
case {
# default
noop
}
}
if ("%{CU-LDAP-Filter}" != "") {
redundant-load-balance {
ldap_host1
ldap_host2
}
}
...
}
The LDAP query filters, though not included above (these things are quite
long and site-specific anyway) are known to work, as they're copied from
our currently in-production configuration that is selecting the ldap
module instance based on the NAS-IP-Address (ie. if NAS-IP-Address is
the VPN server we call the ldap_vpn module which is configured with an
appropriate filter, else we call the ldap_wireless module which is also
appropriately configured). The present setup works, but based on what
I'm reading it would give is a much more flexible and fault-tolerant
(and dare-I-say, more manageable?) setup if I could get the LDAP module
instances configured into a redundant-load-balance stanza, with a
dynamically determined LDAP query filter (so that if one LDAP server is
unavailable, one or more others could be tried instead, instead of
having a hard-coded query to specific LDAP servers for each service).
I hope I'm making sense so far ...
The following command is issued to test:
radeapclient -x localhost:1815 auth testing123 << END_OF_EAP
User-Name = "j_doe"
Cleartext-Password = "**SANITIZED**"
NAS-IP-Address = 192.168.198.20
NAS-Port-Type = "Wireless-802.11"
EAP-Code = Response
EAP-Id = 210
EAP-Type-Identity = "j_doe"
Message-Authenticator = 0x00
NAS-Port = 0
END_OF_EAP
Radiusd, running in debug mode shows the following (config-file parsing
output skipped; it is not showing any errors at all, so although the
configuration I show above may not be producing the intended result, it
at least seems syntactically correct):
Listening on authentication address * port 1815
Listening on accounting address * port 1816
Listening on proxy address * port 1817
Ready to process requests.
User-Name = "j_doe"
NAS-IP-Address = 192.168.198.20
NAS-Port-Type = Wireless-802.11
Message-Authenticator = 0x8499bae7c162d5f0ef2e587fdb9086a0
NAS-Port = 0
EAP-Message = 0x02d200080173796c
+- entering group authorize
++[preprocess] returns ok
++[chap] returns noop
++[mschap] returns noop
rlm_realm: No '@' in User-Name = "j_doe", looking up realm NULL
rlm_realm: No such realm "NULL"
++[suffix] returns noop
rlm_eap: EAP packet type response id 210 length 8
rlm_eap: No EAP Start, assuming it's an on-going EAP conversation
++[eap] returns updated
++[unix] returns notfound
++[files] returns noop
expand: %{NAS-IP-Address} -> 192.168.198.20
++- entering switch %{NAS-IP-Address}
+++- entering case 192.168.198.20
expand: %{Stripped-User-Name} ->
expand: %{User-Name} -> j_doe
expand: (&(cn=%{%{Stripped-User-Name}:-%{User-Name}})**LDAP QUERY1 FILTER TRIMMED**) -> (&(cn=j_doe)**LDAP QUERY1 FILTER TRIMMED**)
++++[control] returns noop
+++- case 192.168.198.20 returns noop
++- switch %{NAS-IP-Address} returns noop
++? if ("%{CU-LDAP-Filter}" != "")
expand: %{CU-LDAP-Filter} ->
? Evaluating ("%{CU-LDAP-Filter}" != "") -> FALSE
++? if ("%{CU-LDAP-Filter}" != "") -> FALSE
++[expiration] returns noop
++[logintime] returns noop
rlm_pap: WARNING! No "known good" password found for the user. Authentication may fail because of this.
++[pap] returns noop
rad_check_password: Found Auth-Type EAP
auth: type "EAP"
+- entering group authenticate
rlm_eap: EAP Identity
rlm_eap: processing type tls
rlm_eap_tls: Initiate
rlm_eap_tls: Start returned 1
rlm_eap: RT Modif EAP-Type = 21 EAP-LENGTH = 1
++[eap] returns handled
EAP-Message = 0x01d300061520
Message-Authenticator = 0x00000000000000000000000000000000
State = 0x1c870d031c541859b55d17dd8af5914a
Finished request 0.
Going to the next request
Waking up in 4.9 seconds.
Cleaning up request 0 ID 232 with timestamp +4
Ready to process requests.
Note that of the above, I believe the following is relevant to my
question:
expand: %{NAS-IP-Address} -> 192.168.198.20
++- entering switch %{NAS-IP-Address}
+++- entering case 192.168.198.20
expand: %{Stripped-User-Name} ->
expand: %{User-Name} -> j_doe
expand: (&(cn=%{%{Stripped-User-Name}:-%{User-Name}})**LDAP QUERY1 FILTER TRIMMED**) -> (&(cn=j_doe)**LDAP QUERY1 FILTER TRIMMED**)
++++[control] returns noop
+++- case 192.168.198.20 returns noop
++- switch %{NAS-IP-Address} returns noop
++? if ("%{CU-LDAP-Filter}" != "")
expand: %{CU-LDAP-Filter} ->
? Evaluating ("%{CU-LDAP-Filter}" != "") -> FALSE
++? if ("%{CU-LDAP-Filter}" != "") -> FALSE
This corresponds to the following from the "authorize" section in my
sites-enabled/default file:
switch "%{NAS-IP-Address}" {
case 192.168.198.20 {
# test
update control {
CU-LDAP-Filter = "(&(cn=%{%{Stripped-User-Name}:-%{User-Name}})(***LDAP QUERY TRIMMED FOR BREVITY***))"
}
}
}
We see that the line where I intend to assign a value to CU-LDAP-Filter
is indeed encountered and the variables referred to in that line are
expanded correctly, but it seems as though the assignment to
CU-LDAP-Filter isn't done: if ("%{CU-LDAP-Filter}" != "") is evaluated
as "FALSE".
I suspect that my "update" statement is likely incorrect, since the only
mention of it in the debug output is:
++++[control] returns noop
Can anyone help me with this? I've read as much of the relevant
documentation as I'm aware exists, especially "man unlang" without which
I certainly wouldn't have gotten even this far, but I'd be very grateful
if someone could point me to further documentation that would help with
what I'm trying to do ...
Thanks ...
--
----------------------------------------------------------------------
Sylvain Robitaille syl at alcor.concordia.ca
Systems and Network analyst Concordia University
Instructional & Information Technology Montreal, Quebec, Canada
----------------------------------------------------------------------
More information about the Freeradius-Users
mailing list