How To Install mod_authnz_external.c
- Version 3.2.2
+ Version 3.3.x
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.
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.
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.
* 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
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;
} 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
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;
}
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),
"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),
}
-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);
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;
}
#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 */