This example shows how to integrate RADIUS authentication into a BAS web application by building a small Lua RADIUS client and wiring it into the application's startup script. It is based on the authentication/root example, with the authentication callback replaced by a RADIUS-backed implementation.
RADIUS is a lightweight UDP-based protocol commonly used for centralized authentication, authorization, and accounting. In this example, the BAS application acts as the RADIUS client and delegates username/password validation to a RADIUS server.
When a user logs in, the application sends a RADIUS Access-Request packet and then waits for one of the standard outcomes:
Access-AcceptAccess-RejectAccess-Challenge(not used by this demo)
www/.preload- Configures the RADIUS client, creates the BAS authenticator, and applies it to the application directory.www/.lua/radius.lua- Lua RADIUS client module.www/index.lsp- Protected landing page shown after a successful login.www/.login/form.lspandwww/.login/failed.lsp- Form-based login UI and failure page.www/public/- Public static assets for the login flow.
To test locally, one simple option is FreeRADIUS on Linux or WSL:
- Install FreeRADIUS:
sudo apt update
sudo apt install freeradius- Add a test user to
/etc/freeradius/3.0/users:
testuser Cleartext-Password := "testpass"
- Allow the BAS client to talk to FreeRADIUS by adding this block to
/etc/freeradius/3.0/clients.conf:
client localhost {
ipaddr = 127.0.0.1
secret = myradiussecret
}- Start FreeRADIUS in debug mode:
sudo freeradius -X- Start the BAS example:
cd LSP-Examples/RADIUS
mako -l::wwwFor more detail on starting the Mako Server, see the command line video tutorial and the command line options documentation.
Then open http://localhost and log in with:
- Username:
testuser - Password:
testpass
HTTP Basic authentication is also supported. You can test it with:
curl -i -u "testuser:testpass" http://localhostwww/.preload creates a RADIUS client with:
local rad = require"radius".create("127.0.0.1", 1812, "myradiussecret")The authenticator's password callback forwards the submitted username and password to rad:login(...). If the RADIUS server returns Access-Accept, the BAS authenticator treats the login as successful; otherwise the login fails and the normal BAS response handler sends the user to the failure flow.
Inside www/.lua/radius.lua, the module:
- builds the RADIUS Access-Request packet
- obfuscates the password according to the RADIUS protocol
- sends the packet over UDP
- waits for the response
- validates the response authenticator before accepting the result
This function creates the RADIUS client instance. The parameters are:
radiusServerIP- IP address of the RADIUS serverradiusServerPort- UDP port, normally1812sharedSecret- pre-shared secret configured on both client and server
The returned object provides rad:login(username, password), which performs a blocking authentication round trip and returns either true or false, err.
rad:login(...) sends one Access-Request packet to the configured server and then waits for the reply. In this example, the method:
- builds the
User-NameandUser-PasswordAVPs - encodes the password using the MD5-based scheme defined by RFC 2865
- sends the packet over UDP
- waits for the response
- accepts the login only when the response code and authenticator both validate
That makes the BAS side a thin client for the centralized RADIUS service rather than a separate password database.
The .preload file does five important things:
- loads the custom Lua RADIUS client
- creates the BAS
authusercallback around it - configures the login-response flow for form-based login
- creates the BAS authenticator
- applies the authenticator to the application directory with
dir:setauth()
- The shared secret in
www/.preloadmust match thesecretconfigured in FreeRADIUS. - This example supports form-based and basic-style flows, but digest authentication is not supported by the RADIUS callback setup used here.
- The current Lua RADIUS module logs credentials through
trace(...), which is a security issue in real deployments. I did not change the code, but you should remove that logging before using the module outside a demo environment. - This example is easiest to understand if you first review the generic authentication examples, because the BAS authenticator flow is the same and only the password backend changes.
- The demo server settings are intentionally visible in
.preloadso you can quickly point the example at a different RADIUS server during testing.