]> granicus.if.org Git - apache-authnz-external/commitdiff
Major revisions to create a new version that works with Apache 2.3 / 2.4
authorjan@unixpapa.com <jan@unixpapa.com@8c465660-3f02-11de-a81c-fde7d73ceb89>
Thu, 6 Oct 2011 14:12:19 +0000 (14:12 +0000)
committerjan@unixpapa.com <jan@unixpapa.com@8c465660-3f02-11de-a81c-fde7d73ceb89>
Thu, 6 Oct 2011 14:12:19 +0000 (14:12 +0000)
mod_authnz_external/AUTHENTICATORS
mod_authnz_external/CHANGES
mod_authnz_external/INSTALL
mod_authnz_external/Makefile
mod_authnz_external/README
mod_authnz_external/UPGRADE
mod_authnz_external/mod_authnz_external.c

index c5bee30947401fbfc9952272712da26764eaac34..734fb535275aa2ed4a6429dd22e897cc3e90dff7 100644 (file)
@@ -1,6 +1,6 @@
             How To Implementation External Authentication Programs
               for mod_authnz_external or mod_auth_external
-                               Version 3.2.0
+                               Version 3.3.x
 
 LANGUAGES
 
index 77b71d59d713447abbf91094c5764b2ab45ef675..10395bf704010e4e565447fdb0bb57986fa8a536 100644 (file)
@@ -1,4 +1,13 @@
-v3.2.6   (Jan Wolter - )
+v3.3.0   (Jan Wolter - Oct 6, 2011)
+----------------------------------------------
+ * Revised to work with Apache 2.3 / 2.4.  Will not work with previous Apache
+   versions.
+ * Deleted 'GroupExternalAuthoritative' and 'AuthzExternalAuthoritative'
+   directives which are obsolete.
+ * Deleted 'GroupExternalError' directive which is superceded by Apache's
+   'AuthzSendForbiddenOnFailure' directive.
+
+v3.2.6   (Jan Wolter - Oct 6, 2011)
 -----------------------------------------------
  * Modified parsing of "Require groups" line so that you can have group
    names that include spaces by enclosing them in quotes.  This change
index 68048036a6a5acf14f91f33fc090b6ce51438cc6..fcf2bba42f64f303b03d088b590789ff2cc0beb6 100644 (file)
@@ -1,5 +1,5 @@
                 How To Install mod_authnz_external.c
-                          Version 3.2.2
+                          Version 3.3.x
 
 NOTES:
 
@@ -7,13 +7,14 @@ NOTES:
    in the INSTALL.HARDCODE file in this directory before following these
    instructions.
 
- * These instructions are for Apache version 2.2.  This version of
+ * These instructions are for Apache version 2.4.  This version of
    mod_authnz_external will not work with older versions of Apache.
    Other versions are available for different releases of Apache:
 
      Apache 1.3   mod_auth_external-2.1.x
      Apache 2.0   mod_auth_external-2.2.x
      Apache 2.2   mod_authnz_external-3.1.x or mod_authnz_external-3.2.x
+     Apache 2.4   mod_authnz_external-3.3.x
 
    You can check your apache version by running it from the command line
    with the -v flag.
@@ -437,7 +438,7 @@ instructions to your server configuration.
        AuthBasicProvider external
        AuthExternal <keyword>
        GroupExternal <groupkeyword>
-       Require group <groupname1> <groupname2> ...
+       Require external-group <groupname1> <groupname2> ...
 
     Here <groupkeyword> matches a name you defined with with the 
     DefineExternalGroup or AddExternalGroup command in step 2.
@@ -462,7 +463,7 @@ instructions to your server configuration.
     owns the file being accessed, you can configure an external group
     checker and then install mod_authz_owner and do:
 
-        Require file-group
+        Require external-file-group
 
     The GroupExternal cannot (yet?) be used with multiple external
     authenticators.
@@ -480,58 +481,30 @@ instructions to your server configuration.
 
     * MODIFYING ERROR CODES FOR GROUP CHECKING:
 
-    Normally, if a group authentication fails, then mod_authnz_external
-    will return a 401 error, which will normally cause the browser to
-    pop up a fresh login box so the user can try logging in with a different
-    ID.  This may not always be appropriate.  If you rejected him because he
-    has a blocked IP address, returning a 403 error, which displays an error
-    page (which you can configure) may be a better choice.  To get a
-    403 error instead of a 401 error on failed group access checks, you
-    would add the following command to your configuration:
+    Normally, if a group authentication fails, then apache will return a
+    401 error, which will normally cause the browser to pop up a fresh
+    login box so the user can try logging in with a different ID.  This
+    may not always be appropriate.  If you rejected him because he has a
+    blocked IP address, returning a 403 error, which displays an error
+    page (which you can configure) may be a better choice than asking him
+    to endlessly try new logins and passwords.
 
