Editing Attributes
Goal: To explore uses of editing attributes in the policy language
Time: 10-25 minutes
File:
-
sites-available/default
Documentation pages:
For this tutorial, you should start with an empty processing
section (recv Access-Request { … }) in the virtual server that you are
using to process requests.
Attributes in the control list can control the behaviour of the server.
For example:
-
Reply.Framed-IP-Address
-
Control.Password.Cleartext
Please refer to attribute lists for more information
Unlang update blocks are used to update one or attributes in one
of the server’s attribute lists.
In previous tutorials, we’ve used the files module, and the authorize
methods of authentication modules such as pap and chap to alter how
the server processes requests by setting an Auth-Type value.
Here, we will emulate that behaviour using the policy language.
-
Create a condition (condition 1) to execute policy code if the
User-Namein the request is 'bob'. -
Within that condition block, set the control attribute
Password.Cleartextto be 'hello', and instruct the server to run theauthenticate { … }subsection forpap.
Condition 1
For testing purposes, edit the following file:
$ vi sites-enabled/default
server default {
recv Access-Request {
# Condition 1
if (User-Name == "bob") {
Control.Password.Cleartext := "hello"
}
}
}
We have defined the cleartext password for the user bob here,
instead of defining it in mods-config/files/authorize, as
usual.
Execute the following command to test this configuration:
echo -e 'User-Name = "bob",
User-Password = "hello"' | radclient -x 127.0.0.1 auth testing123
After executing, verify that you see an Access-Accept returned despite
the files module not being called.
Debug Log Response
(0) Running 'recv Access-Request' from file /etc/raddb/sites-enabled/default
(0) recv Access-Request {
(0) if ( User-Name == "bob" ) {
(0) | ==
(0) | User-Name
(0) | %{User-Name}
(0) | --> bob
(0) | ({bob} == {bob})
(0) | --> true
(0) Control.Password.Cleartext := "hello"
(0) }
Server Response
Sent Access-Request Id 84 from 0.0.0.0:54238 to 127.0.0.1:1812 length 61
Message-Authenticator = 0x
User-Name = "bob"
User-Password = "hello"
Received Access-Accept Id 84 from 127.0.0.1:1812 to 0.0.0.0:54238 via lo length 43
Message-Authenticator = 0x6bdd99181d25a5c61b7577815379d877
User-Name = "bob"
Using additional conditions and update blocks, emulate the logic implemented using the files module in the Matching Users exercise.
-
If an incoming request contains a
User-Nameattribute with the value 'bob', and contains an attributeFramed-Protocolwith valuePPP(condition 2), reply with aFramed-IP-Addressattribute with the value192.168.10.12.
Condition 2
For testing purposes, edit the following file:
$ vi sites-enabled/default
server default {
recv Access-Request {
# Condition 1
if ( User-Name == "bob" ) {
Control.Password.Cleartext := "hello"
# Condition 2
if (Framed-Protocol == ::PPP) {
Reply.Framed-IP-Address := "192.168.10.12"
}
}
}
}
Execute the following command to test this configuration:
echo -e 'User-Name = "bob",
User-Password = "hello",
Framed-Protocol = "PPP"' | radclient -x 127.0.0.1 auth testing123
After executing, verify that you see an Access-Accept returned despite
the files module not being called.
Debug Log Response
(0) Running 'recv Access-Request' from file /etc/raddb/sites-enabled/default
(0) recv Access-Request {
(0) if ( User-Name == "bob" ) {
(0) | ==
(0) | User-Name
(0) | %{User-Name}
(0) | --> bob
(0) | ({bob} == {bob})
(0) | --> true
(0) Control.Password.Cleartext := "hello"
(0) if (Framed-Protocol == :PPP ) {
(0) | ==
(0) | Framed-Protocol
(0) | %{Framed-Protocol}
(0) | --> PPP
(0) | ({PPP} == {PPP})
(0) | --> true
(0) Reply.Framed-IP-Address := 192.168.10.12
(0) }
Server Response
Sent Access-Request Id 237 from 0.0.0.0:53537 to 127.0.0.1:1812 length 67
Message-Authenticator = 0x
User-Name = "bob"
User-Password = "hello"
Framed-Protocol = ::PPP
Received Access-Accept Id 237 from 127.0.0.1:1812 to 0.0.0.0:53537 via lo length 49
Message-Authenticator = 0xcaf8041bd61de3debf77bb7d1fbcddd9
Framed-IP-Address = 192.168.10.12
User-Name = "bob"
-
If an incoming request contains a
Service-Typeattribute with a value ofFramed-User(condition 3), reply with aFramed-Routeattribute assigning a default route of192.168.10.1(0.0.0.0/0 192.168.10.1 1) and aFramed-IP-Netmaskattribute with a value of255.255.255.0.
Condition 3
For testing purposes, edit the following file:
$ vi sites-enabled/default
server default {
recv Access-Request {
# Condition 1
if (User-Name == "bob") {
Control.Password.Cleartext := "hello"
if (Framed-Protocol == :PPP) {
Reply.Framed-IP-Address := "192.168.10.12"
}
if (Service-Type == ::Framed-User) {
Reply.Framed-Route := "0.0.0.0/0 192.168.10.1 1"
Reply.Framed-IP-Netmask := 255.255.255.0
}
}
}
}
Execute the following command to test this configuration:
echo 'User-Name = "bob",
User-Password = "hello",
Framed-Protocol = "PPP",
Service-Type = "Framed-User"' | radclient -x 127.0.0.1 auth testing123
Debug Log Response
(2) Running 'recv Access-Request' from file /etc/raddb/sites-enabled/default
(2) recv Access-Request {
(2) if ( User-Name == "bob" ) {
(2) | ==
(2) | User-Name
(2) | %{User-Name}
(2) | --> bob
(2) | ({bob} == {bob})
(2) | --> true
(2) Control.Password.Cleartext := "hello"
(2) if (Framed-Protocol == ::PPP ) {
(2) | ==
(2) | Framed-Protocol
(2) | %{Framed-Protocol}
(2) | --> PPP
(2) | ({PPP} == {PPP})
(2) | --> true
(2) Reply.Framed-IP-Address := 192.168.10.12
(2) } # if (Framed-Protocol == "PPP" ) (...)
(2) if ( Service-Type == "Framed-User" ) {
(2) | ==
(2) | Service-Type
(2) | %{Service-Type}
(2) | --> Framed-User
(2) | ({Framed-User} == {Framed-User})
(2) | --> true
(2) Reply.Framed-Route := "0.0.0.0/0 192.168.10.1 1"
(2) Reply.Framed-IP-Netmask := 255.255.255.0
(2) }
Server Response
Sent Access-Request Id 237 from 0.0.0.0:49684 to 127.0.0.1:1812 length 73
Message-Authenticator = 0x
User-Name = "bob"
User-Password = "hello"
Framed-Protocol = ::PPP
Service-Type = ::Framed-User
Received Access-Accept Id 237 from 127.0.0.1:1812 to 0.0.0.0:49684 via lo length 81
Message-Authenticator = 0x47734ce6231d0376d41ec238771b94b7
Framed-IP-Address = 192.168.10.12
Framed-Route = "0.0.0.0/0 192.168.10.1 1"
Framed-IP-Netmask = 255.255.255.0
User-Name = "bob"
Again test the server with username "bob" and password "hello". Use the debug output of the server to see which unlang conditions evaluated to true.
Perform other authentication tests, adding the appropriate attributes to the test requests to exercise the different conditions. If you already have test packets from the Matching Users exercises, you may use those, otherwise continue until you have packets that will match:
Conditions 1 and 2, but not 3
Execute the following command to test this configuration:
echo "User-Name = bob
User-Password = hello
Framed-Protocol = PPP" | radclient -x 127.0.0.1 auth testing123
Conditions 1 and 3, but not 2
Execute the following command to test this configuration:
echo "User-Name = bob
User-Password = hello
Service-Type = Framed-User" | radclient -x 127.0.0.1 auth testing123
Conditions 1, 2, and 3
Execute the following command to test this configuration:
echo "User-Name = bob
User-Password = hello
Framed-Protocol = PPP
Service-Type = Framed-User" | radclient -x 127.0.0.1 auth testing123
Response
(2) Sending Access-Accept ID 153 from 0.0.0.0/0:1812 to 127.0.0.1:41313 length 81 via socket radius_udp server * port 1812 (2) Framed-IP-Address = 192.168.10.12 (2) Framed-Route = "0.0.0.0/0 192.168.10.1 1" (2) Framed-IP-Netmask = 255.255.255.0 (2) Packet-Type = ::Access-Accept (2) User-Name = "bob" (2) Finished request
Questions
-
What are the advantages of unlang over the files module when creating policies?
-
What are the advantages of the files modules over unlang? Are there any situations where you think the files module might be better suited to a task than unlang?
-
Can you think of any efficiencies the users module might have over multiple conditions, where policies are being assigned to many different users?