]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
docs: improve unlang policies introduction and preparation section
authorTharka Karunanayake <tharkadharshana@gmail.com>
Tue, 20 Jan 2026 12:06:13 +0000 (17:36 +0530)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 23 Jan 2026 23:19:03 +0000 (18:19 -0500)
docs: provide concrete policy example referencing splitting strings

docs: define task to call realm-split policy

docs: add comprehensive testing steps

doc/antora/modules/tutorials/pages/unlang_policies.adoc

index d5f5602782f5cf6bc85f5ba3d4c44297ce17fc6f..0496726ed16b90c72aa38a071b1d2ee7f11bb9fb 100644 (file)
-= Unlang Policies
+= Policies
 
-*Goal:* Create and use policies for abstracting business logic
+*Goal:* Create and use policies to abstract and reuse business logic in FreeRADIUS.
 
 *Time:* 10-20 minutes
 
-*File:*
+*Files / Directories:*
 
-- `etc/raddb/policy.d/*`
+- `etc/raddb/policy.d/*`   (policy.d where we create and define policies)
+- `etc/raddb/sites-available/default`  (virtual server where we call the policy)
 
-*`man` page:* unlang
+== Preparation
 
-include::partial$unlang_start.adoc[]
+Look through the existing files in `policy.d/` and review
+other documentation sections (especially the unlang reference,
+conditions, and regular expressions) to become familiar with:
 
-Look through the existing files in `etc/raddb/policy.d/*` and the rest
-of the documentation to get a feel for the unlang syntax and the tasks
-that policies can be used for.
+- Policy syntax
+- Attribute references (`request.`, `control.`, `reply.`, etc.)
+- Regular expression matching in `if` conditions
+- Common update operators (`:=`, `+=`, etc.)
 
-The basic structure of a policy is the policy name then a set of curly
-braces containing the body of the policy
+Policies are named blocks of unlang code that can be called almost
+anywhere a module can be called.
 
-------------------------------------------------
-a_policy {
-       if (User-Name =~ /@([\w.+])/) {
-               reply.Reply-Message := "Hello remote %{User-Name}"
-       }
+Basic structure of a policy:
+
+[source,text]
+----
+policy_name {
+    # unlang statements here
 }
-------------------------------------------------
+----
+Example:
+
+You should have already created a policy named `realm-split` in the
+xref:unlang_splitting_strings.adoc[Splitting Strings] tutorial.
+
+File: etc/raddb/policy.d/realm-split
+
+[source,text]
+----
+realm-split {
+    # Check if User-Name exists and contains an "@" symbol
+    if (request.User-Name =~ /^([^@]+)@(.+)$/) {
 
-Policies defined within `etc/raddb/policy.d/*` can be called from
-anywhere in the server where modules can be called.
+        # First capture group - username part (before @)
+        request.Stripped-User-Name := %regex.match(1)
 
-------------------------------------------------
-authorize {
-       ...
-       a_policy
-       ...
+        # Second capture group - domain/realm part (after @)
+        control.Stripped-User-Domain := %regex.match(2)
+
+        # Add reply attributes to validate the split worked correctly
+        # Using Reply-Message to show both values (visible in reply)
+        reply += {
+            Reply-Message = "User: %{request.Stripped-User-Name}"
+            Reply-Message = "Domain: %{control.Stripped-User-Domain}"
+        }
+    }
 }
-------------------------------------------------
+----
+
+Task: Call this policy at the very beginning of the `recv Access-Request`
+section in the default virtual server.
+
+Open the file:
+
+[source]
+----
+$ vi sites-available/default
+----
+
+Add the policy call near the top of the authorize section:
+
+[source,text]
+----
+recv Access-Request {
+    realm-split
+    # ... rest of the section (chap, mschap, digest, files, etc.) ...
+}
+----
+
+Placing it early ensures the User-Name is stripped before any local
+authorization modules (like files, sql, ldap, etc.) access it.
+
+== Testing
+
+Make sure the testing user "bob" exists in `mods-config/files/authorize`:
+
+Run the server in debug mode:
 
-Create a policy `proxy_to_realm` that forwards the incoming request
-to to a remote realm if the `User-Name` attribute ends in `@<remote realm>`.
+[source]
+----
+$ radiusd -X
+----
 
-The contents of this policy should be identical to the the 'unlang'
-code written for the xref:unlang_splitting_strings.adoc[Splitting Strings]
-tutorial.
+Send an Access-Request with User-Name: bob@example.com
 
-Call this policy at the start of the `authorize {}` section of the
-`etc/raddb/sites-available/default` virtual server.
+[source,text]
+----
+echo 'User-Name = "bob@example.com", User-Password = "hello"' | radclient -x 127.0.0.1 auth testing123
+----
 
-All the information you need to create this policy is contained within
-documentation pages and the examples in this exercise.
+**Expected output:**
+----
+Received Access-Accept Id 246 from 127.0.0.1:1812 to 0.0.0.0:56242 via lo length 74
+        Message-Authenticator = 0x1a82a50a6973affe690efe4146e6581e
+        Reply-Message = "User: bob"
+        Reply-Message = "Domain: example.com"
+        User-Name = "bob"
+----
 
 == Questions