You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ji...@apache.org on 2012/08/17 15:45:23 UTC

svn commit: r1374252 - in /httpd/httpd/branches/2.4.x: ./ CHANGES STATUS docs/manual/mod/mod_lua.xml modules/lua/lua_vmprep.c modules/lua/mod_lua.c

Author: jim
Date: Fri Aug 17 13:45:22 2012
New Revision: 1374252

URL: http://svn.apache.org/viewvc?rev=1374252&view=rev
Log:
Merge r1351020, r1370466 from trunk:

Add new directive LuaAuthzProvider to allow implementing an
authorization provider in lua


There is only one global provider name space, therefore allow
LuaAuthzProvider only in global scope.

Remove unnecessary server config field.

Submitted by: sf
Reviewed/backported by: jim

Modified:
    httpd/httpd/branches/2.4.x/   (props changed)
    httpd/httpd/branches/2.4.x/CHANGES
    httpd/httpd/branches/2.4.x/STATUS
    httpd/httpd/branches/2.4.x/docs/manual/mod/mod_lua.xml
    httpd/httpd/branches/2.4.x/modules/lua/lua_vmprep.c
    httpd/httpd/branches/2.4.x/modules/lua/mod_lua.c

Propchange: httpd/httpd/branches/2.4.x/
------------------------------------------------------------------------------
  Merged /httpd/httpd/trunk:r1351020,1370466

Modified: httpd/httpd/branches/2.4.x/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/CHANGES?rev=1374252&r1=1374251&r2=1374252&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.4.x/CHANGES [utf-8] Fri Aug 17 13:45:22 2012
@@ -7,6 +7,9 @@ Changes with Apache 2.4.3
      possible XSS for a site where untrusted users can upload files to
      a location with MultiViews enabled. [Niels Heinen <heinenn google.com>]
 
+  *) mod_lua: Add new directive LuaAuthzProvider to allow implementing an
+     authorization provider in lua. [Stefan Fritsch]
+
   *) httpd.conf: Added configuration directives to set a bad_DNT environment
      variable based on User-Agent and to remove the DNT header field from
      incoming requests when a match occurs. This currently has the effect of

Modified: httpd/httpd/branches/2.4.x/STATUS
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/STATUS?rev=1374252&r1=1374251&r2=1374252&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/STATUS (original)
+++ httpd/httpd/branches/2.4.x/STATUS Fri Aug 17 13:45:22 2012
@@ -88,13 +88,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
-   * mod_lua: Add a Lua authz provider.
-     trunk patch: http://svn.apache.org/viewvc?view=revision&revision=1351020
-                  http://svn.apache.org/viewvc?view=revision&revision=1370466
-     2.4.x patch: trunk patch works.
-     +1: humbedooh, rjung, jim
-     rjung: docs compatibility note 2.5 -> 2.4.3, drop message-tag file from patch
-
    * core: make ap_parse_form_data less strict when checking for a correct 
            Content-Type header when parsing POST, or we risk losing valid 
            data with an appended charset.

Modified: httpd/httpd/branches/2.4.x/docs/manual/mod/mod_lua.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/docs/manual/mod/mod_lua.xml?rev=1374252&r1=1374251&r2=1374252&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/docs/manual/mod/mod_lua.xml (original)
+++ httpd/httpd/branches/2.4.x/docs/manual/mod/mod_lua.xml Fri Aug 17 13:45:22 2012
@@ -130,6 +130,60 @@ handlers (or hooks, or filters) in the s
 
 </section>
 