-       GroupExternalError 403
-
-    This would effect only group checks, never password checks.  Bad
-    passwords always result in a 401 error.
+    Previous versions of mod_authnz_external had a 'GroupExternalError'
+    directive that allowed you to change this. This no longer exists
+    Under Apache 2.4 you can control the return code using the
+    'AuthzSendForbiddenOnFailure' directive.
 
     * INTERACTIONS WITH OTHER AUTHENTICATORS:
 
-    It is possible to configure more than one different authentication
-    module.  If you do so, you will normally want to make them
-    unauthoritative, so that if one fails, the others will be tried.
-    That way, authentication or access will be granted if ANY of the
-    the configured modules finds it valid.
-
-    If all your password checkers are "authn" modules running under
-    mod_auth_basic, then you need do nothing.  The arbitration among
-    such modules is different than the arbitration between top level
-    modules, and does the right thing by default.  But if some are not
-    "authn" modules, then you'll want to make mod_auth basic
-    unauthoritative with the "AuthBasicAuthoritative off" directive
-    described in the Apache manual.
-
-    If you have multiple group checkers, then you will need to make
-    mod_authnz_external un-authoritative for group checking.  To do
-    this, use the directive:
-
-       GroupExternalAuthoritative off
-
-    Of course, you'll probably also have to make the other module
-    unauthoritative.  For example, if you have a "Require user pete"
-    directive and a "Require group admin" directive and expect it to
-    allow either pete or any admin to login, then you need to make
-    mod_authz_user unauthoritative, because that's what checks
-    "Require user" directives.
-
-    See the Apache manual pages on AuthType, AuthName, AuthBasicProvider,
-    Require, and AuthGroupFile for more information.
-
+    Previous versions of mod_authnz_external had 'GroupExternalAuthoritative'
+    directive. In Apache 2.4, the notion of authoritativeness is
+    thankfully almost entirely gone, so this directive is too.
+    
     * OLD DIRECTIVES
 
     Some of the directives mentioned above used to have different names.
-    The old names still work for backward compatibility.
+    One old name still works for backward compatibility.
 
-       AuthzExternalAuthoritative    equals   GroupExternalAuthoritative
        AuthExternalGroupsAtOnce      equals   GroupExternalManyAtOnce
 
 (4) Install the Authenticator
index d76086d177f6e87a5e8a2fbdb9414ca2315aa736..e1bcfd631a2169a45881aa86d728aec3d0f152bf 100644 (file)
@@ -14,7 +14,7 @@ install: mod_authnz_external.la
 
 build: mod_authnz_external.la
 
-mod_authnz_external.la: 
+mod_authnz_external.la: mod_authnz_external.c
        $(APXS) -c mod_authnz_external.c
 
 clean:
index 61f1133a5d6eabd561f6c4e45296e7267fd3db6d..fe5b5fffd6b206bcd569cceb2a885f0eb78f3d80 100644 (file)
@@ -1,4 +1,4 @@
-                   Mod_Authnz_External version 3.2.5
+                   Mod_Authnz_External version 3.3.x
 
      Original Coder: Nathan Neulinger <nneul@umr.edu>
 Previous Maintainer: Tyler Allison    <allison@nas.nasa.gov>
@@ -18,10 +18,14 @@ caution.
 Versions:
 ---------
 
-Mod_authnz_external version 3.2.x is designed for use with Apache version
-2.2.x.  It will not work with Apache 2.0.  If you have an older version of
-Apache, use instead either mod_auth_external-2.1.x for Apache 1.3, or
-mod_auth_external-2.2.x for Apache 2.2.
+Mod_authnz_external version 3.3.x is designed for use with Apache version
+2.4.x.  It will not work with Apache 2.2 or 2.0.  For older versions of
+Apache you will need older branches of mod_authnz_external:
+
+     Apache 1.3   mod_auth_external-2.1.x
+     Apache 2.0   mod_auth_external-2.2.x
+     Apache 2.2   mod_authnz_external-3.1.x or mod_authnz_external-3.2.x
+     Apache 2.4   mod_authnz_external-3.3.x
 
 This module was developed from "mod_auth_external".  It has been restructured
 to fit into the authn/authz structure introduce in Apache 2.1.  It can be used
