From: Alan T. DeKok Date: Thu, 24 Aug 2023 15:25:55 +0000 (-0400) Subject: add and document cache_groups X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=15edd8ef9b8a4d7b67bd056dc83fcf65a0ab116e;p=thirdparty%2Ffreeradius-server.git add and document cache_groups --- diff --git a/doc/antora/modules/raddb/pages/mods-available/sql.adoc b/doc/antora/modules/raddb/pages/mods-available/sql.adoc index bfeed9af1a9..0d76b0743bf 100644 --- a/doc/antora/modules/raddb/pages/mods-available/sql.adoc +++ b/doc/antora/modules/raddb/pages/mods-available/sql.adoc @@ -196,10 +196,10 @@ sql sql2 { start:: Connections to create during module instantiation. -If the server cannot create specified number of connections during instantiation -it will exit. - -Set to `0` to allow the server to start without the database being available. +If the server cannot create specified number of +connections during instantiation it will exit. +Set to `0` to allow the server to start without the +external service being available. @@ -209,14 +209,18 @@ min:: Minimum number of connections to keep open. max:: Maximum number of connections. -If these connections are all in use and a new one is requested, the request -will NOT get a connection. +If these connections are all in use and a new one +is requested, the request will NOT get a connection. + +Setting `max` to *LESS* than the number of threads means +that some threads may starve, and you will see errors +like _No connections available and at max connection limit_. -Setting `max` to LESS than the number of threads means that some threads may starve, -and you will see errors like _No connections available and at max connection limit_. +Setting `max` to MORE than the number of threads means +that there are more connections than necessary. -Setting `max` to MORE than the number of threads means that there are more -connections than necessary. +If `max` is not specified, then it defaults to the number +of workers configured. @@ -280,6 +284,36 @@ When that happens, it will open a new connection. It will also log a WARNING me group_attribute:: The group attribute specific to this instance of `rlm_sql`. +The "group_membership_query" is used to select which groups the user is a member of. + +The module loops over all groups, and places the group name into the "group_attribute". + +The group attribute is used in the "authorize_group_check_query" and "authorize_group_check_query" +to select entries which match that particular group. + +If caching is enabled, then the module is done looping over groups, the module adds the names of +groups to the `control` list. The "group_attribute" can then be used to check group membership. +That check will be done internally, and will not result in a database lookup. This also means that +it is now possible to do group comparisons based on regular expressions. + +It is possible to force a dynamic group lookup via the expansion `%{sql.group:foo}`. This +expansion returns `true` if the user is a member of that SQL group, and `false` otherwise. + +NOTE: The `SQL-Group` attribute is only available after the SQL module has been run. + +The name of the group attribute is automatically determined from the module name. By default, the +name is `SQL-Group`. if the module is an instance such as `sql sql1 { ... }`, then the name of the +group attribute is `SQL1-Group`. + + + +cache_groups: whether or not we cache the list of SQL groups + +The groups are cached in the `control` list. So any comparisons must be done as +`&control.SQL-Group = ...` + +Default is `no`. + .Read database-specific queries. @@ -327,6 +361,7 @@ sql { connect_timeout = 3.0 } group_attribute = "${.:instance}-Group" +# cache_groups = no $INCLUDE ${modconfdir}/${.:name}/main/${dialect}/queries.conf } ``` diff --git a/raddb/mods-available/sql b/raddb/mods-available/sql index 8cf2e5007a2..57263315fa8 100644 --- a/raddb/mods-available/sql +++ b/raddb/mods-available/sql @@ -345,6 +345,16 @@ sql { # group_attribute = "${.:instance}-Group" + # + # cache_groups: whether or not we cache the list of SQL groups + # + # The groups are cached in the `control` list. So any comparisons must be done as + # `&control.SQL-Group = ...` + # + # Default is `no`. + # +# cache_groups = no + # # .Read database-specific queries. # diff --git a/src/modules/rlm_sql/rlm_sql.c b/src/modules/rlm_sql/rlm_sql.c index 8a2f0d74d72..a075bb10456 100644 --- a/src/modules/rlm_sql/rlm_sql.c +++ b/src/modules/rlm_sql/rlm_sql.c @@ -900,13 +900,15 @@ static unlang_action_t rlm_sql_process_groups(rlm_rcode_t *p_result, entry = head; do { + bool added; + fr_pair_t *vp; + next: fr_assert(entry != NULL); fr_pair_value_strdup(sql_group, entry->name, true); + added = false; if (inst->config.authorize_group_check_query) { - fr_pair_t *vp; - /* * Expand the group query */ @@ -956,10 +958,15 @@ static unlang_action_t rlm_sql_process_groups(rlm_rcode_t *p_result, radius_pairmove(request, &request->control_pairs, &check_tmp); fr_pair_list_free(&check_tmp); + + if (inst->config.cache_groups) { + MEM(pair_update_control(&vp, inst->group_da) >= 0); + fr_pair_value_strdup(vp, entry->name, true); + added = true; + } } if (inst->config.authorize_group_reply_query) { - /* * Now get the reply pairs since the paircmp matched */ @@ -1002,6 +1009,11 @@ static unlang_action_t rlm_sql_process_groups(rlm_rcode_t *p_result, *do_fall_through = FALL_THROUGH_DEFAULT; } + if (inst->config.cache_groups && !added) { + MEM(pair_update_control(&vp, inst->group_da) >= 0); + fr_pair_value_strdup(vp, entry->name, true); + } + entry = entry->next; } while (entry != NULL && (*do_fall_through == FALL_THROUGH_YES)); diff --git a/src/modules/rlm_sql/rlm_sql.h b/src/modules/rlm_sql/rlm_sql.h index e9dd9a1af47..dd94e34a8b6 100644 --- a/src/modules/rlm_sql/rlm_sql.h +++ b/src/modules/rlm_sql/rlm_sql.h @@ -106,6 +106,8 @@ typedef struct { char const *authorize_group_reply_query; //!< Query used get reply VPs for a group. char const *groupmemb_query; //!< Query to determine group membership. + bool cache_groups; //!< cache group names in &control.SQL-Group + bool read_groups; //!< Read user groups by default. //!< If false, Fall-Through = yes is required //!< in the previous reply list to process