Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

dynamic VLAN assignment w/ mschapv2 against AD and LDAP

424 views
Skip to first unread message

schilling

unread,
Jan 20, 2011, 11:57:06 AM1/20/11
to
Hi All,

The group helped me configure the freeradius server to do mschapv2
against ldap w/ ntPassword if user sign on with user...@foo.edu, and
to do mschapv2 against AD w/ ntlm if user just sign on with username.
Now I want to go one more step further - passing on some attributes
back to NAS. Basically, I want to achieve
If (ldap authorization) {
if (ldap.employeeStatus = facstaff) {
REPLY{'Service-Type'} = "Framed-User";
REPLY{'Tunnel-Type'} = "VLAN";
REPLY{'Tunnel-Medium-Type'} = "IEEE-802";
REPLY{'Tunnel-Private-Group-Id'} = "facstaff";
} else { # no ldap.employeeStatus attribute or ldap.employeeStatus
!= facstaff
REPLY{'Service-Type'} = "Framed-User";
REPLY{'Tunnel-Type'} = "VLAN";
REPLY{'Tunnel-Medium-Type'} = "IEEE-802";
REPLY{'Tunnel-Private-Group-Id'} = "student";
}
}else { # ntlm authentication
REPLY{'Service-Type'} = "Framed-User";
REPLY{'Tunnel-Type'} = "VLAN";
REPLY{'Tunnel-Medium-Type'} = "IEEE-802";
REPLY{'Tunnel-Private-Group-Id'} = "facstaff";
}

What's the easiest way to accomplish this? unlang? perl module? Where to start?

Thanks,

Schilling

from schilling <schill...@gmail.com>
to FreeRadius users mailing list <freeradi...@lists.freeradius.org>
date Tue, Dec 14, 2010 at 3:14 PM
subject Re: One virtual server for MS-chapv2 against AD w/ ntlm_auth,
the other one against ldap ntpasswd hash possible?
mailed-by gmail.com