+<section id="writingauthzproviders">
+<title>Writing Authorization Providers</title>
+
+<p><module>mod_authz_core</module> provides a high-level interface to
+authorization that is much easier to use than using into the relevant
+hooks directly. The first argument to the
+<directive module="mod_authz_core">Require</directive> directive gives
+the name of the responsible authorization provider. For any
+<directive module="mod_authz_core">Require</directive> line,
+<module>mod_authz_core</module> will call the authorization provider
+of the given name, passing the rest of the line as parameters. The
+provider will then check authorization and pass the result as return
+value.</p>
+
+<p>The authz provider is normally called before authentication. If it needs to
+know the authenticated user name (or if the user will be authenticated at
+all), the provider must return <code>apache2.AUTHZ_DENIED_NO_USER</code>.
+This will cause authentication to proceed and the authz provider to be
+called a second time.</p>
+
+<p>The following authz provider function takes two arguments, one ip
+address and one user name. It will allow access from the given ip address
+without authentication, or if the authenticated user matches the second
+argument:</p>
+
+<highlight language="lua">
+<strong>authz_provider.lua</strong>
+
+require 'apache2'
+
+function authz_check_foo(r, ip, user)
+    if r.useragent_ip == ip then
+        return apache2.AUTHZ_GRANTED
+    elseif r.user == nil then
+        return apache2.AUTHZ_DENIED_NO_USER
+    elseif r.user == user then
+        return apache2.AUTHZ_GRANTED
+    else
+        return apache2.AUTHZ_DENIED
+    end
+end
+</highlight>
+
+<p>The following configuration registers this function as provider
+<code>foo</code> and configures it for URL <code>/</code>:</p>
+<highlight language="config">
+LuaAuthzProvider foo authz_provider.lua authz_check_foo
+&lt;Location /&gt;
+  Require foo 10.1.2.3 john_doe
+&lt;/Location&gt;
+</highlight>
+
+</section>
+
 <section id="writinghooks"><title>Writing Hooks</title>
 
 <p>Hook functions are how modules (and Lua scripts) participate in the
@@ -798,4 +852,30 @@ hook function usually returns OK, DECLIN
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>LuaAuthzProvider</name>
+<description>Plug an authorization provider function into <module>mod_authz_core</module>
+</description>
+<syntax>LuaAuthzProvider provider_name /path/to/lua/script.lua function_name</syntax>
+<contextlist><context>server config</context> </contextlist>
+<compatibility>2.5.0 and later</compatibility>
+
+<usage>
+<p>After a lua function has been registered as authorization provider, it can be used
+with the <directive module="mod_authz_core">Require</directive> directive:</p>
+
+<example>
+<highlight language="config">
+LuaRoot /usr/local/apache2/lua
+LuaAuthzProvider foo authz.lua authz_check_foo
+&lt;Location /&gt;
+  Require foo bar
+&lt;/Location&gt;
+</highlight>
+</example>
+
+</usage>
+</directivesynopsis>
+
+
 </modulesynopsis>

Modified: httpd/httpd/branches/2.4.x/modules/lua/lua_vmprep.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/lua/lua_vmprep.c?rev=1374252&r1=1374251&r2=1374252&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/lua/lua_vmprep.c (original)
+++ httpd/httpd/branches/2.4.x/modules/lua/lua_vmprep.c Fri Aug 17 13:45:22 2012
@@ -19,6 +19,7 @@
 #include "apr_uuid.h"
 #include "lua_config.h"
 #include "apr_file_info.h"
+#include "mod_auth.h"
 
 APLOG_USE_MODULE(lua);
 
@@ -121,6 +122,11 @@ AP_LUA_DECLARE(void) ap_lua_load_apache2
     makeintegerfield(L, PROXYREQ_REVERSE);
     makeintegerfield(L, PROXYREQ_RESPONSE);
     makeintegerfield(L, PROXYREQ_RESPONSE);
