I\'m trying to set up a radius server using a rest backend for authentication. I used the following project as example: https://github.com/fgsants/REST-API-FreeRADIUS
<I have spent an enormous amount of time, trying to figure out, how is this thing suppose to work, as I am a newbie, regarding freeradius. I am also using the nodejs rest api and was able to succeed with the second approach, but in order to do it, I had to add some more bits, inside the inner-tunnel file as follows:
authorize {
update control {
MS-CHAP-Use-NTLM-Auth := No
}
rest
inner-eap
}
authenticate {
inner-eap
Auth-Type PAP {
pap
}
Auth-Type MS-CHAP {
mschap
}
}
FreeRADIUS modules have multiple 'methods', each method handles a different aspect of processing RADIUS packets.
The 'authorize' method is called when the module is listed in the authorize section. The authorize method is used to gather additional information to authorize the user.
The 'authenticate' method is called when a module is listed in the authenticate section, and a module in the authorize section specified that this particular module be used to authenticate the user by setting control:Auth-Type = <module>
.
There are generally two ways you can authenticate a user:
rest.authenticate
).rest.authorize
).You need to decide which of these approaches you're going to use.
If it's approach 1, then the user needs to send their password as plaintext so it can be submitted to the authentication server.
If it's approach 2, then you need to retrieve a copy of the user's password in plaintext from another server.
There are advantages and disadvantages to both approaches, and which approach you choose affects which EAP (Extensible Authentication Protocol) methods are available for you to use.
In your example, you're using WPA/2-Enterprise, in which case the authentication framework running between the AP and the Wireless client will be 802.1X.
With 802.1X the AP and Wireless client exchange authentication packets over a protocol called EAPOL (EAP Over Lan). 802.1X and EAPOL allow the Wireless client to submit credentials to an Authentication Server (usually a RADIUS server), before the encryption keys are exchanged (WPA four-way handshake), and before the wireless client can exchange normal (non-EAPOL) packets with the AP (such as DHCP packets).
With wireless authentication, EAPOL and RADIUS serve mainly as transports for EAP, and its EAP that carries the user's credentials during the authentication attempt.
When the access point forwards EAP data in RADIUS packets it splits the EAP packets into 253-byte chunks and encapsulates those chunks in EAP-Message attributes.
When FreeRADIUS is performing the role of an Authentication Server, it needs to reassemble those 253-byte chunks and run the state machine of whichever EAP method it negotiates with the wireless client.
To simplify writing configurations that deal with EAP authentication, FreeRADIUS uses two virtual servers. The 'outer' server deals with the RADIUS portion of the authentication attempt, and the 'inner' server deals with the EAP portion of the authentication attempt.
Unless you're implementing complex policies the only module the outer server needs to call is 'eap'.
In your configuration remove everything from the authorize and authenticate sections leaving only the eap module:
authorize {
eap
}
authenticate {
eap
}
When the eap module is called in the authorize section, the eap module checks that one or more EAP-Message attributes are present in the request, and they are, it sets control:Auth-Type = EAP
, so that the module called in the authenticate section is also eap.
When the eap module is called in the authenticate section, the eap module concatenates all the EAP-Message attributes back into a single packet, and runs the EAP state machine, calling EAP submodules as appropriate to run the different EAP methods.
Which EAP method runs first is determined by default_eap_type
in raddb/mods-available/eap
.
If you're using approach 1 (user submitting plaintext credentials), you need to use an EAP method like EAP-TTLS, which will wrap the plaintext credentials in a TLS wrapper (to protect them from harvesting).
Set default_eap_type = ttls
if you want to use approach 1.
If you're using approach 2 (external server provides plaintext credentials), you can use a wider range of EAP methods. PEAP (Protected EAP) is the most widely implemented EAP method amongst consumer devices (phones, laptops, VoIP phones etc..). Like TTLS, PEAP uses a TLS wrapper to protect the credential exchange, but instead of sending the user's password in the clear uses MSCHAPv2 for credential exchange, which means the credentials are never sent over the wire in plaintext.
In truth, MSCHAPv2 only offers limited additional protection over TTLS as MSCHAPv2 is considered broken, but you may want to use PEAP if you have legacy clients running <= Windows 7, as EAP-TTLS support was only added in Windows 8.
Set default_eap_type = peap
if you want to use approach 2.
FreeRADIUS submodules for TLS based EAP methods such as TTLS and PEAP run a synthetic request (generated internally) through a separate 'inner' virtual server.
The purpose of this request is to represent the decrypted and decoded contents of the TLS wrapper and to make that content available to other modules (such as rest, ldap, pap etc...) in a standard form that they can interpret.
There's an example inner virtual server that is included in the default config called sites-available/inner-tunnel
. This virtual server is configured as the default in the default EAP module, and this is the one you should modify to set how the user's credentials are validated.
EAP-TTLS can actually run many different inner authentication methods, even another layer of EAP. This is because EAP-TTLS allows multiple attributes in the RADIUS attribute space to be sent within its TLS wrapper.
In general, however, most supplicants will default to running PAP as the inner authentication method, so when you see the synthetic request being sent to the inner virtual server, it'll likely only contain the User-Name
and User-Password
attributes.
Remove all existing text in the authorize and authenticate sections of sites-available/inner-tunnel
.
Either copy the text from your original example into the authorize and authenticate sections, or... I'm not sure you need to call the REST module twice (honestly it's been a long time since I worked on v3), you may want to try:
authorize {
if (&User-Password) {
update control {
Auth-Type = rest
}
}
}
authenticate {
rest {
update = 1
}
if (update) {
ok
}
}
With PEAP, the TLS wrapper contents represent another 'inner' EAP conversation. To process this conversation we need to first retrieve the user's password, and then call the inner-eap module.
Note: inner-eap is another instance of the EAP module, but with only EAP methods enabled that are appropriate to use inside another EAP conversation. inner-eap should be available in mods-available/eap_inner
, you may need to symlink this file from mods-available
to mods-enabled
.
Remove all existing text in the authorize and authenticate sections of sites-available/inner-tunnel
.
In the authorize section list the rest module, then the inner-eap module:
authorize {
rest
inner-eap
}
When the request is received by your API endpoint, you'll need to return a control:Cleartext-Password
attribute, with the user's cleartext password.
In the authenticate section list only the inner-eap module:
authenticate {
inner-eap
}