Got the whole setup working. So basically if users sign on with
user...@foo.edu with eap, they will be sent to ldap w/ ntpassword
authorization. If users sign on with username only with eap, they will
be sent to active directory w/ ntlm authentication.
configuration changes are the following:
etc/raddb/proxy.conf add
realm foo.edu {
}
realm NULL {
}
/etc/raddb/site-enabled/inner-tunnel at the ldap line in authorize section add
switch "%{Realm}" {
case foo.edu {
ldap
#see /etc/raddb/module/mschap if ntpassword available,
then do not use
#NTLM_auth
update control {
MS-CHAP-Use-NTLM-Auth := NO
}
case NULL {
mschap
}
}

etc/raddb/module/mschap, etc/raddb/module/ntlm are all from integrate
with Active Directory howto.
-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html

Alan DeKok

unread,
Jan 20, 2011, 2:15:08 PM1/20/11
to
schilling wrote:
>Basically, I want to achieve
> If (ldap authorization) {
> if (ldap.employeeStatus = facstaff) {
> REPLY{'Service-Type'} = "Framed-User";
> REPLY{'Tunnel-Type'} = "VLAN";
> REPLY{'Tunnel-Medium-Type'} = "IEEE-802";
> REPLY{'Tunnel-Private-Group-Id'} = "facstaff";
> } else { # no ldap.employeeStatus attribute or ldap.employeeStatus

You can put pretty much that into a Perl script, or into "unlang".

> What's the easiest way to accomplish this? unlang? perl module? Where to start?

I'd write a Perl script first.

Alan DeKok.

schilling

unread,
Jan 20, 2011, 3:41:03 PM1/20/11
to
Where should I put the perl script? I already have a perl module for
another virtual server to use radscript.

I also tried unlang in post-auth, like
if ( %{User-Name} =~ /\@/ && fooEmployeeStatus =~ /active/i ) {
update outer.reply {
Service-Type = "Framed-User"
Tunnel-Type = "VLAN"
Tunnel-Medium-Type = "IEEE-802"
Tunnel-Private-Group-Id = "facstaff"
}
}

I did map something to fooEmployeeStatus in ldap.attrmaps
Bare %{...} is invalid in condition at: %{User-Name} =~ /\@/ &&
fooEmployeeStatus =~ /active/i )
/home/sding/opt/etc/raddb/sites-enabled/inner-tunnel[276]: Errors
parsing post-auth section.

How can I reference User-Name in post-auth section of inner-tunnel?

Thanks,

Schilling

Alan Buxey

unread,
Jan 20, 2011, 6:17:44 PM1/20/11
to
Hi,

> Where should I put the perl script? I already have a perl module for
> another virtual server to use radscript.
>
> I also tried unlang in post-auth, like
> if ( %{User-Name} =~ /\@/ && fooEmployeeStatus =~ /active/i ) {
> update outer.reply {
> Service-Type = "Framed-User"
> Tunnel-Type = "VLAN"
> Tunnel-Medium-Type = "IEEE-802"
> Tunnel-Private-Group-Id = "facstaff"
> }
> }


if ( "%{User-Name}" =~ /\@/ && fooEmployeeStatus =~ /active/i ) {

encase in quotes....dont have bare as per debug error

alan

Alexander Clouter

unread,
Jan 21, 2011, 3:49:55 AM1/21/11
to
schilling <schill...@gmail.com> wrote:
>
> Where should I put the perl script? I already have a perl module for
> another virtual server to use radscript.
>
> I also tried unlang in post-auth, like
> if ( %{User-Name} =~ /\@/ && fooEmployeeStatus =~ /active/i ) {
> update outer.reply {
> Service-Type = "Framed-User"
> Tunnel-Type = "VLAN"
> Tunnel-Medium-Type = "IEEE-802"
> Tunnel-Private-Group-Id = "facstaff"
> }
> }
>
I cannot recommend more *not* to do your authorisation in the inner
tunnel, and instead to pass it back on out. There are a number of
reasons, clarity including, but especially you then can make use of the
reject path...

Incase it helps, this is what we (a small-medium university in the
UK) do. In our eap block we set (we use TTLS, however it should be the
same for PEAP):
----
eap {
...

ttls {
...
copy_request_to_tunnel = no
use_tunneled_reply = yes
virtual_server = "auth"
}

...
}

Then we have a 'auth' virtual server:
----
server auth {
authorize {
if ((outer.request:EAP-Message)) {
update outer.request {
User-Name := "%{request:User-Name}"
}
update reply {
User-Name := "%{request:User-Name}"
}
}

validate_username

suffix

if ((outer.request:EAP-Message) && Realm != "%{config:local.MY.realm}") {
update outer.reply {
Reply-Message := "Realm is '%{Realm}' on Inside"
}
reject
}

# if the password is passed to us use it, otherwise yank it from LDAP
if ((outer.request:Cleartext-Password)) {
update control {
Cleartext-Password := "%{outer.request:Cleartext-Password}"
}
}
else {
ldap-login

# some accounts are glitched and do not have a UP :(
if (ok && !(control:Cleartext-Password)) {
update outer.reply {
Reply-Message := "No eDirectory UP"
}
reject
}
}

pap
chap
mschap

update reply {
Auth-Type := "%{control:Auth-Type}"
}
}

authenticate {
Auth-Type PAP {
pap
}
Auth-Type CHAP {
chap
}
Auth-Type MSCHAP {
mschap
}
}
}
----

We are 'blessed' with Novhell, so 'ldap-login' populated
Cleartext-Password from eDirectory if present, your approach would be
different (the interesting bit is if you set
'request:Cleartext-Password' in your outer layer before calling 'eap',
which is a handy hook for a NAGIOS RADIUS hook (letting you test
authentication with eapol_test[1] and remove the AD component from the
equation.

Once the 'auth' virtual server finishes, you will find in the outer
layer for *successful* authentications, 'reply:User-Name' is the inner
username whilst for *failure* authentications you want to use
'request:User-Name'.

> I did map something to fooEmployeeStatus in ldap.attrmaps

> Bare %{...} is invalid in condition at: %{User-Name} =~ /\@/ &&
> fooEmployeeStatus =~ /active/i )


> /home/sding/opt/etc/raddb/sites-enabled/inner-tunnel[276]: Errors
> parsing post-auth section.
>
> How can I reference User-Name in post-auth section of inner-tunnel?
>

In your outer post-auth section then I would recommend the following
unlang (prime the defaults, and use the attributes to fixup what you
want the final result to be):
----
post-auth {
...

# defaults
update reply {


Tunnel-Type := VLAN
Tunnel-Medium-Type := IEEE-802

Tunnel-Private-Group-Id := "unauthorised"

Termination-Action := RADIUS-Request

# Cisco only support a max of 65535
Session-Timeout := 64800

Acct-Interim-Interval := 3600
}

if ( User-Name =~ /@/ && (fooEmployeeStatus) ) {
update reply {
Tunnel-Private-Group-Id := "facstaff"
}
}

...
}
----

If you want to lower the load (and authentication latency) on your AD
servers then you might want to look at the following too:

http://www.mail-archive.com/freeradi...@lists.freeradius.org/msg65781.html

Cheers

[1] http://deployingradius.com/scripts/eapol_test/

--
Alexander Clouter
.sigmonster says: Never ask the barber if you need a haircut.

schilling

unread,
Jan 22, 2011, 11:48:40 PM1/22/11
to
I have the following questions for using perl though. Since I already
use LDAP or ntlm_auth for inner-tunnel mschapv0 authentication. Will
there any flag set so I can know whether LDAP or ntlm_auth is using
for mschapv0 authentication in perl script? Also if if I need to check
ldap/AD for certain attributes in perl script, Do I need to make
another call to them via LDAP in the perl module? Where should I put
the perl script in?

Many Thanks,

Schilling

On Thu, Jan 20, 2011 at 2:15 PM, Alan DeKok <al...@deployingradius.com> wrote:
> schilling wrote:
>>Basically, I want to achieve
>> If (ldap authorization) {
>>     if (ldap.employeeStatus = facstaff) {
>>         REPLY{'Service-Type'}            = "Framed-User";
>>         REPLY{'Tunnel-Type'}             = "VLAN";
>>         REPLY{'Tunnel-Medium-Type'}      = "IEEE-802";
>>         REPLY{'Tunnel-Private-Group-Id'} = "facstaff";
>>     } else { # no ldap.employeeStatus attribute or ldap.employeeStatus
>
>  You can put pretty much that into a Perl script, or into "unlang".
>
>> What's the easiest way to accomplish this? unlang? perl module? Where to start?
>
>  I'd write a Perl script first.
>
>  Alan DeKok.
>

schilling

unread,
Jan 24, 2011, 3:35:21 PM1/24/11
to
Hi Alexander,

I am trying to play with your configuration, basically I have a
virtual server call auth as your example, and modified my eap.conf for
peap to use auth.

what's the config:local.MY.realm? My debug showed

[suffix] Looking up realm "foo.edu" for User-Name = "sd...@foo.edu"^M
[suffix] Found realm "foo.edu"^M
[suffix] Adding Stripped-User-Name = "sding"^M
[suffix] Adding Realm = "foo.edu"^M
[suffix] Authentication realm is LOCAL.^M
++[suffix] returns ok^M
++? if (( outer.request:EAP-Message) && Realm != "%{config:local.MY.realm}" )^M
?? Evaluating (outer.request:EAP-Message) -> TRUE^M
expand: local.MY.realm -> local.MY.realm^M
WARNING: No such configuration item local.MY.realm^M
expand: %{config:local.MY.realm} -> ^M
? Evaluating (Realm != "%{config:local.MY.realm}" ) -> TRUE^M
++? if (( outer.request:EAP-Message) && Realm !=
"%{config:local.MY.realm}" ) -> TRUE^M
++- entering if (( outer.request:EAP-Message) && Realm !=
"%{config:local.MY.realm}" ) {...}^M
expand: Realm is '%{Realm}' on Inside -> Realm is 'foo.edu' on Inside^M
+++[outer.reply] returns ok^M
+++[reject] returns reject^M
++- if (( outer.request:EAP-Message) && Realm !=
"%{config:local.MY.realm}" ) returns reject^M
} # server auth^M

Thanks,

Schilling

Phil Mayers

unread,
Jan 24, 2011, 3:43:32 PM1/24/11
to
On 01/24/2011 08:35 PM, schilling wrote:
> Hi Alexander,
>
> I am trying to play with your configuration, basically I have a
> virtual server call auth as your example, and modified my eap.conf for
> peap to use auth.
>
> what's the config:local.MY.realm? My debug showed

FreeRadius lets you write *any* config hierarchy object, and re-use it
elsewhere; in radiusd.conf (or maybe an include) put:

local {
MY {
realm = x.x

Alexander Clouter

unread,
Jan 24, 2011, 4:38:08 PM1/24/11
to
schilling <schill...@gmail.com> wrote:
>
> I am trying to play with your configuration, basically I have a
> virtual server call auth as your example, and modified my eap.conf for
> peap to use auth.
>
> what's the config:local.MY.realm? My debug showed
>
Phil pretty much covered it (and in a neater manner I was not aware
could be used, but it is obvious now seeing it...), I put all the 'local
site' specific details into a single configuration file (including
SQL/LDAP binding credentials) so that if I want to give someone a copy
of my config, ll I have to really do is trim the 'local' file and know I
have not leaked anything important.

For example, just after '$INCLUDE clients.conf' in the main radiusd.conf
file I add '$INCLUDE LOCAL/local.conf' and that LOCAL/local.conf file
is:
----
local.MY.hostname = iodine.it.soas.ac.uk
local.MY.addr.v6 = 2001:630:1b:6004:168c:9d91:127f:bb0c
local.MY.addr.v4 = 212.219.138.70

local.MY.realm = soas.ac.uk

local.addr.v6 = 2001:630:1b:1001:624a::15bb
local.addr.v4 = 193.63.73.37

local.test.username = test-username
local.test.password = [ahem]

local.ldap.server.1 = ldap1.soas.ac.uk
local.ldap.server.2 = ldap2.soas.ac.uk
local.ldap.username = cn=cheese,ou=is,o=tasty
local.ldap.password = NOM

local.sql.server = sql.soas.ac.uk
local.sql.username = radius-username
local.sql.password = oh-so-very-secret

local.cert.password = omg-do-not-tell-anyones

[snipped]

$INCLUDE ${confdir}/LOCAL/templates.conf

$INCLUDE ${confdir}/LOCAL/policy.conf

$INCLUDE ${confdir}/LOCAL/proxy.conf

$INCLUDE ${confdir}/LOCAL/clients/
----

Cheers

--
Alexander Clouter
.sigmonster says: Riches cover a multitude of woes.
-- Menander

schilling

unread,
Jan 24, 2011, 6:40:40 PM1/24/11
to
Thanks a lot.

More questions.

If you want to lower the load (and authentication latency) on your AD
servers then you might want to look at the following too:

http://www.mail-archive.com/freeradi...@lists.freeradius.org/msg65781.html

I am trying to follow your comment on this. I now realized we used to
run eDir and now converted to iplanet directory. Anyway, do I still
need to enable the compilation --with-edir option as stated below? My
guess is yes since otherwise, I could not call ldap in the post-auth
section in "auth" virtual server for eap.
##etc/raddb/modules/ldap
# Un-comment the following to disable Novell
# eDirectory account policy check and intruder
# detection. This will work *only if* FreeRADIUS is
# configured to build with --with-edir option.
#
#edir_account_policy_check = no

What I want to do is just to check some attribute in our ldap server,
our structure is like the following:
# extended LDIF
#
# LDAPv3
# base <ou=people,dc=foo,dc=edu> with scope subtree
# filter: uid=sding
# requesting: ALL
#

# sding, People, foo.edu
dn: uid=sding,ou=People,dc=foo,dc=edu
ntPassword: 123F0AE5D10B5CCD1A7366E8DEABCDE
fooEduPSHRdeptName: Information Technology Service (ITS)
fooEduPSHRDepartmentNumber: 123456
fooEduEmployeeStatus: Active
employeeStatus: Active
uid: sding

I would like to cache the following attribut/value in your example
cache_ldap-userdn.pm, so I can use these values as logic to assign
user to different VLANs. Can I do that in your pm?
fooEduPSHRdeptName: Information Technology Service (ITS)
fooEduPSHRDepartmentNumber: 123456
fooEduEmployeeStatus: Active
employeeStatus: Active

Thanks,

Schilling

Alexander Clouter

unread,
Jan 25, 2011, 4:23:38 AM1/25/11
to
schilling <schill...@gmail.com> wrote:
>
> Thanks a lot.
>
> More questions.
>
> If you want to lower the load (and authentication latency) on your AD
> servers then you might want to look at the following too:
>
> http://www.mail-archive.com/freeradi...@lists.freeradius.org/msg65781.html
>
First things first, did you get it all working? If not, start there.
When I say 'lower the load', all it does is reduce the number of EAP
packets from about 12 to 4 that are needed for a session resumption; but
also means you only need two LDAP lookups rather that 12. So your AD
load will go from 0.000001 to 0.0000000001 or something. I am bigging
up the numbers more than it is worth (although the latency bit is
possibly handy for roaming devices).
The eDir bit's are probably not needed as you are using mschap with
those 'ntPassword' attributes. eDir has 'universal password' which is a
sales monkey's way of saying "the password is available in plaintext if
required". Sounds like to me you do not currently have FreeRADIUS setup
working the way you want it to?

> I would like to cache the following attribut/value in your example
> cache_ldap-userdn.pm, so I can use these values as logic to assign
> user to different VLANs. Can I do that in your pm?
> fooEduPSHRdeptName: Information Technology Service (ITS)
> fooEduPSHRDepartmentNumber: 123456
> fooEduEmployeeStatus: Active
> employeeStatus: Active
>

Looks like 'employeeStatus' should go in as part of your user filter,
but to do the others I would need to generalise my Perl module. Easily
done, but I'm not going to do it before I know actually have it already
working. :)

/me pats sigmonster and gives it a cookie

Cheers

--
Alexander Clouter
.sigmonster says: Success is a journey, not a destination.

schilling

unread,
Jan 25, 2011, 10:19:03 AM1/25/11
to
I believe I resolved this. I used eapol_test to get all wanted
result, and will try on real NAS later on.

The following is what I did. Basically I followed Alexander's example,
Modified peap section in eap.conf to use another virtual server "auth"
instead of inner-tunnel virtual server. I almost blindly copied
Alexander's example in auth server except I removed the reject for the
realm checks.

The ldap cache pm is not needed in my case since I do not query
windows AD via LDAP to get their attributes. If I want to do ldap
after ntlm against AD, then Alexander's pm might be needed.

Then I want to map certain attribute like employeeStatus from our
iPlanet ldap server to some radius attribute, so I can manipulate it
in the post-auth section.
I put the following line in etc/raddb/dictionary
ATTRIBUTE My-Local-employeeStatus 3000 string

and the following line in etc/raddb/ldap.attrmap
#FOO specific attributes
replyItem My-Local-employeeStatus employeeStatus

Without these two line addition, radius will complain unknown attribute.

Then in the post-auth section

#default will have no Tunnel attribute/value, instead, they will be
configured on
#the NAS to go to student VLANs.

# this will cover my ldap ntPassword authentication/authorization
#facstaff have employeeStatus set while student does not
if ( "%{User-Name}" =~ /@/ && "%{reply:My-Local-employeeStatus}" ) {
update reply {


Service-Type = "Framed-User"
Tunnel-Type = "VLAN"
Tunnel-Medium-Type = "IEEE-802"
Tunnel-Private-Group-Id = "facstaff"
}
}

#this will cover my AD ntlm auth, People in AD are all facstaff
if ( "%{User-Name}" !~ /@/ ) {
update reply {


Service-Type = "Framed-User"
Tunnel-Type = "VLAN"
Tunnel-Medium-Type = "IEEE-802"
Tunnel-Private-Group-Id = "facstaff"
}
}

In this way, people can map arbitrary attribute from ldap to radius,
if not in dictionary/ldap.attrmap, then just defined your own. Then
you have flexibility of using these attribute/value in your logic at
post-auth section.

Thanks all for the hints and help!

Schilling

0 new messages