Sample code for external program w/ EAP?
Hi all. I hate to be a pest...but I cannot find anything really on what I'm trying to do. My setup is a wireless AP (running OpenWRT) using WPA2 - 802.1x authentication, to Freeradius. I'm trying to use a Python program as an "external authenticator", so I can check various things with the username and password in my already existing authentication schemes. I thought this would be easy...I was wrong. Through some trial and error, I've determined that the Python app needs to return "Cleartext-Password" with "some value"...that value is unclear to me since I've returned anything and it takes it. I've tried to mimic the setup at http://wiki.freeradius.org/Rlm_perl , but using Python instead of perl. My question to everyone is this: Is there an example program, in Python or perl, that is complete and works somewhere? Everything I've seen just says things like "your code here", and never specifies what the returns need to be formatted like and/or include for EAP. I had been assuming that I just simply had to return a simple "OK" or "FAIL", but that's clearly not right. I'm including some testing below for those who want to see more of what I'm doing. Thanks, --Brian When I run radtest now, here's what I get (showing that there's an EAP error, but it does give an Access-Accept): [root@xxxx: /usr/local/etc/raddb]#radtest -t eap-md5 user pass 127.0.0.1 0 testing123 Sending Access-Request packet to host 127.0.0.1 port 1812, id=49, length=0 User-Name = "user" User-Password = "pass" NAS-IP-Address = 192.168.12.18 NAS-Port = 0 EAP-Code = Response EAP-Type-Identity = "user" Message-Authenticator = 0x00 EAP-Message = 0x023000090175736572 rlm_eap: EAP-Message not found Received Access-Accept packet from host 127.0.0.1 port 1812, id=49, length=20 Here's the function that's running in my python program: def authorize(p): print "*** authorize ***" print radiusd.radlog(radiusd.L_INFO, '*** radlog call in authorize ***') print print p. sys.stdout.flush() return (radiusd.RLM_MODULE_OK, (('Cleartext-Password','pass'),), (('Auth-Type', 'python'),)) Here's the output from radius -X : rad_recv: Access-Request packet from host 127.0.0.1 port 49493, id=49, length=85 User-Name = "user" User-Password = "pass" NAS-IP-Address = 192.168.12.18 NAS-Port = 0 Message-Authenticator = 0x4b08938d78fe92d1f7a6d60152c9fbc0 EAP-Message = 0x023000090175736572 # Executing section authorize from file /usr/local/etc/raddb/sites-enabled/default +- entering group authorize {...} ++[preprocess] returns ok ++[chap] returns noop ++[mschap] returns noop ++[digest] returns noop [suffix] No '@' in User-Name = "user", looking up realm NULL [suffix] No such realm "NULL" ++[suffix] returns noop [eap] EAP packet type response id 48 length 9 [eap] No EAP Start, assuming it's an on-going EAP conversation ++[eap] returns updated [files] users: Matched entry DEFAULT at line 1 ++[files] returns ok *** authorize *** *** radlog call in authorize *** (('User-Name', '"user"'), ('User-Password', '"pass"'), ('NAS-IP-Address', '192.168.12.18'), ('NAS-Port', '0'), ('Message-Authenticator', '0x4b08938d78fe92d1f7a6d60152c9fbc0'), ('EAP-Message', '0x023000090175736572'), ('EAP-Type', 'Identity')) rlm_python:authorize: 'Cleartext-Password' = 'pass' rlm_python:authorize: 'Auth-Type' = 'python' ++[python] returns ok ++[expiration] returns noop ++[logintime] returns noop [pap] WARNING! No "known good" password found for the user. Authentication may fail because of this. ++[pap] returns noop Found Auth-Type = EAP Found Auth-Type = Python Warning: Found 2 auth-types on request for user 'user' # Executing group from file /usr/local/etc/raddb/sites-enabled/default +- entering group Python {...} *** authenticate *** *** radlog call in authenticate *** (('User-Name', '"user"'), ('User-Password', '"pass"'), ('NAS-IP-Address', '192.168.12.18'), ('NAS-Port', '0'), ('Message-Authenticator', '0x4b08938d78fe92d1f7a6d60152c9fbc0'), ('EAP-Message', '0x023000090175736572'), ('EAP-Type', 'Identity')) ++[python] returns ok # Executing section post-auth from file /usr/local/etc/raddb/sites-enabled/default +- entering group post-auth {...} ++[exec] returns noop Sending Access-Accept of id 49 to 127.0.0.1 port 49493 Finished request 0. Going to the next request Waking up in 4.9 seconds. Cleaning up request 0 ID 49 with timestamp +5 Ready to process requests. When I try to connect from my iPad, it just hangs...probably because it's waiting for that "EAP-Message" that radtest was complaining about.
I should also mention I'd be perfectly happy with using an "exec-program-wait" to authenticate the user since our volume is not that high, but I cannot find an example of how to do that either. Thanks, --Brian From: freeradius-users-bounces+bmccann=andmore.com@lists.freeradius.org [mailto:freeradius-users-bounces+bmccann=andmore.com@lists.freeradius.org] On Behalf Of McCann, Brian Sent: Friday, January 28, 2011 10:54 AM To: freeradius-users@lists.freeradius.org Subject: Sample code for external program w/ EAP? Hi all. I hate to be a pest...but I cannot find anything really on what I'm trying to do. My setup is a wireless AP (running OpenWRT) using WPA2 - 802.1x authentication, to Freeradius. I'm trying to use a Python program as an "external authenticator", so I can check various things with the username and password in my already existing authentication schemes. I thought this would be easy...I was wrong. Through some trial and error, I've determined that the Python app needs to return "Cleartext-Password" with "some value"...that value is unclear to me since I've returned anything and it takes it. I've tried to mimic the setup at http://wiki.freeradius.org/Rlm_perl , but using Python instead of perl. My question to everyone is this: Is there an example program, in Python or perl, that is complete and works somewhere? Everything I've seen just says things like "your code here", and never specifies what the returns need to be formatted like and/or include for EAP. I had been assuming that I just simply had to return a simple "OK" or "FAIL", but that's clearly not right. I'm including some testing below for those who want to see more of what I'm doing. Thanks, --Brian When I run radtest now, here's what I get (showing that there's an EAP error, but it does give an Access-Accept): [root@xxxx: /usr/local/etc/raddb]#radtest -t eap-md5 user pass 127.0.0.1 0 testing123 Sending Access-Request packet to host 127.0.0.1 port 1812, id=49, length=0 User-Name = "user" User-Password = "pass" NAS-IP-Address = 192.168.12.18 NAS-Port = 0 EAP-Code = Response EAP-Type-Identity = "user" Message-Authenticator = 0x00 EAP-Message = 0x023000090175736572 rlm_eap: EAP-Message not found Received Access-Accept packet from host 127.0.0.1 port 1812, id=49, length=20 Here's the function that's running in my python program: def authorize(p): print "*** authorize ***" print radiusd.radlog(radiusd.L_INFO, '*** radlog call in authorize ***') print print p. sys.stdout.flush() return (radiusd.RLM_MODULE_OK, (('Cleartext-Password','pass'),), (('Auth-Type', 'python'),)) Here's the output from radius -X : rad_recv: Access-Request packet from host 127.0.0.1 port 49493, id=49, length=85 User-Name = "user" User-Password = "pass" NAS-IP-Address = 192.168.12.18 NAS-Port = 0 Message-Authenticator = 0x4b08938d78fe92d1f7a6d60152c9fbc0 EAP-Message = 0x023000090175736572 # Executing section authorize from file /usr/local/etc/raddb/sites-enabled/default +- entering group authorize {...} ++[preprocess] returns ok ++[chap] returns noop ++[mschap] returns noop ++[digest] returns noop [suffix] No '@' in User-Name = "user", looking up realm NULL [suffix] No such realm "NULL" ++[suffix] returns noop [eap] EAP packet type response id 48 length 9 [eap] No EAP Start, assuming it's an on-going EAP conversation ++[eap] returns updated [files] users: Matched entry DEFAULT at line 1 ++[files] returns ok *** authorize *** *** radlog call in authorize *** (('User-Name', '"user"'), ('User-Password', '"pass"'), ('NAS-IP-Address', '192.168.12.18'), ('NAS-Port', '0'), ('Message-Authenticator', '0x4b08938d78fe92d1f7a6d60152c9fbc0'), ('EAP-Message', '0x023000090175736572'), ('EAP-Type', 'Identity')) rlm_python:authorize: 'Cleartext-Password' = 'pass' rlm_python:authorize: 'Auth-Type' = 'python' ++[python] returns ok ++[expiration] returns noop ++[logintime] returns noop [pap] WARNING! No "known good" password found for the user. Authentication may fail because of this. ++[pap] returns noop Found Auth-Type = EAP Found Auth-Type = Python Warning: Found 2 auth-types on request for user 'user' # Executing group from file /usr/local/etc/raddb/sites-enabled/default +- entering group Python {...} *** authenticate *** *** radlog call in authenticate *** (('User-Name', '"user"'), ('User-Password', '"pass"'), ('NAS-IP-Address', '192.168.12.18'), ('NAS-Port', '0'), ('Message-Authenticator', '0x4b08938d78fe92d1f7a6d60152c9fbc0'), ('EAP-Message', '0x023000090175736572'), ('EAP-Type', 'Identity')) ++[python] returns ok # Executing section post-auth from file /usr/local/etc/raddb/sites-enabled/default +- entering group post-auth {...} ++[exec] returns noop Sending Access-Accept of id 49 to 127.0.0.1 port 49493 Finished request 0. Going to the next request Waking up in 4.9 seconds. Cleaning up request 0 ID 49 with timestamp +5 Ready to process requests. When I try to connect from my iPad, it just hangs...probably because it's waiting for that "EAP-Message" that radtest was complaining about.
On 28/01/11 15:54, McCann, Brian wrote:
Hi all. I hate to be a pest…but I cannot find anything really on what I’m trying to do.
My setup is a wireless AP (running OpenWRT) using WPA2 – 802.1x authentication, to Freeradius.
I’m trying to use a Python program as an “external authenticator”, so I can check various things with the username and password in my already existing authentication schemes. I thought this would be easy…I was wrong. Through some trial and error, I’ve determined that the Python app needs to return “Cleartext-Password” with “some value”…that value is unclear to me since I’ve returned anything and it takes it.
Cleartext-Password needs to be added to the "config" items of the request. I haven't used rlm_python but I think that looks like this: reply_items = tuple() config_items = tuple( ('Cleartext-Password', 'password'), ('Auth-Type', 'python'), ) return (radiusd.RLM_MODULE_OK, reply_items, config_items) Your current code is returning it in the reply items I think. It's not clear to me that setting Auth-Type is what you want; it'll mean the Python module is then called for the authentication phase, which if you're doing EAP is probably not what you want? It should just be sufficient to return the cleartext-password in the config items, and let FreeRadius handle the auth.
McCann, Brian wrote:
Hi all. I hate to be a pest…but I cannot find anything really on what I’m trying to do.
You're trying to have another program authenticate the user. This means setting up that program as being responsible for the authentication.
I’m trying to use a Python program as an “external authenticator”, so I can check various things with the username and password in my already existing authentication schemes. I thought this would be easy…I was wrong. Through some trial and error, I’ve determined that the Python app needs to return “Cleartext-Password” with “some value”…that value is unclear to me since I’ve returned anything and it takes it.
No. If it's returning a Cleartext-Password, then you are *not* using the program as the authenticator.
My question to everyone is this: Is there an example program, in Python or perl, that is complete and works somewhere? Everything I’ve seen just says things like “your code here”, and never specifies what the returns need to be formatted like and/or include for EAP. I had been assuming that I just simply had to return a simple “OK” or “FAIL”, but that’s clearly not right.
It's right *if* you're running the Python module in the "authenticate" section. This usually means forcing Auth-Type, which is one of the few times where doing that is useful. My $0.02, however, is to say that this is a bad idea. You're nearly always better off letting the authentication server do the authentication. Alan DeKok.
First, that was enlightening because I think you hit on my (possible) confusion of "authenticate" versus "authorize". From my understanding, "authenticate" says 'user X' with 'password Y' is real. It will fail if the username or password is wrong. Authorize says 'user X' has permission to access 'resource Z'. Authorize happens after authenticate, and doesn't care about passwords/proof of identity...it just knows you are 'user X'. Now, here's my exact problem and explain "why" I need to authenticate (not authorize) in my external program (vs ntlm_auth, the users file, ldap, sql, etc). I have an XMLRPC-like server that is accessed over https, and takes a hash of the username and a hash of the password, and will return output granting or denying the user. Since freeradius doesn't know how to talk to the XMLRPC server, I need my external helper. Thanks, --Brian -----Original Message----- From: freeradius-users-bounces+bmccann=andmore.com@lists.freeradius.org [mailto:freeradius-users-bounces+bmccann=andmore.com@lists.freeradius.org] On Behalf Of Alan DeKok Sent: Friday, January 28, 2011 11:44 AM To: FreeRadius users mailing list Subject: Re: Sample code for external program w/ EAP? McCann, Brian wrote:
Hi all. I hate to be a pest…but I cannot find anything really on what I’m trying to do.
You're trying to have another program authenticate the user. This means setting up that program as being responsible for the authentication.
I’m trying to use a Python program as an “external authenticator”, so I can check various things with the username and password in my already existing authentication schemes. I thought this would be easy…I was wrong. Through some trial and error, I’ve determined that the Python app needs to return “Cleartext-Password” with “some value”…that value is unclear to me since I’ve returned anything and it takes it.
No. If it's returning a Cleartext-Password, then you are *not* using the program as the authenticator.
My question to everyone is this: Is there an example program, in Python or perl, that is complete and works somewhere? Everything I’ve seen just says things like “your code here”, and never specifies what the returns need to be formatted like and/or include for EAP. I had been assuming that I just simply had to return a simple “OK” or “FAIL”, but that’s clearly not right.
It's right *if* you're running the Python module in the "authenticate" section. This usually means forcing Auth-Type, which is one of the few times where doing that is useful. My $0.02, however, is to say that this is a bad idea. You're nearly always better off letting the authentication server do the authentication. Alan DeKok. - List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
On 01/28/2011 06:34 PM, McCann, Brian wrote:
Now, here's my exact problem and explain "why" I need to authenticate (not authorize) in my external program (vs ntlm_auth, the users file, ldap, sql, etc). I have an XMLRPC-like server that is accessed over https, and takes a hash of the username and a hash of the password, and will return output granting or denying the user. Since freeradius doesn't know how to talk to the XMLRPC server, I need my external helper.
Are you aware that this will severly limit your options with respect to EAP and windows clients? Only EAP-TTLS/PAP gives you the username & password. Windows clients only support EAP-TLS (no username/password) or EAP-PEAP/MS-CHAPv2 using the built-in supplicant. You will never see a password from a windows client; just an mschap challenge/response pair. Unless your XMLRPC handler can process those, you will not be able to authenticate windows clients without installing extra supplicant software. Anyway, you probably want to do something like this in /etc/raddb/sites-availble/inner-tunnel: authorize { ... pap } authenticate { Auth-Type PAP { python } } ...then write the "authenticate" handler of your python module to return the appropriate code.
participants (3)
-
Alan DeKok -
McCann, Brian -
Phil Mayers