]> granicus.if.org Git - apache/commitdiff
mod_auth_basic: Add a generic mechanism to fake basic authentication
authorGraham Leggett <minfrin@apache.org>
Sun, 17 Mar 2013 16:02:41 +0000 (16:02 +0000)
committerGraham Leggett <minfrin@apache.org>
Sun, 17 Mar 2013 16:02:41 +0000 (16:02 +0000)
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.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1457471 13f79535-47bb-0310-9956-ffa450edef68

docs/log-message-tags/next-number
docs/manual/expr.xml
docs/manual/mod/mod_auth_basic.xml
docs/manual/mod/mod_ssl.xml
modules/aaa/mod_auth_basic.c

index 71398996e7c1fbc53a459a440a04b104631cd093..1db299c003761570b87484285ff82694afa53418 100644 (file)
@@ -1 +1 @@
-2455
+2460
index 8079fd266f880107d8f7d49f7c74b8fc574d153e..790463f8a843af2522ecfc76ce088d7dfe2ccd9e 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 869efa238be4ece04dbdb3e6a212334a54c5db99..299eccaa365a62e90608267920a241ab4873f914 100644 (file)
@@ -109,4 +109,63 @@ 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 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>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} password
+&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>
+
+</usage>
+</directivesynopsis>
+
 </modulesynopsis>
index f748246d9635df0b18c011edceb96e231fd63038..3fbe0314629dd88b96391ec2daa7dd9e01cef9e7 100644 (file)
@@ -1292,6 +1292,11 @@ The available <em>option</em>s are:</p>
     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 569b6050d689c6e73f2b5bffeec6cc85c73f0975..39999f07c20d25378a9ef02e806c957c56835c28 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;
+
+    return newconf;
+}
+
 static const char *add_authn_provider(cmd_parms *cmd, void *config,
                                       const char *arg)
 {
@@ -93,15 +118,50 @@ 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;
+
+    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_TAKE2("AuthBasicFake", add_basic_fake, NULL, OR_AUTHCFG,
+                  "Fake basic authentication using the given expressions for "
+                  "username and password"),
     {NULL}
 };
 
@@ -294,10 +354,62 @@ 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->fake_set) {
+        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);
+        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);
+        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);
 }
@@ -306,7 +418,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 */