+    makeintegerfield(L, AUTHZ_DENIED);
+    makeintegerfield(L, AUTHZ_GRANTED);
+    makeintegerfield(L, AUTHZ_NEUTRAL);
+    makeintegerfield(L, AUTHZ_GENERAL_ERROR);
+    makeintegerfield(L, AUTHZ_DENIED_NO_USER);
 
     /*
        makeintegerfield(L, HTTP_CONTINUE);

Modified: httpd/httpd/branches/2.4.x/modules/lua/mod_lua.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/lua/mod_lua.c?rev=1374252&r1=1374251&r2=1374252&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/lua/mod_lua.c (original)
+++ httpd/httpd/branches/2.4.x/modules/lua/mod_lua.c Fri Aug 17 13:45:22 2012
@@ -24,6 +24,7 @@
 #include "lua_config.h"
 #include "apr_optional.h"
 #include "mod_ssl.h"
+#include "mod_auth.h"
 
 #ifdef APR_HAS_THREADS
 #include "apr_thread_proc.h"
@@ -39,11 +40,22 @@ APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap_l
 static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *lua_ssl_val = NULL;
 static APR_OPTIONAL_FN_TYPE(ssl_is_https) *lua_ssl_is_https = NULL;
 
-     module AP_MODULE_DECLARE_DATA lua_module;
+module AP_MODULE_DECLARE_DATA lua_module;
 
 #define AP_LUA_HOOK_FIRST (APR_HOOK_FIRST - 1)
 #define AP_LUA_HOOK_LAST  (APR_HOOK_LAST  + 1)
 
+typedef struct {
+    const char *name;
+    const char *file_name;
+    const char *function_name;
+    ap_lua_vm_spec *spec;
+    apr_array_header_t *args;
+} lua_authz_provider_spec;
+
+apr_hash_t *lua_authz_providers;
+
+
 /**
  * error reporting if lua has an error.
  * Extracts the error from lua stack and prints
@@ -128,7 +140,7 @@ static ap_lua_vm_spec *create_vm_spec(ap
     else {
         spec->file = r->filename;
     }
-    ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, APLOGNO()
+    ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, APLOGNO(02313)
                   "%s details: scope: %s, file: %s, func: %s",
                   what, scope_to_string(spec->scope), spec->file,
                   function ? function : "-");
@@ -964,6 +976,131 @@ AP_LUA_DECLARE(int) ap_lua_ssl_is_https(
 
 /*******************************/
 
