]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MAJOR: auth: Change the internal authentication system.
authorThierry FOURNIER <tfournier@exceliance.fr>
Wed, 22 Jan 2014 17:38:02 +0000 (18:38 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 17 Mar 2014 17:06:06 +0000 (18:06 +0100)
This patch remove the limit of 32 groups. It also permit to use standard
"pat_parse_str()" function in place of "pat_parse_strcat()". The
"pat_parse_strcat()" is no longer used and its removed. Before this
patch, the groups are stored in a bitfield, now they are stored in a
list of strings. The matching is slower, but the number of groups is
low and generally the list of allowed groups is short.

The fetch function "smp_fetch_http_auth_grp()" used with the name
"http_auth_group" return valid username. It can be used as string for
displaying the username or with the acl "http_auth_group" for checking
the group of the user.

Maybe the names of the ACL and fetch methods are no longer suitable, but
I keep the current names for conserving the compatibility with existing
configurations.

The function "userlist_postinit()" is created from verification code
stored in the big function "check_config_validity()". The code is
adapted to the new authentication storage system and it is moved in the
"src/auth.c" file. This function is used to check the validity of the
users declared in groups and to check the validity of groups declared
on the "user" entries.

This resolve function is executed before the check of all proxy because
many acl needs solved users and groups.

doc/configuration.txt
include/proto/auth.h
include/types/auth.h
include/types/pattern.h
src/acl.c
src/auth.c
src/cfgparse.c
src/pattern.c
src/proto_http.c

index 81a50994e88032fd2b3e4fef6c5227436b3452d5..7e9a650361d33495bd4cef5ff1c2b13be0f2daf3 100644 (file)
@@ -10750,15 +10750,19 @@ http_auth(<userlist>) : boolean
   fetch function is not really useful outside of ACLs. Currently only http
   basic auth is supported.
 
-http_auth_group(<userlist>) : group
-  Returns a boolean indicating whether the authentication data received from
-  the client match a username & password stored in the specified userlist, and
-  whether that username belongs to one of the groups supplied in ACL patterns.
+http_auth_group(<userlist>) : string
+  Returns a string corresponding to the user name found in the authentication
+  data received from the client if both the user name and password are valid
+  according to the specified userlist. The main purpose is to use it in ACLs
+  where it is then checked whether the user belongs to any group within a list.
   This fetch function is not really useful outside of ACLs. Currently only http
   basic auth is supported.
 
   ACL derivatives :
-    http_auth_group(<userlist>) : user group match
+    http_auth_group(<userlist>) : group ...
+    Returns true when the user extracted from the request and whose password is
+    valid according to the specified userlist belongs to at least one of the
+    groups.
 
 http_first_req : boolean
   Returns true when the request being processed is the first one of the
index 711b2f89fb08aba578dbae88684c91412b27b0ba..a9606134b542457f0a9a9c4f2329cdd7a6bc0a9e 100644 (file)
@@ -20,9 +20,11 @@ extern struct userlist *userlist;
 
 struct userlist *auth_find_userlist(char *name);
 unsigned int auth_resolve_groups(struct userlist *l, char *groups);
+int userlist_postinit();
 void userlist_free(struct userlist *ul);
 enum pat_match_res pat_match_auth(struct sample *smp, struct pattern *pattern);
-int check_user(struct userlist *ul, unsigned int group_mask, const char *user, const char *pass);
+int check_user(struct userlist *ul, const char *user, const char *pass);
+int check_group(struct userlist *ul, char *name);
 
 #endif /* _PROTO_AUTH_H */
 
index e60d363ec1aaf44fa00a1e1ff70885932c6db8cc..964f29b6a963875687b64668baaed68e9d711f87 100644 (file)
 
 #include <types/auth.h>
 
-#define MAX_AUTH_GROUPS (unsigned int)(sizeof(int)*8)
-
 #define AU_O_INSECURE  0x00000001              /* insecure, unencrypted password */
 
+struct auth_groups {
+       struct auth_groups *next;
+       char *name;
+       char *groupusers; /* Just used during the configuration parsing. */
+};
+
+struct auth_groups_list {
+       struct auth_groups_list *next;
+       struct auth_groups *group;
+};
+
 struct auth_users {
        struct auth_users *next;
        unsigned int flags;
        char *user, *pass;
        union {
-               char *groups;
-               unsigned int group_mask;
+               char *groups_names; /* Just used during the configuration parsing. */
+               struct auth_groups_list *groups;
        } u;
 };
 
@@ -36,9 +45,7 @@ struct userlist {
        struct userlist *next;
        char *name;
        struct auth_users *users;
-       int grpcnt;
-       char *groups[MAX_AUTH_GROUPS];
-       char **groupusers;
+       struct auth_groups *groups;
 };
 
 #endif /* _TYPES_AUTH_H */
index 4e893724f4cbcb36f5e7bd869788cc2a8617ce50..93ee29700fbf0b147aa11ed37e774a36e5d5a8ba 100644 (file)
@@ -138,7 +138,6 @@ struct pattern {
                        unsigned char mask;     /* number of bits */
                } ipv6;                         /* IPv6 address/mask */
                struct pat_time time;           /* valid hours and days */
-               unsigned int group_mask;
                struct eb_root *tree;           /* tree storing all values if any */
        } val;                                  /* direct value */
        union {
index abfd04cc2a3941915740f918b9f266ba3b2a4a81..8ce49a91b798562f04363e667a632c161ca6742b 100644 (file)
--- a/src/acl.c
+++ b/src/acl.c
@@ -1053,18 +1053,13 @@ int acl_find_targets(struct proxy *p)
                                        continue;
                                }
 
