]> granicus.if.org Git - apache/commitdiff
Merge r1457471, r1457504, r1462266, r1468581 from trunk:
authorJim Jagielski <jim@apache.org>
Thu, 11 Jul 2013 12:13:13 +0000 (12:13 +0000)
committerJim Jagielski <jim@apache.org>
Thu, 11 Jul 2013 12:13:13 +0000 (12:13 +0000)
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
docs/manual/expr.xml
docs/manual/mod/mod_auth_basic.xml
docs/manual/mod/mod_ssl.xml
modules/aaa/mod_auth_basic.c

diff --git a/STATUS b/STATUS
index f8c2533e1956c4849d1c3919a8e185baa98a35e7..430b32d66c702748d622571b34900b340e646166 100644 (file)
--- 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
index cecd792d1393efd6e2c7ea1f221c232576fc6b34..50eb436fce512213faa90d05b4c7f2a557df6687 100644 (file)
 <seealso><directive module="core" type="section">If</directive></seealso>
 <seealso><directive module="core" type="section">ElseIf</directive></seealso>
 <seealso><directive module="core" type="section">Else</directive></seealso>
+<seealso><directive module="mod_auth_basic">AuthBasicFake</directive></seealso>
+<seealso><directive module="mod_auth_form">AuthFormLoginRequiredLocation</directive></seealso>
+<seealso><directive module="mod_auth_form">AuthFormLoginSuccessLocation</directive></seealso>
+<seealso><directive module="mod_auth_form">AuthFormLogoutLocation</directive></seealso>
 <seealso><directive module="mod_rewrite">RewriteCond</directive></seealso>
 <seealso><directive module="mod_setenvif">SetEnvIfExpr</directive></seealso>
 <seealso><directive module="mod_headers">Header</directive></seealso>
index 8fb11d3ac2fa1f23b44b9db2f8f144c1a96c0eac..f952476b6ed7d1948510e893602708a7a8b7ec27 100644 (file)
@@ -110,4 +110,75 @@ lower level modules</description>
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>AuthBasicFake</name>
+<description>Fake basic authentication using the given expressions for
+username and password</description>
+<syntax>AuthBasicFake off|username [password]</syntax>
+<default>none</default>
+<contextlist><context>directory</context><context>.htaccess</context>
+</contextlist>
+<override>AuthConfig</override>
+
+<usage>
+    <p>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 <a href="../expr.html">expression parser</a>,
+    which allows both the username and password to be set based on
+    request parameters.</p>
+
+    <p>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".</p>
+
+    <p>In this example, we pass a fixed username and password to a
+    backend server.</p>
+
+    <example><title>Fixed Example</title>
+    <highlight language="config">
+&lt;Location /demo&gt;
+    AuthBasicFake demo demopass
+&lt;/Location&gt;
+    </highlight>
+    </example>
+
+    <p>In this example, we pass the email address extracted from a client
+    certificate, extending the functionality of the FakeBasicAuth option
+    within the <directive module="mod_ssl">SSLOptions</directive>
+    directive. Like the FakeBasicAuth option, the password is set to the
+    fixed string "password".</p>
+
+    <example><title>Certificate Example</title>
+    <highlight language="config">
+&lt;Location /secure&gt;
+    AuthBasicFake %{SSL_CLIENT_S_DN_Email}
+&lt;/Location&gt;
+    </highlight>
+    </example>
+
+    <p>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.</p>
+
+    <example><title>Password Example</title>
+    <highlight language="config">
+&lt;Location /secure&gt;
+    AuthBasicFake %{SSL_CLIENT_S_DN_Email} %{sha1:passphrase-%{SSL_CLIENT_S_DN_Email}}
+&lt;/Location&gt;
+    </highlight>
+    </example>
+
+    <example><title>Exclusion Example</title>
+    <highlight language="config">
+&lt;Location /public&gt;
+    AuthBasicFake off
+&lt;/Location&gt;
+    </highlight>
+    </example>
+
+</usage>
+</directivesynopsis>
+
 </modulesynopsis>
index 75c34497c2b8cc07c4b1645c11f0eac23193956a..19bd4a5cc0731ee16f1076353f82668a1fba3c7f 100644 (file)
@@ -1293,6 +1293,11 @@ The available <em>option</em>s are:</p>
     word `<code>password</code>''. 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: ``<code>$1$OXLyS...$Owx8s2/m9/gfkcRVXzgoE/</code>''.</p>
+
+    <p>Note that the <directive module="mod_auth_basic">AuthBasicFake</directive>
+    directive within <module>mod_auth_basic</module> can be used as a more
+    general mechanism for faking basic authentication, giving control over the
+    structure of both the username and password.</p>
 </li>
 <li><code>StrictRequire</code>
     <p>
index cadeb5bda988c3debf0917bd51fd5f5d0d3b04a3..19cce78c42997353c1ab65bc988b39db4cb15795 100644 (file)
 #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 */