Mini-mini-HowTo freeradius vs. ActiveDirectory

Völker, Christian Christian.Voelker at qsc.de
Thu Nov 17 11:28:56 CET 2005


Yohoo!

Ok, I got it running. My freeradius authenticates vs. our ActiveDirectory (MS Win  2003 Server).

Here is a short summary, written as HowTo. It's version 0.0.1beta ;-)

_*Mini HowTo*_

*Authenticate freeradius vs. ActiveDirectory*
Nov. 2005

*Author:*
Christian Völker, c.voelker "at/@" knebb "dot/." de
Feel free to contact.

This is only a very mini and small version to help you getting the freeradius- server authenticating vs. ActiveDirectory.

*Disclaimer:*
I'm not responsible for anything if you follow these instructions. Do it at your own risk. I'm a linux specialist (RHCE, Novell CNI and CLP,...) and don't have much knowledge about the windows stuff. So I can't explain any of these things going on there ;)

*Situation:*
We want to authenticate administrators of our network-devices against our existing ActiveDirectory. ActiveDirectory can communicate via the LDAP-protocol. But the user attributes of the MS-users aber different from the "normal" Unix-UIDs in (Open)LDAP. So you can't easily switch between OpenLDAP and AD.
Additionally, there should be a failover if one of our AD servers is going down.

*Prerequisites:*
_freeradius_
Here I used 1.0.1-1.RHEL on a RedHat Enterprise Linux AS release 3, running in a virtual machine under VMWare (don't care, a real machine would be fine also ;-))
_ActiveDirectory_
Of course, you will need AD running. Here, is it an MS-Windows 2003 Server.
_Linux_
I've installed it on a RedHat Enterprise Linux AS release 3 system, any other system would be ok also.

What we don't need is ntlm_auth, winbindd or kerberos.

*Preface:*
_PAP/CHAP..._
Alan DeKok wrote in the mailing list:
-----------mail-----------
This is done via simple LDAP bind, which AD supports.
It works for PAP authentication.  It doesn't work for CHAP, MSCHAP,
or PEAP.
-----------end mail-----------
Don't assk me for any disadvantages, my knowledge about the MS products is very low.
_failover_
Another statement from Alan DeKok (Dec, 15, 2004)
-----------mail-----------
> However, when I am using redundant, I cannot have this redundancy for  
> Ldap-Group lookups.  
Yes.  That's an issue.  
-----------end mail-----------
So there is no functionality for Ldap-groups with failover. Below I can show you a workaround from Dustin Doris.

*How-To*
_/etc/raddb/radiusd.conf_
I don't understand all of the features. All I changed were the ldap parms. So take a look at my /etc/raddb/radius.conf. Some explanations are commented with "#": I only changed parts in the ldap section. So the rest should be left as default.

-----------file-----------
ldap {
	# servername or ip
	# should be resolvable with dns and reverse DNS
	server = "ads2.example.com"

	# Usually AD doesn't allow anonymous requests
	# so you have to create a proxy users for the requests
	# you should enter the full DN here
	identity = "cn=proxy,ou=service,dc=example,dc=com"

	# also the password for the proxy user should be given here
	# It's cleartext, so it could be a security flaw
	password = 'password'

	# this is the basedn, where freeradius starts with it's search
	# without the "ou=" it didn't work here (don't know why!)
	basedn = "ou=all_users,dc=example,dc=com"

	# the filterparm tells radius where to look for the username
	# due of AD it's not the usual OpenLDAP, you have to 
	# use the login name of AD. It's called "sAMAaccountname"
	# if you don't trust, take a look at AD with a ldap browser
	# Our AD is very huge, the servers are very slow
	# I encoutered problems by checking the groupmembership when users
 	# are member in many groups
 	# so I added the AND (&) and filtered against objectClass=person
	# additionally I increased again the timeout values
	# Now everything runs fine
	filter = "(&(sAMAccountname=%{Stripped-User-Name:-%{User-Name}})(objectClass=person))"

	# the groupname_attribute describes, which object type the
	# groups are. In my case all groups are stored as
	# cn=...
	# I'm not sure about this, but it's working here
	groupname_attribute = "cn"

	# Also I had to check the meaning of the filters. 
	# I hadn't found any explanation of this parm
	# so I will explain my understanding of this parm
	# "|" and "&" are logical operators  for "OR" and "AND"
	# %{Ldap-UserDn} is a variable, self-explanation
	# The following statement looks only for the objectClasses group 
	# and top which I figured out in our AD setup for the groups
	groupmembership_filter = "(|(&(objectClass=group)(member=%{Ldap-UserDn}))(&(objectClass=top)(uniquemember=%{Ldap-UserDn})))"

	# Here freeradius becomes the info at which attribute he should
	# take a look for the group membership
	# In AD it's called "memberOf", not "LDAP-Group"
	groupmembership_attribute = memberOf

	# For debugging purposes, set it to 0xFFFF, default is 0x0000
	ldap_debug = 0xFFFF
	
	# We want to use secure transactions
	# I don't know, if we need to configure openssl for this feature
	start_tls = yes

	# default, unchanged
	dictionary_mapping = ${raddbdir}/ldap.attrmap

	# we have many users, so I increased this value
	# match it to your situation
	ldap_connections_number = 50
	
	# I had to increase the timeout about a multiple of 10
	# Our AD servers aren't very fast, but perhaps it's normal
	# If you run in problems, increase it
	timeout = 40
	timelimit = 30
	net_timeout = 10

	# Our AD is very huge, the servers are very slow
	# I encoutered problems by checking the groupmembership when users
 	# are member in many groups
	# take a look at the "filter" statement
	# additionally I increased again the timeout values
	# Now everything runs fine
	# timeout = 400
	# timelimit = 300
	# net_timeout = 100
}
-----------end file-----------

_/etc/raddb/users_
Next, you have to edit the /etc/raddb/users file. Freeradius will go through this file to check what to do with special users or requests. 

All entries have the following syntax. 

<username> 	<items to check>
	[<item to do>,]
	<item to do>

If the request from the client matches the first line, radius will do the following line(s). At the moment, I told freeradius to recognize the groups and did not configure with the right priv-level. 

My file looks like this:
-----------file-----------
DEFAULT     Ldap-Group == "Cisco_RO", NAS-Identifier =~ "^as5300"
		Auth-Type := LDAP,
		Service-Type = Login,
		Cisco-AVPair = "shell:priv-lvl=7"

DEFAULT     Ldap-Group == "Cisco_RW", NAS-IP-Address =~ "^192\.168\.21\.[0-9]+$"
		Auth-Type := LDAP,
		Service-Type = Login,
		Cisco-AVPair = "shell:priv-lvl=15"

DEFAULT 	Auth-Type := Reject
		Reply-Message = "Access denied." 
-----------end file-----------

"DEFAULT" matches all users. First match counts. In my example, all users are checked if they are member of the group "Cisco-RO". If so, other items will not be checked (you have to add "PassTrough = yes"). In the above example it's not a good idea to put members of "Cisco_RW" also in the group "Cisco_RO". In this case, radius will never come to "Cisco_RW". Again, first match.

First entry only matches NAS-devices which begin with as5300, in the second only devices from 192.168.21.0 up to 192.168.21.9. If you need assistance in the regular expressions, take a look at "man grep".


_/etc/raddb/clients.conf_
-----------file-----------
client 127.0.0.1 {
        secret          = default_secret
        shortname       = localhost
}

client 192.168.0.0/16 {
        secret 		= secret
        shortname 	= network
 }
-----------end file-----------

All clients authenticating against freeradius need to have the (shared) secret as the server. You have to configure your clients.

*Test it*
Now start your freeradius server with the appropriate command and start some tests. Use user from your AD. Pay attention on your groups.
-----------shell-----------
radtest cv 'ADpassword' localhost 0 default_secret
Sending Access-Request of id 227 to 127.0.0.1:1812
        User-Name = "cv"
        User-Password = "ADpassword"
        NAS-IP-Address = ldaptest
        NAS-Port = 0
rad_recv: Access-Accept packet from host 127.0.0.1:1812, id=227, length=51
        Service-Type = Login-User
        Cisco-AVPair = "shell:priv-lvl=15"
-----------end shell-----------


When you see the "Access-Accept", everything is fine :)

