diff -Naur freeradius-server-2.2.0-orig/doc/cui_howto.txt freeradius-server-2.2.0/doc/cui_howto.txt --- freeradius-server-2.2.0-orig/doc/cui_howto.txt 1970-01-01 01:00:00.000000000 +0100 +++ freeradius-server-2.2.0/doc/cui_howto.txt 2012-09-13 10:57:56.645722777 +0200 @@ -0,0 +1,78 @@ +Chargeable-User-Identity (CUI) support. + +1. OVERVIEW + +This extension introduces support for Chargeable-User-Identity (CUI) attribute +as defined in RFC 4372. + +The CUI attribute is meant to support roaming scenarios where +the user is accessing the network at one location (Service Provider - SP) +while authenticated by a RADIUS server at another institution (Identity +Provider - IdP). CUI provides means for the SP to request the IdP +to return a unique, persistent, opaque user identifier. + +As defined in RFC 4372, CUI request is sent as a NULL value (single +zero byte) of CUI attribute inside the Access-Request packet. +CUI response should be sent as the CUI value inside the Access-Accept. + +This extension has the following functionality: + +The SP side (*requesting* CUI): + - add the CUI NULL attribute to Access-Request proxied from + the local NAS to the IdP + - receive the CUI value from the IdP and store it in the local + database + - update Accounting-Request packets sent by NAS by adding + the appropriate CUI attribute (unless the attibute is + already present). + +The IdP side (*returning* CUI): + - respond to the CUI request by generating the CUI value. + The value is created as the md5 hash if a configurable local + salt and the User-Name attribute value. + +While CUI support has been added for roaming it is also useful for local +accounting. + +2. INSTALLATION + +The CUI *requesting* and CUI *returning* sides are implemented and +described separately. Most likely you want to run both, so just follow +the instructions of both sections. + +2.1 *requesting* CUI + + - Setup a MySQL database by creating (or using) a database of your + choice and create an additional table cui. The schema is located + in ${raddbdir}/sql/mysql/cui.sql. + + - Enter the necessary details into ${raddbdir}/modules/cui. + Things you need to modify are: + server - typically this will be localhost; + login - mysql user allowed to modify the tables + password - password for this user + radius_db - database name you wish to use + + - Modify the the main configuration file + "${raddbdir}/sites-availabe/default". + Search for CUI. There are four sections where CUI is mentioned. + Follow the instructions for *requesting* the CUI. + +2.2 *returning* CUI + + - Modify the the main configuration file + "${raddbdir}/sites-available/default". + Search for CUI. There are four sections where CUI is mentioned. + Follow the instructions for *returning* the CUI. + The cui_hash_key is used to safeguard the CUI from dictionary + attacks and should be set to some "random" string. + + - Modify "${raddbdir}/sites-availabe/inner-tunnel" + Search for CUI. There is one section where CUI is mentioned. + Follow the instructions for *returning* the CUI. + +3. ACKNOWLEDGEMENTS + +Authors: Maja Gorecka-Wolniewicz , Alan DeKok + +Contributors: Stefan Winter, Tomasz Wolniewicz diff -Naur freeradius-server-2.2.0-orig/raddb/modules/cui freeradius-server-2.2.0/raddb/modules/cui --- freeradius-server-2.2.0-orig/raddb/modules/cui 2012-09-10 13:51:34.000000000 +0200 +++ freeradius-server-2.2.0/raddb/modules/cui 2012-09-13 10:58:19.975050772 +0200 @@ -21,5 +21,5 @@ connect_failure_retry_delay = 60 cui_table = "cui" sql_user_name = "%{User-Name}" -#$INCLUDE sql/${database}/cui.conf + $INCLUDE sql/${database}/cui.conf } diff -Naur freeradius-server-2.2.0-orig/raddb/policy.conf freeradius-server-2.2.0/raddb/policy.conf --- freeradius-server-2.2.0-orig/raddb/policy.conf 2012-09-10 13:51:34.000000000 +0200 +++ freeradius-server-2.2.0/raddb/policy.conf 2012-09-13 11:00:40.929563217 +0200 @@ -145,53 +145,80 @@ } } - # - # The following policies are for the Chargeable-User-Identity - # (CUI) configuration. + # + # The following policies are for the Operator-Name handling + # (RFC5580) + # + operator_name { + if (Packet-Type == Access-Request) { + update request { + Operator-Name := "%{config:sp_operator_name}" + Chargeable-User-Identity = '\\000' + } + } + } + + # + # The following policies are for the Chargeable-User-Identity + # (CUI) configuration. See doc/cui_howto.txt for more information. # # - # The client indicates it can do CUI by sending a CUI attribute - # containing one zero byte + # The client requests the CUI by sending a CUI attribute + # containing one zero byte. # - cui_authorize { - update request { - Chargeable-User-Identity:='\\000' + cui_pre-proxy { + if (Packet-Type == Access-Request) { + update proxy-request { + Chargeable-User-Identity = '\\000' + } } } # - # Add a CUI attribute based on the User-Name, and a secret key - # known only to this server. + # Add a CUI attribute based on the User-Name, and a secret key + # known only to this server. # cui_postauth { - if (FreeRadius-Proxied-To == 127.0.0.1) { - if (outer.request:Chargeable-User-Identity) { - update outer.reply { - Chargeable-User-Identity:="%{md5:%{config:cui_hash_key}%{User-Name}}" + if (FreeRadius-Proxied-To == "127.0.0.1") { + # + # Add the CUI to Access-Accept, but only if the CUI + # was set in the request. + # + if (outer.request:Chargeable-User-Identity && (outer.request:Operator-Name) || !("%{config:cui_require_operator_name}") ) { + update reply { + Chargeable-User-Identity := "%{md5:%{config:cui_hash_key}%{request:User-Name}%{%{outer.request:Operator-Name}:-}}" } } } else { - if (Chargeable-User-Identity) { + # + # If the CUI was set in the request and the CUI reply + # is not already set by inner auth, add it to + # Access-Accept + # + if (!("%{control:Proxy-To-Realm}") && \ + (Chargeable-User-Identity) && \ + !(reply:Chargeable-User-Identity) && \ + ( (Operator-Name) || ! ("%{config:cui_require_operator_name}") ) ) { update reply { - Chargeable-User-Identity="%{md5:%{config:cui_hash_key}%{User-Name}}" + Chargeable-User-Identity = "%{md5:%{config:cui_hash_key}%{request:User-Name}%{%{Operator-Name}:-}}" } } } } # - # If there is a CUI attribute in the reply, add it to the DB. + # If there is a CUI attribute in the reply, add it to the DB. # cui_updatedb { - if (reply:Chargeable-User-Identity) { + if ("%{reply:Chargeable-User-Identity}") { cui } } # - # If we had stored a CUI for the User, add it to the request. + # If we had stored a CUI for the User, add it to the request. # cui_accounting { # @@ -199,20 +226,22 @@ # in the DB. # if (!Chargeable-User-Identity) { - update request { - Chargeable-User-Identity := "%{cui: SELECT cui FROM cui WHERE clientipaddress = '%{Client-IP-Address}' AND callingstationid = '%{Calling-Station-Id}' AND username = '%{User-Name}'}" + update control { + Chargeable-User-Identity = "%{cui: SELECT cui FROM cui WHERE clientipaddress = '%{Client-IP-Address}' AND callingstationid = '%{Calling-Station-Id}' AND username = '%{User-Name}'}" } } - # - # If it exists now, then write out when we last saw - # this CUI. + # If it exists now, then update request and write out + # when we last saw this CUI. # - if (Chargeable-User-Identity && (Chargeable-User-Identity != "")) { + if (control:Chargeable-User-Identity && \ + (control:Chargeable-User-Identity != "")) { + update request { + Chargeable-User-Identity := "%{control:Chargeable-User-Identity}" + } cui } } - # # Normalize the MAC Addresses in the Calling/Called-Station-Id # diff -Naur freeradius-server-2.2.0-orig/raddb/sites-available/default freeradius-server-2.2.0/raddb/sites-available/default --- freeradius-server-2.2.0-orig/raddb/sites-available/default 2012-09-10 13:51:34.000000000 +0200 +++ freeradius-server-2.2.0/raddb/sites-available/default 2012-09-13 11:04:54.939298452 +0200 @@ -1,3 +1,13 @@ +# If *returning* the CUI, set cui_hash_key to some random string +# and uncomment the line below +# cui_hash_key = "some secret value" +# If *returning* the CUI and the Operator-Name attribute in request is +# required, uncomment the line below +# cui_require_operator_name = yes +# If Operator-Name attribute is used, uncomment the line below and +# fill out with one of your registered DNS domain names, which +# will be used as the Operator-Name attribute value +# sp_operator_name = "1your.registered.domain.name" ###################################################################### # # As of 2.0.0, FreeRADIUS supports virtual hosts using the @@ -376,6 +386,11 @@ # Accounting. Log the accounting data. # accounting { + # cui_accounting reads the record form the temporary database, + # selects the corresponding CUI value, as set cui_updatedb + # and adds the CUI attribute to the accounting request + # uncomment the line below if *requesting* the CUI +# cui_accounting # # Create a 'detail'ed log of the packets. # Note that accounting requests which are proxied @@ -459,6 +474,17 @@ # Once we KNOW that the user has been authenticated, there are # additional steps we can take. post-auth { + # cui_postauth reacts to the Chargeable-User-Identity request + # by adding the md5 hash created from a configurable local + # salt (cui_hash_key) and the (inner) User-Name value + # uncomment the line below if *returning* the CUI +# cui_postauth + # + # cui_updatedb updates the temporary database adding + # the record containing the received CUI value to be later + # used in accounting + # uncomment the line below if *requesting* the CUI +# cui_updatedb # Get an address from the IP Pool. # main_pool @@ -581,6 +607,14 @@ # Uncomment the following line if you want to change attributes # as defined in the preproxy_users file. # files + + # operator_name adds Operator-Name value to Access-Request +# operator_name + + # cui_pre-proxy adds the NULL CUI value to Access-Request + # thus making it a Chargeable-User-Identity request + # uncomment the line below if *requesting* the CUI +# cui_pre-proxy # Uncomment the following line if you want to filter requests # sent to remote servers based on the rules defined in the diff -Naur freeradius-server-2.2.0-orig/raddb/sites-available/inner-tunnel freeradius-server-2.2.0/raddb/sites-available/inner-tunnel --- freeradius-server-2.2.0-orig/raddb/sites-available/inner-tunnel 2012-09-10 13:51:34.000000000 +0200 +++ freeradius-server-2.2.0/raddb/sites-available/inner-tunnel 2012-09-13 11:05:56.237168046 +0200 @@ -261,6 +261,12 @@ # Once we KNOW that the user has been authenticated, there are # additional steps we can take. post-auth { + # cui_postauth reacts to the Chargeable-User-Identity request + # by adding the md5 hash created from a configurable local + # salt (cui_hash_key) and the (inner) User-Name value + # uncomment the line below if *returning* the CUI +# cui_postauth + # Note that we do NOT assign IP addresses here. # If you try to assign IP addresses for EAP authentication types, # it WILL NOT WORK. You MUST use DHCP. diff -Naur freeradius-server-2.2.0-orig/raddb/sql/mysql/cui.conf freeradius-server-2.2.0/raddb/sql/mysql/cui.conf --- freeradius-server-2.2.0-orig/raddb/sql/mysql/cui.conf 2012-09-10 13:51:34.000000000 +0200 +++ freeradius-server-2.2.0/raddb/sql/mysql/cui.conf 2012-09-13 10:59:05.245170029 +0200 @@ -1,31 +1,55 @@ # -*- text -*- - ## -## Queries to update the CUI table. +## cui.conf -- SQL - CUI queries ## -postauth_query = "INSERT IGNORE INTO ${cui_table} \ - (clientipaddress, callingstationid, username, cui, lastaccounting) \ - VALUES \ - ('%{Client-IP-Address}', '%{Calling-Station-Id}', '%{User-Name}', '%{reply:Chargeable-User-Identity}', NULL) ON DUPLICATE KEY UPDATE lastaccounting='0000-00-00 00:00:00', cui='%{reply:Chargeable-User-Identity}'"; +## $Id$ +# +# This is a part of the Chargeable-User-Identity module +# See doc/cui_howto.txt for more information + + +# postauth_query creates a temporary record remembering +# Client-IP-Address, Calling-Station-Id, User-Name, +# Chargeable-User-Identity. +# This information is used later to correlate accounting requests +# with the information received in Access-Accept +# + postauth_query = "INSERT IGNORE INTO ${cui_table} \ + (clientipaddress, callingstationid, username, \ + cui, lastaccounting) \ + VALUES \ + ('%{Client-IP-Address}', '%{Calling-Station-Id}', \ + '%{User-Name}', '%{reply:Chargeable-User-Identity}', NULL) \ + ON DUPLICATE KEY UPDATE \ + lastaccounting='0000-00-00 00:00:00', \ + cui='%{reply:Chargeable-User-Identity}'"; + +# accounting_start_query and accounting_update_query are called +# by Accounting-Request Start or Interim Update. +# The appropriate temporary record is updates by entering +# the current time as the lastaccounting field. +# The value of lastaccounting can be used to clean up the database +# from stale temporary records. +# + accounting_start_query = "UPDATE ${cui_table} \ + SET lastaccounting = CURRENT_TIMESTAMP \ + WHERE clientipaddress = '%{Client-IP-Address}' \ + AND callingstationid = '%{Calling-Station-Id}' \ + AND username = '%{User-Name}' \ + AND cui = '%{Chargeable-User-Identity}'"; -accounting_start_query = "UPDATE ${cui_table} \ - SET \ - lastaccounting = CURRENT_TIMESTAMP \ - WHERE clientipaddress = '%{Client-IP-Address}' \ - AND callingstationid = '%{Calling-Station-Id}' \ - AND username = '%{User-Name}' \ - AND cui = '%{Chargeable-User-Identity}'"; - -accounting_update_query = "UPDATE ${cui_table} \ - SET \ - lastaccounting = CURRENT_TIMESTAMP \ - WHERE clientipaddress = '%{Client-IP-Address}' \ - AND callingstationid = '%{Calling-Station-Id}' \ - AND username = '%{User-Name}' \ - AND cui = '%{Chargeable-User-Identity}'"; + accounting_update_query = "UPDATE ${cui_table} \ + SET lastaccounting = CURRENT_TIMESTAMP \ + WHERE clientipaddress = '%{Client-IP-Address}' \ + AND callingstationid = '%{Calling-Station-Id}' \ + AND username = '%{User-Name}' \ + AND cui = '%{Chargeable-User-Identity}'"; -accounting_stop_query = "DELETE FROM ${cui_table} WHERE \ - clientipaddress = '%{Client-IP-Address}' \ - AND callingstationid = '%{Calling-Station-Id}' \ - AND username = '%{User-Name}' \ - AND cui = '%{Chargeable-User-Identity}'"; +# accounting_stop_query is called by Accounting-Request Stop. +# It deletes the temporary record form the database. +# + accounting_stop_query = "DELETE FROM ${cui_table} WHERE \ + clientipaddress = '%{Client-IP-Address}' \ + AND callingstationid = '%{Calling-Station-Id}' \ + AND username = '%{User-Name}' \ + AND cui = '%{Chargeable-User-Identity}'"; diff -Naur freeradius-server-2.2.0-orig/raddb/sql/mysql/cui.sql freeradius-server-2.2.0/raddb/sql/mysql/cui.sql --- freeradius-server-2.2.0-orig/raddb/sql/mysql/cui.sql 2012-09-10 13:51:34.000000000 +0200 +++ freeradius-server-2.2.0/raddb/sql/mysql/cui.sql 2012-09-13 10:59:05.245170029 +0200 @@ -1,3 +1,7 @@ +# +# Table structure for table 'cui' +# +# CREATE TABLE `cui` ( `clientipaddress` varchar(15) NOT NULL default '', `callingstationid` varchar(50) NOT NULL default '',