]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
doc: refactor header and intro for unlang splitting strings tutorial
authortharkadharshana <tharkadharshana@gmail.com>
Mon, 19 Jan 2026 10:38:56 +0000 (16:08 +0530)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 23 Jan 2026 23:18:10 +0000 (18:18 -0500)
doc: add common control attributes and formalize task description

doc: add unlang policy code and server integration instructions

doc: add verification and testing section with multiple scenarios

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

index 6df59c134caa9fdcab81a2f2d6cdf518497cc5b7..6d1b20fccda84a61b46be53a0819c3032c891056 100644 (file)
 = Splitting strings
 
-include::ROOT:partial$v3_warning.adoc[]
-
 *Goal:* Explore uses of regular expressions and subcapture groups
-
 *Time:* 10-20 minutes
 
-*File:*  
-
+*File:*
 - `etc/raddb/policy.d/*`
 
-*`man` page:* unlang
+*`man` page:* `unlang`
 
 *documentation page(s):*
 
 - xref:reference:unlang/condition/index.adoc[Conditions]
 - xref:reference:unlang/condition/regex.adoc[Regular expressions]
-- xref:reference:unlang/update.adoc[The Update Statement]
-
-include::partial$unlang_start.adoc[]
-
-include::partial$common_control_attrs_sidebar.adoc[]
-
-Regular expressions are an extremely powerful tool in the 'unlang' policy
-language.  They provide both validation capabilities, allowing users
-to check the format of incoming attributes, and substring extraction
-(via capture groups).
-
-If you've completed the xref:proxy.adoc[Proxy] exercise you'll have
-used the `suffix` module to split an incoming `User-Name` value into
-its components and setup the request for proxying.
-
-Create an unlang version of "suffix" that splits an incoming `User-Name` into
-two components on the "@" separator.
-
-The first component should be written to the `request.Stripped-User-Name`
-attribute and the second component should be written to the
-`control.Stripped-User-Domain` attribute.
-
-Use `bob@realm1.sh` and `bob@realm2.sh` to test your new policy to ensure
-it works as expected.
-
-If you've completed the xref:proxy.adoc[Proxy] tutorial and have test
-realms setup, modify the policy code you have just written to proxy
-the request to the realm specified in the `User-Name` attribute.
+- xref:reference:unlang/index.adoc[Unlang]
+
+
+For this tutorial you should start with an empty authorization section:
+
+[source,unlang]
+----
+recv Access-Request {
+    # We'll include our policy in here
+}
+----
+
+in the virtual server you’re using to process requests.
+
+== Common control attributes
+Attributes in the control list can control the behaviour of the server.
+Commonly used control attributes are:
+
+* `control.Auth-Type` specifies the `authenticate <name> {}` section to run
+
+Regular expressions are an extremely powerful tool in the 'unlang' policy language.
+They provide both validation capabilities, allowing users to check the format of
+incoming attributes, and substring extraction (via capture groups).
+
+If you’ve completed the xref:proxy.adoc[Proxy] exercise you’ll have used the `suffix` module to
+split an incoming `User-Name` value into its components and setup the request for
+proxying.
+
+**Task:**
+Create an unlang version of "suffix" that splits an incoming `User-Name` into two
+components on the "@" separator.
+
+The first component should be written to the `request.Stripped-User-Name` attribute
+and the second component should be written to the `control.Stripped-User-Domain`
+attribute.
+
+Use `bob@realm1.com` and `bob@realm2.com` to test your new policy to ensure it works
+as expected.
+
+If you’ve completed the xref:proxy.adoc[Proxy] tutorial and have test realms setup, modify the
+policy code you have just written to proxy the request to the realm specified
+in the `User-Name` attribute.
+
+== Step 1 – Basic splitting policy
+
+[source,unlang]
+.FILE: /etc/raddb/policy.d/realm-split
+----
+realm-split {
+    # Check if User-Name exists and contains an "@" symbol
+    if (request.User-Name =~ /^([^@]+)@(.+)$/) {
+        # First capture group - username part (before @)
+        request.Stripped-User-Name := %regex.match(1)
+
+        # 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}"
+        }
+    }
+}
+----
+
+Add the above created policy into `raddb/sites-available/default`:
+
+[source,unlang]
+----
+server default {
+    recv Access-Request {
+        realm_split
+        files
+    }
+}
+----
+
+Also make sure our testing user "bob" exists in `raddb/mods-config/files/authorize`:
+
+[source,unlang]
+----
+bob     Password.Cleartext := "hello"
+----
+Then execute the following commands to test this configuration:
+
+[source]
+----
+echo 'User-Name = "bob@realm1.com", User-Password = "hello"' | radclient -x 127.0.0.1 auth testing123
+----
+
+**Expected debug (relevant lines):**
+
+----
+(0)    recv Access-Request {
+(0)      policy realm-split {
+(0)        if (request.User-Name =~ /^([^@]+)@(.+)$/)  {
+(0)          | =~
+(0)              | request.User-Name
+(0)                | %{request.User-Name}
+(0)                | --> bob@realm1.com
+(0)          | ({bob@realm1.com} =~ (null))
+(0)          | --> true
+(0)          | %regex.match(1)
+(0)            | %regex.match(1)
+(0)            | regex.match
+(0)            | %regex.match({1})
+(0)            | --> bob
+(0)          request.Stripped-User-Name := "bob"
+(0)          | %regex.match(2)
+(0)            | %regex.match(2)
+(0)            | regex.match
+(0)            | %regex.match({2})
+(0)            | --> realm1.com
+(0)          control.Stripped-User-Domain := "realm1.com"
+(0)              | %{request.Stripped-User-Name}
+(0)              | --> bob
+(0)              | %{control.Stripped-User-Domain}
+(0)              | --> realm1.com
+(0)          reply += {
+(0)            Reply-Message = "User: bob"
+(0)            Reply-Message = "Domain: realm1.com"
+(0)          }
+(0)        } # if (request.User-Name =~ /^([^@]+)@(.+)$/)  (...)
+(0)      } # policy realm-split (...)
+----
+
+**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: realm1.com"
+----
+
+If you want to test above scenario with different username "alice" you need to add that user into `mods-config/files/authorize`, after that you can test that
+user using the command below:
+
+[source]
+----
+echo 'User-Name = "alice@abc.com", User-Password = "hello"' | radclient -x 127.0.0.1 auth testing123
+----
+
+**Expected output:**
+
+----
+        Reply-Message = "User: alice"
+        Reply-Message = "Domain: abc.com"
+----
+
+If we want to test the above scenario with a different domain, such as `bob@realm2.com`, use the following command:
+
+[source]
+----
+echo 'User-Name = "bob@realm2.com", User-Password = "hello"' | radclient -x 127.0.0.1 auth testing123
+----
+
+**Expected output:**
+
+----
+        Reply-Message = "User: bob"
+        Reply-Message = "Domain: realm2.com"
+----
 
 == Questions