+                               /* For each pattern, check if the group exists. */
                                list_for_each_entry(pattern, &expr->pat.patterns, list) {
-                                       /* this keyword only has one argument */
-                                       pattern->val.group_mask = auth_resolve_groups(expr->smp->arg_p->data.usr, pattern->ptr.str);
-
-                                       if (!pattern->val.group_mask) {
+                                       if (!check_group(expr->smp->arg_p->data.usr, pattern->ptr.str)) {
                                                Alert("proxy %s: acl %s %s(): invalid group '%s'.\n",
                                                      p->id, acl->name, expr->kw, pattern->ptr.str);
                                                cfgerr++;
                                        }
-                                       free(pattern->ptr.str);
-                                       pattern->ptr.str = NULL;
-                                       pattern->len = 0;
                                }
                        }
                }
index 203b5aaf7d0b1a83bc83ead898ebb926d02635f4..961c2886672e8071157f7d4d119516dd396f1dc8 100644 (file)
@@ -26,6 +26,7 @@
 #include <unistd.h>
 
 #include <common/config.h>
+#include <common/errors.h>
 
 #include <proto/acl.h>
 #include <proto/log.h>
@@ -54,36 +55,14 @@ auth_find_userlist(char *name)
        return NULL;
 }
 
-/* find group_mask for selected gropus. The function returns 1 if OK or nothing to do,
- * 0 if case of unresolved groupname.
- * WARING: the function destroys the list (strtok), so it can only be used once.
- */
-
-unsigned int
-auth_resolve_groups(struct userlist *l, char *groups)
+int check_group(struct userlist *ul, char *name)
 {
+       struct auth_groups *ag;
 
-       char *group = NULL;
-       unsigned int g, group_mask = 0;
-
-       if (!groups || !*groups)
-               return 0;
-
-       while ((group = strtok(group?NULL:groups," "))) {
-               for (g = 0; g < l->grpcnt; g++)
-                       if (!strcmp(l->groups[g], group))
-                               break;
-
-               if (g == l->grpcnt) {
-                       Alert("No such group '%s' in userlist '%s'.\n",
-                               group, l->name);
-                       return 0;
-               }
-
-               group_mask |= (1 << g);
-       }
-
-       return group_mask;
+       for (ag = ul->groups; ag; ag = ag->next)
+               if (strcmp(name, ag->name) == 0)
+                       return 1;
+       return 0;
 }
 
 void
