Chargeable-User-Identity implementation

Stefan Winter stefan.winter at restena.lu
Tue Nov 16 15:24:11 CET 2010


  Hi,

> > From my perspective, Chargeable-User-Identity is something that should
> be logged with the 'custom' SQL logging rules being used.  Slipping it
> into a separate table, somehow feels weird; I guess that's what makes me
> a packet-pusher and someone else a database guru :)

The question is: where to put it. The CUI information comes with the 
Access-Accept, and needs to be stored before the first accounting packet 
(if any) arrives at the server. So it can't be an extra column in any 
accounting query.
SQL logging in post-auth would be an option. But that usually doesn't 
store the necessary bits to retrofit the incoming accounting queries 
with the CUI value (Calling-Station-Id being one thing that needs to be 
logged alongside, to correlate the auth and acct). So that requires a 
new structure for radpostauth - which is certainly a possibility. I just 
wonder how much people fancy if radpostauth structure changes between 
releases - it hasn't changed in a long while now.


>   * I thought Client-IP-Address was deprecated and we all should be using
> 	'%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}'

Humm. That deserves updating the code :-)

>   * section 2.1 of RFC 4372 lets you be awkward about mis-matching CUI's
> 	and offers you the option to Reject :)

That's the paragraph for re-authentications, right? i.e

"Upon receiving a non-nul CUI value in an Access-Request, the home

    RADIUS server MAY verify that the value of CUI matches the CUI from
    the previous Access-Accept.  If the verification fails, then the
    RADIUS server SHOULD respond with an Access-Reject message."

I don't think that is essential or even clever to implement. A home server is allowed to change its CUIs after a (long) while. Now what happens if a user authenticated with one value for his CUI, the home server meanwhile rolled over to a new CUI, and then the client reauthenticates? Rejecting the re-auth is rather drastic, and out of control of the user in question.


>   * not too sure about the outer.request bits.  It seems cleaner to get
> 	the inner layer to return just the User-Name to the outer layer,
> 	the outer layer can then add the CUI bits (as if it was a
> 	non-EAP request) and trim the User-Name in the reply packet
> 	before it sends out the Access-Accept

The code in that section is the result of a rather long and fruitful 
trial-and-error: there are EAP methods which don't have an inner method. 
Some other EAP types generate the CUI value not in the last inner-tunnel 
packet, but the penultimate one. I'm not the one who implemented it, but 
I know that much pain has gone into testing and refining these statements.
But this doesn't preclude from advancing the implementation even more, 
of course. But I'd be happy to have *some* implementation in mainline 
release eventually, and then take it from there.

>   * I never thought to add Operator-Name as part of the hash key for CUI,
> 	noted for myself, ta
>   * not sure about even having cui_require_operator_name as the
> 	user's realm would tell you who you need to pester surely?

No, the user's realm gives the Service Provider an idea who the 
responsible Identity Provider is. Operator-Name gives the Identity 
Provider an idea which Service Provider to pester.

The "require" part of this is due to privacy considerations: if 
Operator-Name is not in the packet, CUI for a user will be the same *at 
all Service Provider locations* - enabling tracking mobility profiles. 
As an Identity Provider you could say: "I'll only release CUI if I can 
do it per Service Provider to prevent tracking" - and the "require" 
option allows you to make just that happen.

Greetings,

Stefan Winter

> My approach is a bit more softly-softly (although I will admit it has
> not had any field testing), most of the brains is here in policy.conf:
> ----
> cui {
>          if (Realm == "%{config:local.MY.realm}") {
>                  update control {
>                          # md5(cui_hash_key + user at realm)
>                          Chargeable-User-Identity := "%{md5:%{config:local.MY.cui_hash_key}%{tolower:%{%{reply:User-Name}:-%{request:User-Name}}}}"
>                  }
>
>                  if ((request:Chargeable-User-Identity)) {
>                          update reply {
>                                  Chargeable-User-Identity := "%{control:Chargeable-User-Identity}"
>                          }
>
>                          if (request:Chargeable-User-Identity != "\\000") {
>                                  if (request:Chargeable-User-Identity != reply:Chargeable-User-Identity) {
>                                          update reply {
>                                                  Reply-Message := "CUI Mismatch"
>                                          }
>                                          reject
>                                  }
>                          }
>                  }
>                  else {
>                          update request {
>                                  Chargeable-User-Identity := "%{control:Chargeable-User-Identity}"
>                          }
>                  }
>
>                  ok
>          }
>
>          noop
> }
> ----
>
> The for internal clients I have something like[1]:
> ----
> post-auth {
>          update reply {
>                  Operator-Name := "1%{config:local.MY.realm}"
>          }
>
>          cui
>
>          [snipped policy]
>
>          [snipped logging]
> }
>
> accounting {
>          [snipped logging]
>
>          cui
>
>          [snipped logging]
> }
>
> pre-proxy {
>          if (Packet-Type != "Accounting-Request") {
>                  update proxy-request {
>                          Service-Type := Authenticate-Only
>                          Chargeable-User-Identity := "\\000"
>                  }
>          }
>
>          update proxy-request {
>                  Operator-Name := "1%{config:local.MY.realm}"
>
>                  NAS-IP-Address := "%{config:local.MY.addr.lanwarden.v4}"
>                  NAS-IPv6-Address := "%{config:local.MY.addr.lanwarden.v6}"
>          }
>
>          [snipped logging]
> }
> ----
>
> For the roamers:
> ----
> post-auth {
>          cui
>
>          [snipped policy]
>
>          [snipped logging]
> }
> ----
>
> For the SQL logging, it is just an extra column on my table:
> ----
> CREATE TABLE dot1x_auth
> (
>    id bigserial NOT NULL,
>    realm character varying(253),
>    nas_ip_address inet,
>    nas_port_type character varying(32),
>    nas_port_id character varying(64),
>    calling_station_id character varying(64) NOT NULL,
>    called_station_id character varying(64),
>    packet_src_address inet NOT NULL,
>    nas_identifier character varying(253),
>    reply_message character varying(253),
>    module_message character varying(253),
>    eap_type character varying(16),
>    auth_type character varying(16),
>    "timestamp" timestamp with time zone NOT NULL,
>    packet_type character varying(32) NOT NULL,
>    tunnel_private_group_id character varying(32),
>    user_name character varying(253) NOT NULL,
>    inet_client_addr inet NOT NULL DEFAULT inet_client_addr(),
>    nas_port integer,
>    nas_ipv6_address inet,
>    chargeable_user_identity character varying(253),<------
>    operator_name character varying(253),<------
>    CONSTRAINT dot1x_auth_id PRIMARY KEY (id)
> )
> ----
>
> Cheers
>
> [1] snipped irrelevant bits of course, if anyone wants our full
> 	FreeRADIUS config dump to see this in real life then do ask
> 	offlist
>


-- 
Stefan WINTER
Ingenieur de Recherche
Fondation RESTENA - Réseau Téléinformatique de l'Education Nationale et de la Recherche
6, rue Richard Coudenhove-Kalergi
L-1359 Luxembourg

Tel: +352 424409 1
Fax: +352 422473




More information about the Freeradius-Users mailing list