feature request: ldap enhancements
Hello Arran, you asked if I have any feature requests. So, here are two points I want to discuss: 1. reload all RADIUS clients stored in ldap on SIGHUP (bulk load) - 'radmin -e "hup ldap"' would be sufficient here 2. enhanced ldap support for storing and managing huntgroups Our goal is to restrict several users to one or more "NAS groups". It should be possible that the same NAS can be member of multiple huntgroups as well as to assign multiple huntgroups to a user. Example: huntgroup-1 NAS-IP-Address == 192.0.2.5 huntgroup-1 NAS-IP-Address == 192.0.2.6 huntgroup-1 NAS-IP-Address == 192.0.2.7 huntgroup-2 NAS-IP-Address == 192.0.2.7 huntgroup-2 NAS-IP-Address == 192.0.2.8 huntgroup-2 NAS-IP-Address == 192.0.2.9 user1 Cleartext-Password := "password1", Huntgroup-Name == "huntgroup-1" Service-Type = Administrative-User user2 Cleartext-Password := "password2", Huntgroup-Name == "huntgroup-2" Service-Type = Administrative-User user3 Cleartext-Password := "password3", Huntgroup-Name == "huntgroup-1", Huntgroup-Name == "huntgroup-2" Service-Type = Administrative-User Please pardon if the huntgroup assignment here is incorrect, I did not use huntgroups at all for now. To do this in ldap there have to be something like: a) new object class for huntgroups to distinct these from other RADIUS related objects like RADIUS clients and RADIUS profiles. I think this approach is better than adding a multi-valued attribute to the RADIUS clients object class for better clarity. b) The existing RADIUS profile object class should be extended for a multi-valued attribute to assign multiple huntgroups to a user profile. With this assumption radiusd could read all defined huntgroups on startup (reread on SIGHUP;-) ) and do the matching in authorize section after the user profile is read from ldap. Would be glad if you can give your thoughts on this or maybe some hints if this could be achieved already different. Hope this two points are not very far-fetched ;-) Regard, Tobias
On 18 Dec 2013, at 07:42, Hachmer, Tobias <Tobias.Hachmer@stadt-frankfurt.de> wrote:
Hello Arran,
you asked if I have any feature requests. So, here are two points I want to discuss:
1. reload all RADIUS clients stored in ldap on SIGHUP (bulk load) - ‘radmin -e "hup ldap"’ would be sufficient here
That's difficult. You'll notice that non the of the modules which use a connection pool at marked as HUP safe. The reason for this is due to how HUP works. It first creates a new instance of every HUP safe module used by the server, and in doing so creates a new connection pool. The connection pool then opens X number of additional connections. After a period the old instance is freed and the old connections destroyed. Between the HUP and the old instance being freed the server would have double the number of connections open. This can cause issues where things like SQL and LDAP servers may have limits on the maximum number of clients. It should be possible to avoid recreating connection pools, and as an added bonus it might allow shared connection pools. I'd need Alan's feedback on whether it's acceptable to allow configuration changes to the module, whilst not allowing configuration changes with the connection pool before implementing such a change. You can use the dynamic clients server to load additional clients in without HUP or restart, in all current versions of the server (if this is all you require).
2. enhanced ldap support for storing and managing huntgroups Our goal is to restrict several users to one or more “NAS groups”. It should be possible that the same NAS can be member of multiple huntgroups as well as to assign multiple huntgroups to a user.
Example: huntgroup-1 NAS-IP-Address == 192.0.2.5 huntgroup-1 NAS-IP-Address == 192.0.2.6 huntgroup-1 NAS-IP-Address == 192.0.2.7
huntgroup-2 NAS-IP-Address == 192.0.2.7 huntgroup-2 NAS-IP-Address == 192.0.2.8 huntgroup-2 NAS-IP-Address == 192.0.2.9
user1 Cleartext-Password := "password1", Huntgroup-Name == "huntgroup-1" Service-Type = Administrative-User
user2 Cleartext-Password := "password2", Huntgroup-Name == "huntgroup-2" Service-Type = Administrative-User
user3 Cleartext-Password := "password3", Huntgroup-Name == "huntgroup-1", Huntgroup-Name == "huntgroup-2" Service-Type = Administrative-User
Please pardon if the huntgroup assignment here is incorrect, I did not use huntgroups at all for now.
To do this in ldap there have to be something like: a) new object class for huntgroups to distinct these from other RADIUS related objects like RADIUS clients and RADIUS profiles. I think this approach is better than adding a multi-valued attribute to the RADIUS clients object class for better clarity. b) The existing RADIUS profile object class should be extended for a multi-valued attribute to assign multiple huntgroups to a user profile.
This doesn't fit with the design of the server. The only information read in from a dynamic source and implicitly cached are the clients entries, and that is for performance reasons. None of the directory, database, datastore modules currently support caching data read from an external server. Where caching is required for performance or resilience, the rlm_cache module can be used. Modifications to rlm_ldap for v3.0.x allowed group membership information to be cached. That is all group information is retrieved from the LDAP directory for a particular object, and then written into control attributes. Those control attributes can then be cached with the rlm_cache module. When LDAP-Group == <value> is executed, the rlm_ldap module checks for the presence of these control attributes, and if they're found, they are used to determine membership instead of calling out to the server. The same system can be used to store group information about NAS. In your above example you would create an object to represent the NAS with an IP address attribute. You would treat this object as the 'user' (principal), and filter using IP address instead of User-Name. Group membership can then be checked with the rlm_ldap instance specific pair comparison. ldap NAS { <config> } if (NAS-Ldap-Group == 'group-1') { } If you need to invalidate the cache, you can do it by setting the cache epoch appropriately using the radmin command. This avoids HUPing the server, which is a potentially dangerous operation. -Arran Arran Cudbard-Bell <a.cudbardb@freeradius.org> FreeRADIUS Development Team FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2
Hello Arran, thanks for your answer and sorry for my delay... -----Ursprüngliche Nachricht----- Von: freeradius-users-bounces+tobias.hachmer=stadt-frankfurt.de@lists.freeradius.org [mailto:freeradius-users-bounces+tobias.hachmer=stadt-frankfurt.de@lists.freeradius.org] Im Auftrag von Arran Cudbard-Bell Gesendet: Mittwoch, 18. Dezember 2013 14:43 An: FreeRadius users mailing list Betreff: Re: feature request: ldap enhancements On 18 Dec 2013, at 07:42, Hachmer, Tobias <Tobias.Hachmer@stadt-frankfurt.de> wrote:
1. reload all RADIUS clients stored in ldap on SIGHUP (bulk load) - 'radmin -e "hup ldap"' would be sufficient here That's difficult. You'll notice that non the of the modules which use a connection pool at marked as HUP safe. The reason for this is due to how HUP works. It first creates a new instance of every HUP safe module used by the server, and in doing so creates a new connection pool. The connection pool then opens X number of additional connections. After a period the old instance is freed and the old connections destroyed. Between the HUP and the old instance being freed the server would have double the number of connections open. This can cause issues where things like SQL and LDAP servers may have limits on the maximum number of clients. It should be possible to avoid recreating connection pools, and as an added bonus it might allow shared connection pools. I'd need Alan's feedback on whether it's acceptable to allow configuration changes to the module, whilst not allowing configuration changes with the connection pool before implementing such a change. You can use the dynamic clients server to load additional clients in without HUP or restart, in all current versions of the server (if this is all you require).
I know the dynamic client feature. Here we're looking for the possibility to manage client ip ranges within ldap also. If using dynamic clients server the ip range clients come from must not be defined in clients.conf. So I see, the only way to using the full management of radius clients in ldap is to restart fr server after adding client definitions in ldap.
2. enhanced ldap support for storing and managing huntgroups Our goal is to restrict several users to one or more "NAS groups". It should be possible that the same NAS can be member of multiple huntgroups as well as to assign multiple huntgroups to a user. To do this in ldap there have to be something like: a) new object class for huntgroups to distinct these from other RADIUS related objects like RADIUS clients and RADIUS profiles. I think this approach is better than adding a multi-valued attribute to the RADIUS clients object class for better clarity. b) The existing RADIUS profile object class should be extended for a multi-valued attribute to assign multiple huntgroups to a user profile.
This doesn't fit with the design of the server. The only information read in from a dynamic source and implicitly cached are the clients entries, and that is for performance reasons. None of the directory, database, datastore modules currently support caching data read from an external server. Where caching is required for performance or resilience, the rlm_cache module can be used. Modifications to rlm_ldap for v3.0.x allowed group membership information to be cached. That is all group information is retrieved from the LDAP directory for a particular object, and then written into control attributes. Those control attributes can then be cached with the rlm_cache module. When LDAP-Group == <value> is executed, the rlm_ldap module checks for the presence of these control attributes, and if they're found, they are used to determine membership instead of calling out to the server. The same system can be used to store group information about NAS. In your above example you would create an object to represent the NAS with an IP address attribute. You would treat this object as the 'user' (principal), and filter using IP address instead of User-Name. Group membership can then be checked with the rlm_ldap instance specific pair comparison. ldap NAS { <config> }
if (NAS-Ldap-Group == 'group-1') {
} Ok, if I understand this correct I need for each RADIUS Client a separate ldap object in a different ou? And how can I join the "NAS groups" with the user objects in order to restrict access for user1 to NAS group 1+2 and for user2 to NAS group 2+3 ?
Regards, Tobias Hachmer
I know the dynamic client feature. Here we're looking for the possibility to manage client ip ranges within ldap also. If using dynamic clients server the ip range clients come from must not be defined in clients.conf. So I see, the only way to using the full management of radius clients in ldap is to restart fr server after adding client definitions in ldap.
Yes, for now.
Ok, if I understand this correct I need for each RADIUS Client a separate ldap object in a different ou?
Well it doesn't *have* to be in a different OU, but it's probably better to do that, and they don't have to be separate from the clients you load in with the LDAP module at startup.
And how can I join the "NAS groups" with the user objects in order to restrict access for user1 to NAS group 1+2 and for user2 to NAS group 2+3 ?
You ned two instance of the LDAP module because the configurations are quite different. One you'd set to filter on user objects, the other would be radiusClient objects. ldap user { } ldap nas { } authorize { user nas if ((NAS-LDAP-Group == 'foo' || NAS-LDAP-Group == 'bar') && (User-LDAP-Group == 'baz')) { } } To search for the NAS you probably want to use shortname, and you'll need to make sure that's unique. user { # Where to start searching in the tree for users base_dn = "${..base_dn}" # Filter for user objects, should be specific enough # to identify a single user object. filter = "(&(radiusClientShortname=%{client:shortname})(objectclass=radiusClient))" ... } IIRC the current client xlat doesn't let you retrieve ID, and you can't use IP addresses if you're using ranges because the LDAP server won't have operators for comparing IPs/ranges. -Arran Arran Cudbard-Bell <a.cudbardb@freeradius.org> FreeRADIUS Development Team FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2
To search for the NAS you probably want to use shortname, and you'll need to make sure that's unique.
user { # Where to start searching in the tree for users base_dn = "${..base_dn}"
# Filter for user objects, should be specific enough # to identify a single user object. filter = "(&(radiusClientShortname=%{client:shortname})(objectclass=radiusClient))"
... }
IIRC the current client xlat doesn't let you retrieve ID, and you can't use IP addresses if you're using ranges because the LDAP server won't have operators for comparing IPs/ranges.
And before you complain about how horribly inefficient it is, remember you can cache group memberships :) Arran Cudbard-Bell <a.cudbardb@freeradius.org> FreeRADIUS Development Team FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2
-----Ursprüngliche Nachricht----- Von: freeradius-users-bounces+tobias.hachmer=stadt-frankfurt.de@lists.freeradius.org [mailto:freeradius-users-bounces+tobias.hachmer=stadt-frankfurt.de@lists.freeradius.org] Im Auftrag von Arran Cudbard-Bell Gesendet: Montag, 13. Januar 2014 22:32 An: FreeRadius users mailing list Betreff: Re: feature request: ldap enhancements
I know the dynamic client feature. Here we're looking for the possibility to manage client ip ranges within ldap also. If using dynamic clients server the ip range clients come from must not be defined in clients.conf. So I see, the only way to using the full management of radius clients in ldap is to restart fr server after adding client definitions in ldap. Yes, for now.
OK, I can work with this but it would be great to make some enhancements to rlm_ldap regarding reread radius client objects, e.g. periodically like every 30 minutes. This would be sufficient.
Ok, if I understand this correct I need for each RADIUS Client a separate ldap object in a different ou? Well it doesn't *have* to be in a different OU, but it's probably better to do that, and they don't have to be separate from the clients you load in with the LDAP module at startup. And how can I join the "NAS groups" with the user objects in order to restrict access for user1 to NAS group 1+2 and for user2 to NAS group 2+3 ? You ned two instance of the LDAP module because the configurations are quite different. One you'd set to filter on user objects, the other would be radiusClient objects.
I hope I understand now. I have to define a second ldap instance and configure it to find the radiusClient objects instead of real user objects as well as the correct group membership parameters. Will test it.
To search for the NAS you probably want to use shortname, and you'll need to make sure that's unique. user { # Where to start searching in the tree for users base_dn = "${..base_dn}"
# Filter for user objects, should be specific enough # to identify a single user object. filter = "(&(radiusClientShortname=%{client:shortname})(objectclass=radiusClient))" ... }
authorize { user nas if ((NAS-LDAP-Group == 'foo' || NAS-LDAP-Group == 'bar') && (User-LDAP-Group == 'baz')) { } }
So, the radius clients will be "treated" as users where username will be the clients shortname, right? Hmm, I'm just thinking of the unlang conditions. I can just imagine to define one big if block like: if((NAS-LDAP-Group == 'foo' || NAS-LDAP-Group == 'bar') && (User-LDAP-Group == 'baz')) { handled } elsif((NAS-LDAP-Group == 'foo2' || NAS-LDAP-Group == 'bar2') && (User-LDAP-Group == 'baz2')) { handled } elsif((NAS-LDAP-Group == 'foo' || NAS-LDAP-Group == 'bar2') && (User-LDAP-Group == 'baz3')) { handled } else { reject } Am I using the conditions here the right way or is there a better approach? Regards, Tobias Hachmer
Hachmer, Tobias wrote:
OK, I can work with this but it would be great to make some enhancements to rlm_ldap regarding reread radius client objects, e.g. periodically like every 30 minutes. This would be sufficient.
The dynamic clients code already handles this. I'd suggest instead ensuring that the dynamic clients can have ranges, and not just IP addresses. Simpler, and more flexible. Alan DeKok.
On 14 Jan 2014, at 16:16, Alan DeKok <aland@deployingradius.com> wrote:
Hachmer, Tobias wrote:
OK, I can work with this but it would be great to make some enhancements to rlm_ldap regarding reread radius client objects, e.g. periodically like every 30 minutes. This would be sufficient.
The dynamic clients code already handles this. I'd suggest instead ensuring that the dynamic clients can have ranges, and not just IP addresses. Simpler, and more flexible.
Done... In theory. On v3.0.x and master. If you just wanted to add ranges, use a combination of dynamic clients and the LDAP bulk load. This will reduce load on your LDAP directory on server restart. If you're wanting to do crazy things like change secrets regularly, use dynamic clients only, and poke the server using radmin. Arran Cudbard-Bell <a.cudbardb@freeradius.org> FreeRADIUS Development Team FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2
-----Ursprüngliche Nachricht----- Von: freeradius-users-bounces+tobias.hachmer=stadt-frankfurt.de@lists.freeradius.org [mailto:freeradius-users-bounces+tobias.hachmer=stadt-frankfurt.de@lists.freeradius.org] Im Auftrag von Arran Cudbard-Bell Gesendet: Dienstag, 14. Januar 2014 18:58 An: FreeRadius users mailing list Betreff: Re: feature request: ldap enhancements
On 14 Jan 2014, at 16:16, Alan DeKok <aland@deployingradius.com> wrote:
The dynamic clients code already handles this. I'd suggest instead ensuring that the dynamic clients can have ranges, and not just IP addresses. Simpler, and more flexible.
Done... In theory. On v3.0.x and master. If you just wanted to add ranges, use a combination of dynamic clients and the LDAP bulk load.
Thanks for the update. Yes, this is also a good resolution. How do I have to use the new internal FR attribute FreeRADIUS-Client-IP-Prefix? For my understanding I have to create ldap objects with rdn cn=IP-Prefix like cn=10.0.1.0/24. What way is the matching done? Regards, Tobias Hachmer
On 15 Jan 2014, at 08:27, Hachmer, Tobias <Tobias.Hachmer@stadt-frankfurt.de> wrote:
-----Ursprüngliche Nachricht----- Von: freeradius-users-bounces+tobias.hachmer=stadt-frankfurt.de@lists.freeradius.org [mailto:freeradius-users-bounces+tobias.hachmer=stadt-frankfurt.de@lists.freeradius.org] Im Auftrag von Arran Cudbard-Bell Gesendet: Dienstag, 14. Januar 2014 18:58 An: FreeRadius users mailing list Betreff: Re: feature request: ldap enhancements
On 14 Jan 2014, at 16:16, Alan DeKok <aland@deployingradius.com> wrote:
The dynamic clients code already handles this. I'd suggest instead ensuring that the dynamic clients can have ranges, and not just IP addresses. Simpler, and more flexible.
Done... In theory. On v3.0.x and master. If you just wanted to add ranges, use a combination of dynamic clients and the LDAP bulk load.
Thanks for the update. Yes, this is also a good resolution.
How do I have to use the new internal FR attribute FreeRADIUS-Client-IP-Prefix? For my understanding I have to create ldap objects with rdn cn=IP-Prefix like cn=10.0.1.0/24. What way is the matching done?
If your subnets are fixed size and on the octets boundaries, use a regex and the LDAP wildcard operator. If your subnets are a fixed size but not on octets boundaries I can add an xlat function to zero out the host bits: update control { Tmp-Ip-Address-0 := "%{ipprefix:%{Packet-Src-IP-Address}/<cidr>}" } If they're a limited range of sizes then the solution above could work, just add additional prefixes to the filter for your standard subnet sizes. If they're arbitrary sizes then this solution won't work well For actually retrieving the data you could use (yet another) instance of rlm_ldap with a different configuration, or ldap xlat and pull each client attribute from the directory one at a time. Arran Cudbard-Bell <a.cudbardb@freeradius.org> FreeRADIUS Development Team FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2
participants (3)
-
Alan DeKok -
Arran Cudbard-Bell -
Hachmer, Tobias