index c62899cde088cae76f321c5222d061d097348738..253ca8c24ba7bc6bdf0e33fffb2d167590a1574d 100644 (file)
@@ -49,8 +49,8 @@ How to upgrade from mod_auth_external to mod_authnz_external:
 
         AuthExternalAuthoritative off
 
-     This command will no longer work.  Instead you should use one or both
-     of the following commands:
+     This command will no longer work.  If upgrading to Apache 2.2, you
+     should use one or both of the following commands:
 
         AuthBasicAuthoritative off
         GroupExternalAuthoritative off
@@ -66,6 +66,9 @@ How to upgrade from mod_auth_external to mod_authnz_external:
      group checker was given a chance to decide if the user was in that group
      based on it's group database.
 
+     In Apache 2.4, all of this is handled quite differently. I need to
+     document this.
+
 (6)  If you were using multiple Require directives, the behavior may change
      under Apache 2.2.  Suppose you wanted to allow access to user "pete" and
      members of the group "admins".  You might have do:
@@ -85,6 +88,9 @@ How to upgrade from mod_auth_external to mod_authnz_external:
 
         GroupUserAuthoritative off
 
+     Again, in Apache 2.4, all of this is handled quite differently, and this
+     document needs updating.
+
 (7)  Note that a new type of functionality is available under Apache 2.2 with
      mod_authnz_external.  Thanks to mod_authz_owner, you can now do:
 
@@ -103,3 +109,7 @@ How to upgrade from mod_auth_external to mod_authnz_external:
      being used for http authentication, but for people using 'pwauth'
      with mod_authnz_external, these really check if the user has been
      authenticated as the unix user who owns the file.
+
+     In Apache 2.4, this is the same, except the latter of the two becomes:
+
+         Require external-file-group
index 94e52a3844a3012f62262e62b3c9b6b06d35d5a3..f43f603aa94b22517c49d0aebd302d42d3099a8b 100644 (file)
@@ -119,9 +119,7 @@ typedef struct
     apr_array_header_t *auth_name; /* Auth keyword for current dir */
     char *group_name;           /* Group keyword for current dir */
     char *context;              /* Context string from AuthExternalContext */
-    int  authoritative;                 /* Are we authoritative in current dir? */
     int  groupsatonce;          /* Check all groups in one call in this dir? */
-    char *grouperror;           /* What to return if group auth fails */
 
 } authnz_external_dir_config_rec;
 
@@ -137,6 +135,9 @@ typedef struct
 } authnz_external_svr_config_rec;
 
 
+/* A handle for retrieving the requested file's group from mod_authnz_owner */
+APR_DECLARE_OPTIONAL_FN(char*, authz_owner_get_file_group, (request_rec *r));
+
 /*
  * Creators for per-dir and server configurations.  These are called
  * via the hooks in the module declaration to allocate and initialize
@@ -152,9 +153,7 @@ static void *create_authnz_external_dir_config(apr_pool_t *p, char *d)
     dir->auth_name= apr_array_make(p,2,sizeof(const char *));  /* no default */
     dir->group_name= NULL;     /* no default */
     dir->context= NULL;                /* no default */
-    dir->authoritative= 1;     /* strong by default */
     dir->groupsatonce= 1;      /* default to on */
-    dir->grouperror= NULL;     /* default to 401 */
     return dir;
 }
 
@@ -350,19 +349,6 @@ static const command_rec authnz_external_cmds[] =
        RSRC_CONF,
        "a keyword followed by the method by which the data is passed"),
 
-    AP_INIT_FLAG("GroupExternalAuthoritative",
-       ap_set_flag_slot,
-       (void *)APR_OFFSETOF(authnz_external_dir_config_rec, authoritative),
-       OR_AUTHCFG,
-       "Set to 'off' to allow access control to be passed along to lower "
-           "modules if this module can't confirm access rights" ),
-
-    AP_INIT_FLAG("AuthzExternalAuthoritative",
-       ap_set_flag_slot,
-       (void *)APR_OFFSETOF(authnz_external_dir_config_rec, authoritative),
-       OR_AUTHCFG,
-       "Old version of 'GroupExternalAuthoritative'" ),
-
     AP_INIT_TAKE1("AuthExternalContext",
        ap_set_string_slot,
        (void *)APR_OFFSETOF(authnz_external_dir_config_rec, context),
@@ -370,12 +356,6 @@ static const command_rec authnz_external_cmds[] =
        "An arbitrary context string to pass to the authenticator in the "
        ENV_CONTEXT " environment variable"),
 