@@ -91,11 +70,21 @@ userlist_free(struct userlist *ul)
 {
        struct userlist *tul;
        struct auth_users *au, *tau;
-       int i;
+       struct auth_groups_list *agl, *tagl;
+       struct auth_groups *ag, *tag;
 
        while (ul) {
+               /* Free users. */
                au = ul->users;
                while (au) {
+                       /* Free groups that own current user. */
+                       agl = au->u.groups;
+                       while (agl) {
+                               tagl = agl;
+                               agl = agl->next;
+                               free(tagl);
+                       }
+
                        tau = au;
                        au = au->next;
                        free(tau->user);
@@ -103,30 +92,135 @@ userlist_free(struct userlist *ul)
                        free(tau);
                }
 
+               /* Free grouplist. */
+               ag = ul->groups;
+               while (ag) {
+                       tag = ag;
+                       ag = ag->next;
+                       free(tag->name);
+                       free(tag);
+               }
+
                tul = ul;
                ul = ul->next;
-
-               for (i = 0; i < tul->grpcnt; i++)
-                       free(tul->groups[i]);
-
                free(tul->name);
                free(tul);
        };
 }
 
+int userlist_postinit()
+{
+       struct userlist *curuserlist = NULL;
+
+       /* Resolve usernames and groupnames. */
+       for (curuserlist = userlist; curuserlist; curuserlist = curuserlist->next) {
+               struct auth_groups *ag;
+               struct auth_users *curuser;
+               struct auth_groups_list *grl;
+
+               for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
+                       char *group = NULL;
+                       struct auth_groups_list *groups = NULL;
+
+                       if (!curuser->u.groups_names)
+                               continue;
+
+                       while ((group = strtok(group?NULL:curuser->u.groups_names, ","))) {
+                               for (ag = curuserlist->groups; ag; ag = ag->next) {
+                                       if (!strcmp(ag->name, group))
+                                               break;
+                               }
+
+                               if (!ag) {
+                                       Alert("userlist '%s': no such group '%s' specified in user '%s'\n",
+                                             curuserlist->name, group, curuser->user);
+                                       return ERR_ALERT | ERR_FATAL;
+                               }
+
+                               /* Add this group at the group userlist. */
+                               grl = calloc(1, sizeof(*grl));
+                               if (!grl) {
+                                       Alert("userlist '%s': no more memory when trying to allocate the user groups.\n",
+                                             curuserlist->name);
+                                       return  ERR_ALERT | ERR_FATAL;
+                               }
+
+                               grl->group = ag;
+                               grl->next = groups;
+                               groups = grl;
+                       }
+
+                       free(curuser->u.groups);
+                       curuser->u.groups = groups;
+               }
+
+               for (ag = curuserlist->groups; ag; ag = ag->next) {
+                       char *user = NULL;
+
+                       if (!ag->groupusers)
+                               continue;
+
+                       while ((user = strtok(user?NULL:ag->groupusers, ","))) {
+                               for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
+                                       if (!strcmp(curuser->user, user))
+                                               break;
+                               }
+
+                               if (!curuser) {
+                                       Alert("userlist '%s': no such user '%s' specified in group '%s'\n",
+                                             curuserlist->name, user, ag->name);
+                                       return ERR_ALERT | ERR_FATAL;
+                               }
+
+                               /* Add this group at the group userlist. */
+                               grl = calloc(1, sizeof(*grl));
+                               if (!grl) {
+                                       Alert("userlist '%s': no more memory when trying to allocate the user groups.\n",
+                                             curuserlist->name);
+                                       return  ERR_ALERT | ERR_FATAL;
+                               }
+
+                               grl->group = ag;
+                               grl->next = curuser->u.groups;
+                               curuser->u.groups = grl;
+                       }
+
+                       free(ag->groupusers);
+                       ag->groupusers = NULL;
+               }
+
+#ifdef DEBUG_AUTH
+               for (ag = curuserlist->groups; ag; ag = ag->next) {
+                       struct auth_groups_list *agl;
+
+                       fprintf(stderr, "group %s, id %p, users:", ag->name, ag);
+                       for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
+                               for (agl = curuser->u.groups; agl; agl = agl->next) {
+                                       if (agl->group == ag)
+                                               fprintf(stderr, " %s", curuser->user);
+                               }
+                       }
+                       fprintf(stderr, "\n");
+               }
+#endif
+       }
+
+       return ERR_NONE;
+}
+
 /*
  * Authenticate and authorize user; return 1 if OK, 0 if case of error.
  */
 int