+static const char *lua_authz_parse(cmd_parms *cmd, const char *require_line,
+                                   const void **parsed_require_line)
+{
+    const char *provider_name;
+    lua_authz_provider_spec *spec;
+
+    apr_pool_userdata_get((void**)&provider_name, AUTHZ_PROVIDER_NAME_NOTE,
+                          cmd->temp_pool);
+    ap_assert(provider_name != NULL);
+
+    spec = apr_hash_get(lua_authz_providers, provider_name, APR_HASH_KEY_STRING);
+    ap_assert(spec != NULL);
+
+    if (require_line && *require_line) {
+        const char *arg;
+        spec->args = apr_array_make(cmd->pool, 2, sizeof(const char *));
+        while ((arg = ap_getword_conf(cmd->pool, &require_line)) && *arg) {
+            APR_ARRAY_PUSH(spec->args, const char *) = arg;
+        }
+    }
+
+    *parsed_require_line = spec;
+    return NULL;
+}
+
+static authz_status lua_authz_check(request_rec *r, const char *require_line,
+                                    const void *parsed_require_line)
+{
+    apr_pool_t *pool;
+    ap_lua_vm_spec *spec;
+    lua_State *L;
+    ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config,
+                                                         &lua_module);
+    const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
+                                                     &lua_module);
+    const lua_authz_provider_spec *prov_spec = parsed_require_line;
+    int result;
+    int nargs = 0;
+
+    spec = create_vm_spec(&pool, r, cfg, server_cfg, prov_spec->file_name,
+                          NULL, 0, prov_spec->function_name, "authz provider");
+
+    L = ap_lua_get_lua_state(pool, spec);
+    if (L == NULL) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02314)
+                      "Unable to compile VM for authz provider %s", prov_spec->name);
+        return AUTHZ_GENERAL_ERROR;
+    }
+    lua_getglobal(L, prov_spec->function_name);
+    if (!lua_isfunction(L, -1)) {
+        ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02319)
+                      "Unable to find function %s in %s",
+                      prov_spec->function_name, prov_spec->file_name);
+        return AUTHZ_GENERAL_ERROR;
+    }
+    ap_lua_run_lua_request(L, r);
+    if (prov_spec->args) {
+        int i;
+        if (!lua_checkstack(L, prov_spec->args->nelts)) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02315)
+                          "Error: authz provider %s: too many arguments", prov_spec->name);
+            return AUTHZ_GENERAL_ERROR;
+        }
+        for (i = 0; i < prov_spec->args->nelts; i++) {
+            const char *arg = APR_ARRAY_IDX(prov_spec->args, i, const char *);
+            lua_pushstring(L, arg);
+        }
+        nargs = prov_spec->args->nelts;
+    }
+    if (lua_pcall(L, 1 + nargs, 1, 0)) {
+        const char *err = lua_tostring(L, -1);
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02316)
+                      "Error executing authz provider %s: %s", prov_spec->name, err);
+        return AUTHZ_GENERAL_ERROR;
+    }
+    if (!lua_isnumber(L, -1)) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02317)
+                      "Error: authz provider %s did not return integer", prov_spec->name);
+        return AUTHZ_GENERAL_ERROR;
+    }
+    result = lua_tointeger(L, -1);
+    switch (result) {
+        case AUTHZ_DENIED:
+        case AUTHZ_GRANTED:
+        case AUTHZ_NEUTRAL:
+        case AUTHZ_GENERAL_ERROR:
+        case AUTHZ_DENIED_NO_USER:
+            return result;
+        default:
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02318)
+                          "Error: authz provider %s: invalid return value %d",
+                          prov_spec->name, result);
+    }
+    return AUTHZ_GENERAL_ERROR;
+}
+
+static const authz_provider lua_authz_provider =
+{
+    &lua_authz_check,
+    &lua_authz_parse,
+};
+
+static const char *register_authz_provider(cmd_parms *cmd, void *_cfg,
+                                           const char *name, const char *file,
+                                           const char *function)
+{
+    lua_authz_provider_spec *spec;
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err)
+        return err;
+
+    spec = apr_pcalloc(cmd->pool, sizeof(*spec));
+    spec->name = name;
+    spec->file_name = file;
+    spec->function_name = function;
+
+    apr_hash_set(lua_authz_providers, name, APR_HASH_KEY_STRING, spec);
+    ap_register_auth_provider(cmd->pool, AUTHZ_PROVIDER_GROUP, name,
+                              AUTHZ_PROVIDER_VERSION,
+                              &lua_authz_provider,
+                              AP_AUTH_INTERNAL_PER_CONF);
+    return NULL;
+}
+
+
 command_rec lua_commands[] = {
 
     AP_INIT_TAKE1("LuaRoot", register_lua_root, NULL, OR_ALL,
@@ -975,6 +1112,8 @@ command_rec lua_commands[] = {
     AP_INIT_TAKE1("LuaPackageCPath", register_package_cdir, NULL, OR_ALL,
                   "Add a directory to lua's package.cpath"),
 
+    AP_INIT_TAKE3("LuaAuthzProvider", register_authz_provider, NULL, RSRC_CONF|EXEC_ON_READ,
+                  "Provide an authorization provider"),
 
     AP_INIT_TAKE23("LuaHookTranslateName", register_translate_name_hook, NULL,
                   OR_ALL,
@@ -1207,6 +1346,9 @@ static void lua_register_hooks(apr_pool_
 
     APR_OPTIONAL_HOOK(ap_lua, lua_request, lua_request_hook, NULL, NULL,
                       APR_HOOK_REALLY_FIRST);
+
+    /* providers */
+    lua_authz_providers = apr_hash_make(p);
 }
 
 AP_DECLARE_MODULE(lua) = {