From 73e8100e8a3c3c2b93b15ebcce5c69578975572b Mon Sep 17 00:00:00 2001 From: Jim Jagielski Date: Thu, 11 Jul 2013 12:13:13 +0000 Subject: [PATCH] Merge r1457471, r1457504, r1462266, r1468581 from trunk: mod_auth_basic: Add a generic mechanism to fake basic authentication using the ap_expr parser. This allows the administrator to construct their own username and password for basic authentication based on their needs. Alternative fix for PR52616. Remove the Authorization header should either the username or the password resolve to an empty string. * Inherit providers during merging mod_auth_basic: Allow AuthBasicFake to be switched off for an URL space. Submitted by: minfrin, rpluem, minfrin Reviewed/backported by: jim git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1502199 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 11 --- docs/manual/expr.xml | 4 + docs/manual/mod/mod_auth_basic.xml | 71 +++++++++++++ docs/manual/mod/mod_ssl.xml | 5 + modules/aaa/mod_auth_basic.c | 154 +++++++++++++++++++++++++++-- 5 files changed, 228 insertions(+), 17 deletions(-) diff --git a/STATUS b/STATUS index f8c2533e19..430b32d66c 100644 --- a/STATUS +++ b/STATUS @@ -90,17 +90,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - * mod_auth_basic: Add a generic mechanism to fake basic authentication - using the ap_expr parser. This allows the administrator to construct - their own username and password for basic authentication based on their - needs. Alternative fix for PR52616. - trunk patch: http://svn.apache.org/r1457471 - http://svn.apache.org/r1457504 - http://svn.apache.org/r1462266 - http://svn.apache.org/r1468581 - 2.4.x patch: http://people.apache.org/~minfrin/httpd-mod_auth_basic-fake4.patch - +1: minfrin, jim, druggeri - * mod_proxy: Connection header clearing issues trunk patch: https://svn.apache.org/viewvc?view=revision&revision=1481891 https://svn.apache.org/viewvc?view=revision&revision=1482075 diff --git a/docs/manual/expr.xml b/docs/manual/expr.xml index cecd792d13..50eb436fce 100644 --- a/docs/manual/expr.xml +++ b/docs/manual/expr.xml @@ -41,6 +41,10 @@ If ElseIf Else +AuthBasicFake +AuthFormLoginRequiredLocation +AuthFormLoginSuccessLocation +AuthFormLogoutLocation RewriteCond SetEnvIfExpr Header diff --git a/docs/manual/mod/mod_auth_basic.xml b/docs/manual/mod/mod_auth_basic.xml index 8fb11d3ac2..f952476b6e 100644 --- a/docs/manual/mod/mod_auth_basic.xml +++ b/docs/manual/mod/mod_auth_basic.xml @@ -110,4 +110,75 @@ lower level modules + +AuthBasicFake +Fake basic authentication using the given expressions for +username and password +AuthBasicFake off|username [password] +none +directory.htaccess + +AuthConfig + + +

The username and password specified are combined into an + Authorization header, which is passed to the server or service + behind the webserver. Both the username and password fields are + interpreted using the expression parser, + which allows both the username and password to be set based on + request parameters.

+ +

If the password is not specified, the default value "password" + will be used. To disable fake basic authentication for an URL + space, specify "AuthBasicFake off".

+ +

In this example, we pass a fixed username and password to a + backend server.

+ + Fixed Example + +<Location /demo> + AuthBasicFake demo demopass +</Location> + + + +

In this example, we pass the email address extracted from a client + certificate, extending the functionality of the FakeBasicAuth option + within the SSLOptions + directive. Like the FakeBasicAuth option, the password is set to the + fixed string "password".

+ + Certificate Example + +<Location /secure> + AuthBasicFake %{SSL_CLIENT_S_DN_Email} +</Location> + + + +

Extending the above example, we generate a password by hashing the + email address with a fixed passphrase, and passing the hash to the + backend server. This can be used to gate into legacy systems that do + not support client certificates.