-    AP_INIT_TAKE1("GroupExternalError",
-       ap_set_string_slot,
-       (void *)APR_OFFSETOF(authnz_external_dir_config_rec, grouperror),
-       OR_AUTHCFG,
-       "HTTP error code to return when group authentication fails"),
-
     AP_INIT_FLAG("GroupExternalManyAtOnce",
        ap_set_flag_slot,
        (void *)APR_OFFSETOF(authnz_external_dir_config_rec, groupsatonce),
@@ -644,7 +624,8 @@ static int exec_hardcode(const request_rec *r, const char *extpath,
 }
 
 
-static int authz_external_check_user_access(request_rec *r)
+static authz_status externalgroup_check_authorization(request_rec *r,
+       const char *require_args, const void *parsed_require_args)
 {
     authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *)
        ap_get_module_config(r->per_dir_config, &authnz_external_module);
@@ -652,100 +633,104 @@ static int authz_external_check_user_access(request_rec *r)
     authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
        ap_get_module_config(r->server->module_config, &authnz_external_module);
 
-    int i, code, ret;
-    int m= r->method_number;
-    const char *extpath, *extmethod;
+    char *user= r->user;
     char *extname= dir->group_name;
-    int required_group= 0;
+    const char *extpath, *extmethod;
     const char *t, *w;
-    const apr_array_header_t *reqs_arr= ap_requires(r);
-    const char *filegroup= NULL;
-    require_line *reqs;
-
-    /* If no external authenticator has been configured, pass */
-    if ( !extname ) return DECLINED;
+    int code;
 
-    /* If there are no Require arguments, pass */
-    if (!reqs_arr) return DECLINED;
-    reqs=  (require_line *)reqs_arr->elts;
+    /* If no authenticated user, pass */
+    if ( !user ) return AUTHZ_DENIED_NO_USER;
 
+    /* If no external authenticator has been configured, pass */
+    if ( !extname ) return AUTHZ_DENIED;
 
-    /* Loop through the "Require" argument list */
-    for(i= 0; i < reqs_arr->nelts; i++)
+    /* Get the path and method associated with that external */
+    if (!(extpath= apr_table_get(svr->group_path, extname)) ||
+       !(extmethod= apr_table_get(svr->group_method,extname)))
     {
-       if (!(reqs[i].method_mask & (AP_METHOD_BIT << m))) continue;
-
-       t= reqs[i].requirement;
-       w= ap_getword_white(r->pool, &t);
+       errno= 0;
+       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+           "invalid GroupExternal keyword (%s)", extname);
+       return AUTHZ_DENIED;
+    }
 
-       /* The 'file-group' directive causes mod_authz_owner to store the
-        * group name of the file we are trying to access in a note attached
-        * to the request.  It's our job to decide if the user actually is
-        * in that group.  If the note is missing, we just decline.
-        */
-       if ( !strcasecmp(w, "file-group"))
+    if (dir->groupsatonce)
+    {
+       /* Pass rest of require line to authenticator */
+       code= exec_external(extpath, extmethod, r, ENV_GROUP, require_args);
+       if (code == 0) return AUTHZ_GRANTED;
+    }
+    else
+    {
+       /* Call authenticator once for each group name on line */
+       t= require_args;
+       while ((w= ap_getword_conf(r->pool, &t)) && w[0])
        {
-           filegroup= apr_table_get(r->notes, AUTHZ_GROUP_NOTE);
-           if (filegroup == NULL) continue;
+           code= exec_external(extpath, extmethod, r, ENV_GROUP, w);
+           if (code == 0) return AUTHZ_GRANTED;
        }
+    }
 