-check_user(struct userlist *ul, unsigned int group_mask, const char *user, const char *pass)
+check_user(struct userlist *ul, const char *user, const char *pass)
 {
 
        struct auth_users *u;
        const char *ep;
 
 #ifdef DEBUG_AUTH
-       fprintf(stderr, "req: userlist=%s, user=%s, pass=%s, group_mask=%u\n",
-               ul->name, user, pass, group_mask);
+       fprintf(stderr, "req: userlist=%s, user=%s, pass=%s, group=%s\n",
+               ul->name, user, pass, group);
 #endif
 
        for (u = ul->users; u; u = u->next)
@@ -137,17 +231,12 @@ check_user(struct userlist *ul, unsigned int group_mask, const char *user, const
                return 0;
 
 #ifdef DEBUG_AUTH
-       fprintf(stderr, "cfg: user=%s, pass=%s, group_mask=%u, flags=%X",
-               u->user, u->pass, u->u.group_mask, u->flags);
+       fprintf(stderr, "cfg: user=%s, pass=%s, flags=%X, groups=",
+               u->user, u->pass, u->flags);
+       for (agl = u->u.groups; agl; agl = agl->next)
+               fprintf(stderr, " %s", agl->group->name);
 #endif
 
-       /*
-        * if user matches but group does not,
-        * it makes no sens to check passwords
-        */
-       if (group_mask && !(group_mask & u->u.group_mask))
-               return 0;
-
        if (!(u->flags & AU_O_INSECURE)) {
 #ifdef CONFIG_HAP_CRYPT
                ep = crypt(pass, u->pass);
@@ -170,14 +259,28 @@ check_user(struct userlist *ul, unsigned int group_mask, const char *user, const
 enum pat_match_res
 pat_match_auth(struct sample *smp, struct pattern *pattern)
 {
-
        struct userlist *ul = smp->ctx.a[0];
-       char *user = smp->ctx.a[1];
-       char *pass = smp->ctx.a[2];
-       unsigned int group_mask = pattern->val.group_mask;
+       struct auth_users *u;
+       struct auth_groups_list *agl;
 
-       if (check_user(ul, group_mask, user, pass))
-               return PAT_MATCH;
-       else
+       /* Check if the userlist is present in the context data. */
+       if (!ul)
+               return PAT_NOMATCH;
+
+       /* Browse the userlist for searching user. */
+       for (u = ul->users; u; u = u->next) {
+               if (strcmp(smp->data.str.str, u->user) == 0)
+                       break;
+       }
+       if (!u)
+               return 0;
+
+       /* Browse each group for searching group name that match the pattern. */
+       for (agl = u->u.groups; agl; agl = agl->next) {
+               if (strcmp(agl->group->name, pattern->ptr.str) == 0)
+                       break;
+       }
+       if (!agl)
                return PAT_NOMATCH;
+       return PAT_MATCH;
 }
index 5cbb9e2a6bc6f0fb78d9a678d0d18703c285076f..10dfa895e7dfc05d137aa26749318ab184ee0a63 100644 (file)
@@ -6248,10 +6248,8 @@ cfg_parse_users(const char *file, int linenum, char **args, int kwm)
                        goto out;
                }
 
-               newul->groupusers = calloc(MAX_AUTH_GROUPS, sizeof(char *));
                newul->name = strdup(args[1]);
-
-               if (!newul->groupusers | !newul->name) {
+               if (!newul->name) {
                        Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
                        err_code |= ERR_ALERT | ERR_ABORT;
                        goto out;
@@ -6261,8 +6259,9 @@ cfg_parse_users(const char *file, int linenum, char **args, int kwm)
                userlist = newul;
 
        } else if (!strcmp(args[0], "group")) {         /* new group */
-               int cur_arg, i;
+               int cur_arg;
                const char *err;
+               struct auth_groups *ag;
 
                if (!*args[1]) {
                        Alert("parsing [%s:%d]: '%s' expects <name> as arguments.\n",
@@ -6279,18 +6278,25 @@ cfg_parse_users(const char *file, int linenum, char **args, int kwm)
                        goto out;
                }
 
-               for(i = 0; i < userlist->grpcnt; i++)
-                       if (!strcmp(userlist->groups[i], args[1])) {
+               for (ag = userlist->groups; ag; ag = ag->next)
+                       if (!strcmp(ag->name, args[1])) {
                                Warning("parsing [%s:%d]: ignoring duplicated group '%s' in userlist '%s'.\n",
                                      file, linenum, args[1], userlist->name);
                                err_code |= ERR_ALERT;
                                goto out;
                        }
 
-               if (userlist->grpcnt >= MAX_AUTH_GROUPS) {
-                       Alert("parsing [%s:%d]: too many groups (%u) in in userlist '%s' while adding group '%s'.\n",
-                             file, linenum, MAX_AUTH_GROUPS, userlist->name, args[1]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
+               ag = calloc(1, sizeof(*ag));
+               if (!ag) {
+                       Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
+                       err_code |= ERR_ALERT | ERR_ABORT;
+                       goto out;
+               }
+
+               ag->name = strdup(args[1]);
+               if (!ag) {
+                       Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
+                       err_code |= ERR_ALERT | ERR_ABORT;
                        goto out;
                }
 
@@ -6298,7 +6304,7 @@ cfg_parse_users(const char *file, int linenum, char **args, int kwm)
 
                while (*args[cur_arg]) {
                        if (!strcmp(args[cur_arg], "users")) {
-                               userlist->groupusers[userlist->grpcnt] = strdup(args[cur_arg + 1]);
+                               ag->groupusers = strdup(args[cur_arg + 1]);
                                cur_arg += 2;
                                continue;
                        } else {
@@ -6309,7 +6315,9 @@ cfg_parse_users(const char *file, int linenum, char **args, int kwm)
                        }
                }
 
-               userlist->groups[userlist->grpcnt++] = strdup(args[1]);
+               ag->next = userlist->groups;
+               userlist->groups = ag;
+
        } else if (!strcmp(args[0], "user")) {          /* new user */
                struct auth_users *newuser;
                int cur_arg;
@@ -6359,7 +6367,7 @@ cfg_parse_users(const char *file, int linenum, char **args, int kwm)
                                cur_arg += 2;
                                continue;
                        } else if (!strcmp(args[cur_arg], "groups")) {
-                               newuser->u.groups = strdup(args[cur_arg + 1]);
+                               newuser->u.groups_names = strdup(args[cur_arg + 1]);
                                cur_arg += 2;
                                continue;
                        } else {
@@ -6602,7 +6610,6 @@ int check_config_validity()
        int cfgerr = 0;
        struct proxy *curproxy = NULL;
        struct server *newsrv = NULL;
-       struct userlist *curuserlist = NULL;
        int err_code = 0;
        unsigned int next_pxid = 1;
        struct bind_conf *bind_conf;
@@ -6623,6 +6630,11 @@ int check_config_validity()
 
        pool2_capture = create_pool("capture", global.tune.cookie_len, MEM_F_SHARED);
 
+       /* Post initialisation of the users and groups lists. */
+       err_code = userlist_postinit();
+       if (err_code != ERR_NONE)
+               goto out;
+
        /* first, we will invert the proxy list order */
        curproxy = NULL;
        while (proxy) {
@@ -7091,7 +7103,9 @@ out_uri_auth_compat:
                        curproxy->conf.args.line = 0;
                }
 
-               /* only now we can check if some args remain unresolved */
+               /* only now we can check if some args remain unresolved.
+                * This must be done after the users and groups resolution.
+                */
                cfgerr += smp_resolve_args(curproxy);
                if (!cfgerr)
                        cfgerr += acl_find_targets(curproxy);
@@ -7680,78 +7694,6 @@ out_uri_auth_compat:
                }
        }
 
-       for (curuserlist = userlist; curuserlist; curuserlist = curuserlist->next) {
-               struct auth_users *curuser;
-               int g;
-
-               for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
-                       unsigned int group_mask = 0;
-                       char *group = NULL;
-
-                       if (!curuser->u.groups)
-                               continue;
-
-                       while ((group = strtok(group?NULL:curuser->u.groups, ","))) {
-
-                               for (g = 0; g < curuserlist->grpcnt; g++)
-                                       if (!strcmp(curuserlist->groups[g], group))
-                                               break;
-
-                               if (g == curuserlist->grpcnt) {
-                                       Alert("userlist '%s': no such group '%s' specified in user '%s'\n",
-                                             curuserlist->name, group, curuser->user);
-                                       err_code |= ERR_ALERT | ERR_FATAL;
-                                       goto out;
-                               }
-
-                               group_mask |= (1 << g);
-                       }
-
-                       free(curuser->u.groups);
-                       curuser->u.group_mask = group_mask;
-               }
-
-               for (g = 0; g < curuserlist->grpcnt; g++) {
-                       char *user = NULL;
-
-                       if (!curuserlist->groupusers[g])
-                               continue;
-
-                       while ((user = strtok(user?NULL:curuserlist->groupusers[g], ","))) {
-                               for (curuser = curuserlist->users; curuser; curuser = curuser->next)
-                                       if (!strcmp(curuser->user, user))
-                                               break;
-
-                               if (!curuser) {
-                                       Alert("userlist '%s': no such user '%s' specified in group '%s'\n",
-                                             curuserlist->name, user, curuserlist->groups[g]);
-                                       err_code |= ERR_ALERT | ERR_FATAL;
-                                       goto out;
-                               }
-
-                               curuser->u.group_mask |= (1 << g);
-                       }
-
-                       free(curuserlist->groupusers[g]);
-               }
-
-               free(curuserlist->groupusers);
-
-#ifdef DEBUG_AUTH
-               for (g = 0; g < curuserlist->grpcnt; g++) {
-                       fprintf(stderr, "group %s, id %d, mask %08X, users:", curuserlist->groups[g], g , 1 << g);
-
-                       for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
-                               if (curuser->u.group_mask & (1 << g))
-                                       fprintf(stderr, " %s", curuser->user);
-                       }
-
-                       fprintf(stderr, "\n");
-               }
-#endif
-
-       }
-
        /* automatically compute fullconn if not set. We must not do it in the
         * loop above because cross-references are not yet fully resolved.
         */
index 306b514b228adae1cc32f6f85620ba1e6d7e9d0d..31df937b57e2b4ac785e963561ae60b19a012c9e 100644 (file)
@@ -242,45 +242,6 @@ int pat_parse_bin(const char **text, struct pattern *pattern, enum pat_usage usa
        return !!parse_binary(*text, &pattern->ptr.str, &pattern->len, err);
 }
 
-/* Parse and concatenate all further strings into one. */
-int
-pat_parse_strcat(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
-{
-       int len = 0, i;
-       char *s;
-       struct chunk *trash;
-
-       for (i = 0; *text[i]; i++)
-               len += strlen(text[i])+1;
-
-       pattern->type = SMP_T_CSTR;
-       if (usage == PAT_U_COMPILE) {
-               pattern->ptr.str = calloc(1, len);
-               if (!pattern->ptr.str) {
-                       memprintf(err, "out of memory while loading pattern");
-                       return 0;
-               }
-       }
-       else {
-               trash = get_trash_chunk();
-               if (trash->size < len) {
-                       memprintf(err, "no space avalaible in the buffer. expect %d, provides %d",
-                                 len, trash->size);
-                       return 0;
-               }
-               pattern->ptr.str = trash->str;
-       }
-
-       s = pattern->ptr.str;
-
-       for (i = 0; *text[i]; i++)
-               s += sprintf(s, i?" %s":"%s", text[i]);
-
-       pattern->len = len;
-
-       return i;
-}
-
 /* Parse a regex. It is allocated. */
 int pat_parse_reg(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
index 0c6a6233f7b370ca687f7d9c7bffda98549d22b4..702ef22fb3365f6579a6c570aa4bed9e02a8115d 100644 (file)
@@ -1361,6 +1361,9 @@ const char *http_parse_reqline(struct http_msg *msg,
  * have the credentials overwritten by another session in parallel.
  */
 
+/* This bufffer is initialized in the file 'src/haproxy.c'. This length is
+ * set according to global.tune.bufsize.
+ */
 char *get_http_auth_buff;
 
 int
@@ -9630,7 +9633,7 @@ smp_fetch_http_auth(struct proxy *px, struct session *l4, void *l7, unsigned int
                return 0;
 
        smp->type = SMP_T_BOOL;
-       smp->data.uint = check_user(args->data.usr, 0, l4->txn.auth.user, l4->txn.auth.pass);
+       smp->data.uint = check_user(args->data.usr, l4->txn.auth.user, l4->txn.auth.pass);
        return 1;
 }
 
@@ -9648,20 +9651,19 @@ smp_fetch_http_auth_grp(struct proxy *px, struct session *l4, void *l7, unsigned
        if (!get_http_auth(l4))
                return 0;
 
-       /* pat_match_auth() will need several information at once */
-       smp->ctx.a[0] = args->data.usr;      /* user list */
-       smp->ctx.a[1] = l4->txn.auth.user;   /* user name */
-       smp->ctx.a[2] = l4->txn.auth.pass;   /* password */
-
        /* if the user does not belong to the userlist or has a wrong password,
         * report that it unconditionally does not match. Otherwise we return
-        * a non-zero integer which will be ignored anyway since all the params
-        * that pat_match_auth() will use are in test->ctx.a[0,1,2].
+        * a string containing the username.
         */
-       smp->type = SMP_T_BOOL;
-       smp->data.uint = check_user(args->data.usr, 0, l4->txn.auth.user, l4->txn.auth.pass);
-       if (smp->data.uint)
-               smp->type = SMP_T_UINT;
+       if (!check_user(args->data.usr, l4->txn.auth.user, l4->txn.auth.pass))
+               return 0;
+
+       /* pat_match_auth() will need the user list */
+       smp->ctx.a[0] = args->data.usr;
+
+       smp->type = SMP_T_CSTR;
+       smp->data.str.str = l4->txn.auth.user;
+       smp->data.str.len = strlen(l4->txn.auth.user);
 
        return 1;
 }
@@ -10371,7 +10373,7 @@ static struct acl_kw_list acl_kws = {ILH, {
        { "hdr_reg",         "req.hdr",       pat_parse_reg,     pat_match_reg     },
        { "hdr_sub",         "req.hdr",       pat_parse_str,     pat_match_sub     },
 
-       { "http_auth_group", NULL,            pat_parse_strcat,  pat_match_auth    },
+       { "http_auth_group", NULL,            pat_parse_str,     pat_match_auth    },
 
        { "method",          NULL,            pat_parse_meth,    pat_match_meth    },
 
@@ -10461,7 +10463,7 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
        { "hdr_val",         smp_fetch_hdr_val,        ARG2(0,STR,SINT), val_hdr, SMP_T_UINT, SMP_USE_HRQHV },
 
        { "http_auth",       smp_fetch_http_auth,      ARG1(1,USR),      NULL,    SMP_T_BOOL, SMP_USE_HRQHV },
-       { "http_auth_group", smp_fetch_http_auth_grp,  ARG1(1,USR),      NULL,    SMP_T_BOOL, SMP_USE_HRQHV },
+       { "http_auth_group", smp_fetch_http_auth_grp,  ARG1(1,USR),      NULL,    SMP_T_CSTR, SMP_USE_HRQHV },
        { "http_first_req",  smp_fetch_http_first_req, 0,                NULL,    SMP_T_BOOL, SMP_USE_HRQHP },
        { "method",          smp_fetch_meth,           0,                NULL,    SMP_T_UINT, SMP_USE_HRQHP },
        { "path",            smp_fetch_path,           0,                NULL,    SMP_T_CSTR, SMP_USE_HRQHV },