+ + Password Example + +<Location /secure> + AuthBasicFake %{SSL_CLIENT_S_DN_Email} %{sha1:passphrase-%{SSL_CLIENT_S_DN_Email}} +</Location> + + + + Exclusion Example + +<Location /public> + AuthBasicFake off +</Location> + + + +
+
+ diff --git a/docs/manual/mod/mod_ssl.xml b/docs/manual/mod/mod_ssl.xml index 75c34497c2..19bd4a5cc0 100644 --- a/docs/manual/mod/mod_ssl.xml +++ b/docs/manual/mod/mod_ssl.xml @@ -1293,6 +1293,11 @@ The available options are:

word `password''. Those who live under MD5-based encryption (for instance under FreeBSD or BSD/OS, etc.) should use the following MD5 hash of the same word: ``$1$OXLyS...$Owx8s2/m9/gfkcRVXzgoE/''.

+ +

Note that the AuthBasicFake + directive within mod_auth_basic can be used as a more + general mechanism for faking basic authentication, giving control over the + structure of both the username and password.

  • StrictRequire

    diff --git a/modules/aaa/mod_auth_basic.c b/modules/aaa/mod_auth_basic.c index cadeb5bda9..19cce78c42 100644 --- a/modules/aaa/mod_auth_basic.c +++ b/modules/aaa/mod_auth_basic.c @@ -29,26 +29,53 @@ #include "http_protocol.h" #include "http_request.h" #include "ap_provider.h" +#include "ap_expr.h" #include "mod_auth.h" typedef struct { authn_provider_list *providers; - char *dir; + char *dir; /* unused variable */ int authoritative; + ap_expr_info_t *fakeuser; + ap_expr_info_t *fakepass; + int fake_set:1; + int authoritative_set:1; } auth_basic_config_rec; static void *create_auth_basic_dir_config(apr_pool_t *p, char *d) { auth_basic_config_rec *conf = apr_pcalloc(p, sizeof(*conf)); - conf->dir = d; /* Any failures are fatal. */ conf->authoritative = 1; return conf; } +static void *merge_auth_basic_dir_config(apr_pool_t *p, void *basev, void *overridesv) +{ + auth_basic_config_rec *newconf = apr_pcalloc(p, sizeof(*newconf)); + auth_basic_config_rec *base = basev; + auth_basic_config_rec *overrides = overridesv; + + newconf->authoritative = + overrides->authoritative_set ? overrides->authoritative : + base->authoritative; + newconf->authoritative_set = overrides->authoritative_set + || base->authoritative_set; + + newconf->fakeuser = + overrides->fake_set ? overrides->fakeuser : base->fakeuser; + newconf->fakepass = + overrides->fake_set ? overrides->fakepass : base->fakepass; + newconf->fake_set = overrides->fake_set || base->fake_set; + + newconf->providers = overrides->providers ? overrides->providers : base->providers; + + return newconf; +} + static const char *add_authn_provider(cmd_parms *cmd, void *config, const char *arg) { @@ -94,15 +121,72 @@ static const char *add_authn_provider(cmd_parms *cmd, void *config, return NULL; } +static const char *set_authoritative(cmd_parms * cmd, void *config, int flag) +{ + auth_basic_config_rec *conf = (auth_basic_config_rec *) config; + + conf->authoritative = flag; + conf->authoritative_set = 1; + + return NULL; +} + +static const char *add_basic_fake(cmd_parms * cmd, void *config, + const char *user, const char *pass) +{ + auth_basic_config_rec *conf = (auth_basic_config_rec *) config; + const char *err; + + if (!strcasecmp(user, "off")) { + + conf->fakeuser = NULL; + conf->fakepass = NULL; + conf->fake_set = 1; + + } + else { + + /* if password is unspecified, set it to the fixed string "password" to + * be compatible with the behaviour of mod_ssl. + */ + if (!pass) { + pass = "password"; + } + + conf->fakeuser = + ap_expr_parse_cmd(cmd, user, AP_EXPR_FLAG_STRING_RESULT, + &err, NULL); + if (err) { + return apr_psprintf(cmd->pool, + "Could not parse fake username expression '%s': %s", user, + err); + } + conf->fakepass = + ap_expr_parse_cmd(cmd, pass, AP_EXPR_FLAG_STRING_RESULT, + &err, NULL); + if (err) { + return apr_psprintf(cmd->pool, + "Could not parse fake password expression '%s': %s", user, + err); + } + conf->fake_set = 1; + + } + + return NULL; +} + static const command_rec auth_basic_cmds[] = { AP_INIT_ITERATE("AuthBasicProvider", add_authn_provider, NULL, OR_AUTHCFG, "specify the auth providers for a directory or location"), - AP_INIT_FLAG("AuthBasicAuthoritative", ap_set_flag_slot, - (void *)APR_OFFSETOF(auth_basic_config_rec, authoritative), - OR_AUTHCFG, + AP_INIT_FLAG("AuthBasicAuthoritative", set_authoritative, NULL, OR_AUTHCFG, "Set to 'Off' to allow access control to be passed along to " "lower modules if the UserID is not known to this module"), + AP_INIT_TAKE12("AuthBasicFake", add_basic_fake, NULL, OR_AUTHCFG, + "Fake basic authentication using the given expressions for " + "username and password, 'off' to disable. Password defaults " + "to 'password' if missing."), {NULL} }; @@ -295,10 +379,68 @@ static int authenticate_basic_user(request_rec *r) return OK; } +/* If requested, create a fake basic authentication header for the benefit + * of a proxy or application running behind this server. + */ +static int authenticate_basic_fake(request_rec *r) +{ + const char *auth_line, *user, *pass, *err; + auth_basic_config_rec *conf = ap_get_module_config(r->per_dir_config, + &auth_basic_module); + + if (!conf->fakeuser) { + return DECLINED; + } + + user = ap_expr_str_exec(r, conf->fakeuser, &err); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02455) + "AuthBasicFake: could not evaluate user expression for URI '%s': %s", r->uri, err); + return HTTP_INTERNAL_SERVER_ERROR; + } + if (!user || !*user) { + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02458) + "AuthBasicFake: empty username expression for URI '%s', ignoring", r->uri); + + apr_table_unset(r->headers_in, "Authorization"); + + return DECLINED; + } + + pass = ap_expr_str_exec(r, conf->fakepass, &err); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02456) + "AuthBasicFake: could not evaluate password expression for URI '%s': %s", r->uri, err); + return HTTP_INTERNAL_SERVER_ERROR; + } + if (!pass || !*pass) { + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02459) + "AuthBasicFake: empty password expression for URI '%s', ignoring", r->uri); + + apr_table_unset(r->headers_in, "Authorization"); + + return DECLINED; + } + + auth_line = apr_pstrcat(r->pool, "Basic ", + ap_pbase64encode(r->pool, + apr_pstrcat(r->pool, user, + ":", pass, NULL)), + NULL); + apr_table_setn(r->headers_in, "Authorization", auth_line); + + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02457) + "AuthBasicFake: \"Authorization: %s\"", + auth_line); + + return OK; +} + static void register_hooks(apr_pool_t *p) { ap_hook_check_authn(authenticate_basic_user, NULL, NULL, APR_HOOK_MIDDLE, AP_AUTH_INTERNAL_PER_CONF); + ap_hook_fixups(authenticate_basic_fake, NULL, NULL, APR_HOOK_LAST); ap_hook_note_auth_failure(hook_note_basic_auth_failure, NULL, NULL, APR_HOOK_MIDDLE); } @@ -307,7 +449,7 @@ AP_DECLARE_MODULE(auth_basic) = { STANDARD20_MODULE_STUFF, create_auth_basic_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ + merge_auth_basic_dir_config, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server config */ auth_basic_cmds, /* command apr_table_t */ -- 2.40.0