From 310b8eb0102ea2f60d0a72396112943ff9cd9813 Mon Sep 17 00:00:00 2001 From: "jan@unixpapa.com" Date: Thu, 6 Oct 2011 14:12:19 +0000 Subject: [PATCH] Major revisions to create a new version that works with Apache 2.3 / 2.4 --- mod_authnz_external/AUTHENTICATORS | 2 +- mod_authnz_external/CHANGES | 11 +- mod_authnz_external/INSTALL | 69 ++----- mod_authnz_external/Makefile | 2 +- mod_authnz_external/README | 14 +- mod_authnz_external/UPGRADE | 14 +- mod_authnz_external/mod_authnz_external.c | 225 +++++++++++----------- 7 files changed, 170 insertions(+), 167 deletions(-) diff --git a/mod_authnz_external/AUTHENTICATORS b/mod_authnz_external/AUTHENTICATORS index c5bee30..734fb53 100644 --- a/mod_authnz_external/AUTHENTICATORS +++ b/mod_authnz_external/AUTHENTICATORS @@ -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 diff --git a/mod_authnz_external/CHANGES b/mod_authnz_external/CHANGES index 77b71d5..10395bf 100644 --- a/mod_authnz_external/CHANGES +++ b/mod_authnz_external/CHANGES @@ -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 diff --git a/mod_authnz_external/INSTALL b/mod_authnz_external/INSTALL index 6804803..fcf2bba 100644 --- a/mod_authnz_external/INSTALL +++ b/mod_authnz_external/INSTALL @@ -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 GroupExternal - Require group ... + Require external-group ... Here 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 diff --git a/mod_authnz_external/Makefile b/mod_authnz_external/Makefile index d76086d..e1bcfd6 100644 --- a/mod_authnz_external/Makefile +++ b/mod_authnz_external/Makefile @@ -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: diff --git a/mod_authnz_external/README b/mod_authnz_external/README index 61f1133..fe5b5ff 100644 --- a/mod_authnz_external/README +++ b/mod_authnz_external/README @@ -1,4 +1,4 @@ - Mod_Authnz_External version 3.2.5 + Mod_Authnz_External version 3.3.x Original Coder: Nathan Neulinger Previous Maintainer: Tyler Allison @@ -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 diff --git a/mod_authnz_external/UPGRADE b/mod_authnz_external/UPGRADE index c62899c..253ca8c 100644 --- a/mod_authnz_external/UPGRADE +++ b/mod_authnz_external/UPGRADE @@ -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 diff --git a/mod_authnz_external/mod_authnz_external.c b/mod_authnz_external/mod_authnz_external.c index 94e52a3..f43f603 100644 --- a/mod_authnz_external/mod_authnz_external.c +++ b/mod_authnz_external/mod_authnz_external.c @@ -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 */ -- 2.40.0