-       if( !strcmp(w,"group") || filegroup != NULL)
-       {
-           required_group= 1;
-
-           if (t[0] || filegroup != NULL)
-           {
-               /* Get the path and method associated with that external */
-               if (!(extpath= apr_table_get(svr->group_path, extname)) ||
-                   !(extmethod= apr_table_get(svr->group_method,
-                           extname)))
-               {
-                   errno= 0;
-                   ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                       "invalid GroupExternal keyword (%s)", extname);
-                   ap_note_basic_auth_failure(r);
-                   return HTTP_INTERNAL_SERVER_ERROR;
-               }
-
-               if (filegroup != NULL)
-               {
-                   /* Check if user is in the group that owns the file */
-                   code= exec_external(extpath, extmethod, r, ENV_GROUP,
-                           filegroup);
-                   if (code == 0) return OK;
-               }
-               else if (dir->groupsatonce)
-               {
-                   /* Pass rest of require line to authenticator */
-                   code= exec_external(extpath, extmethod, r, ENV_GROUP, t);
-                   if (code == 0) return OK;
-               }
-               else
-               {
-                   /* Call authenticator once for each group name on line */
-                   do {
-                       w= ap_getword_conf(r->pool, &t);
-                       code= exec_external(extpath,
-                               extmethod, r, ENV_GROUP, w);
-                       if (code == 0) return OK;
-                   } while(t[0]);
-               }
-           }
-       }
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+       "Authorization of user %s to access %s failed. "
+       "User not in Required group.",
+       r->user, r->uri);
+
+    return AUTHZ_DENIED;
+}
+
+APR_OPTIONAL_FN_TYPE(authz_owner_get_file_group) *authz_owner_get_file_group;
+
+static authz_status externalfilegroup_check_authorization(request_rec *r,
+       const char *require_args, const void *parsed_require_args)
+{
+    authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *)
+       ap_get_module_config(r->per_dir_config, &authnz_external_module);
+
+    authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
+       ap_get_module_config(r->server->module_config, &authnz_external_module);
+
+    char *user= r->user;
+    char *extname= dir->group_name;
+    const char *extpath, *extmethod;
+    const char *filegroup= NULL;
+    const char *t, *w;
+    int code;
+
+    /* If no authenticated user, pass */
+    if ( !user ) return AUTHZ_DENIED_NO_USER;
+
+    /* If no external authenticator has been configured, pass */
+    if ( !extname ) return AUTHZ_DENIED;
+
+    /* Get the path and method associated with that external */
+    if (!(extpath= apr_table_get(svr->group_path, extname)) ||
+       !(extmethod= apr_table_get(svr->group_method,extname)))
+    {
+       errno= 0;
+       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+           "invalid GroupExternal keyword (%s)", extname);
+       return AUTHZ_DENIED;
     }
 
-    /* If we didn't see a 'require group' or aren't authoritive, decline */
-    if (!required_group || !dir->authoritative)
-       return DECLINED;
+    /* Get group name for requested file from mod_authz_owner */
+    filegroup= authz_owner_get_file_group(r);
 
-    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-       "access to %s failed, reason: user %s not allowed access (%s)",
-       r->uri, r->user, dir->grouperror);
+    if (!filegroup)
+       /* No errog log entry, because mod_authz_owner already made one */
+       return AUTHZ_DENIED;
+
+    /* Pass the group to the external authenticator */
+    code= exec_external(extpath, extmethod, r, ENV_GROUP, filegroup);
+    if (code == 0) return AUTHZ_GRANTED;
 
-    ap_note_basic_auth_failure(r);
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+       "Authorization of user %s to access %s failed. "
+       "User not in Required file group (%s).",
+       r->user, r->uri, filegroup);
 
-    return (dir->grouperror && (ret= atoi(dir->grouperror)) > 0) ? ret :
-       HTTP_UNAUTHORIZED;
+    return AUTHZ_DENIED;
 }
 
 
@@ -831,18 +816,40 @@ static const authn_provider authn_external_provider =
 #endif
 };
 
+static const authz_provider authz_externalgroup_provider =
+{
+    &externalgroup_check_authorization,
+    NULL,
+};
 
-static void register_hooks(apr_pool_t *p)
+static const authz_provider authz_externalfilegroup_provider =
 {
-    ap_register_provider(p, AUTHN_PROVIDER_GROUP, "external", "0",
-           &authn_external_provider);
+    &externalfilegroup_check_authorization,
+    NULL,
+};
 
-    ap_hook_auth_checker(authz_external_check_user_access, NULL, NULL,
-           APR_HOOK_MIDDLE);
+static void register_hooks(apr_pool_t *p)
+{
+    /* Get a handle on mod_authz_owner */
+    authz_owner_get_file_group = APR_RETRIEVE_OPTIONAL_FN(authz_owner_get_file_group);
+
+    /* Register authn provider */
+    ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "external",
+           AUTHN_PROVIDER_VERSION,
+           &authn_external_provider, AP_AUTH_INTERNAL_PER_CONF);
+
+    /* Register authz providers */
+    ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "external-group",
+           AUTHZ_PROVIDER_VERSION,
+           &authz_externalgroup_provider, AP_AUTH_INTERNAL_PER_CONF);
+
+    ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "external-file-group",
+           AUTHZ_PROVIDER_VERSION,
+           &authz_externalfilegroup_provider, AP_AUTH_INTERNAL_PER_CONF);
 }
 
 
-module AP_MODULE_DECLARE_DATA authnz_external_module = {
+AP_DECLARE_MODULE(authnz_external) = {
     STANDARD20_MODULE_STUFF,
     create_authnz_external_dir_config,   /* create per-dir config */
     NULL,                        /* merge per-dir config - dflt is override */