If not, you have to start your server with the "-X" parameter for debugging. You can change the call in the script under /etc/init.d. Perhaps it's a good idea to enable the ldap-debug in the radiusd.conf.

*failover*
If you need some explanation, take a look at the "configurable_failover" doc.

You have to enable two ldap modules:
	ldap ldap1 {
		server = "server1..."
		[...]
	}
	ldap ldap2 {
		server = "server2..."
		[...]
	}
instantiate {
	[...]
	ldap1
	ldap2
}
authorize {
	[...]
	#ldap
	redundant {
		ldap1 {
			fail = 1
			ok = return
		}
		ldap2 {
			fail = 1
			ok = return
		}
	}
authenticate {
	[...]
	Auth-Type LDAP {
		redundant {
			ldap1 {
				fail = 1
				ok = return
			}
			ldap2 {
				fail = 1
				ok = return
			}
		}
	}

This config runs fine, even with ldap groups as long as the second server is reachable. If it fails, the request will fail. So it's not that what we want. You have to use the following workaround:

In your users file you have to add an prefix for each ldap group like this:

DEFAULT		ldap1-Ldap-Group == "cisco-users"
		[...]

DEFAULT		ldap2-Ldap-Group == "cisco-users"
		[...]


In this case everything works fine. But you have to add two entries in the users.




More information about the Freeradius-Users mailing list