]> granicus.if.org Git - apache/commitdiff
Add new directive LuaAuthzProvider to allow implementing an
authorStefan Fritsch <sf@apache.org>
Sat, 16 Jun 2012 22:51:19 +0000 (22:51 +0000)
committerStefan Fritsch <sf@apache.org>
Sat, 16 Jun 2012 22:51:19 +0000 (22:51 +0000)
authorization provider in lua

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

CHANGES
docs/log-message-tags/next-number
docs/manual/mod/mod_lua.xml
modules/lua/lua_vmprep.c
modules/lua/mod_lua.c
modules/lua/mod_lua.h

diff --git a/CHANGES b/CHANGES
index e584188ba5b4e917b9ed960955de12d2db17864e..e43b479346b3d770702ad7f84f0761423ea5034f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,9 @@ Changes with Apache 2.5.0
      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]
+
   *) mod_lua: Add a few missing request_rec fields. Rename remote_ip to
      client_ip to match conn_rec. [Stefan Fritsch]
 
index 2612554b2d3af3f615fa8cf39107edf476895621..ed5edbf7f250df6988af2336a10534f55183d568 100644 (file)
@@ -1 +1 @@
-2313
+2320
index fe3b0b8f13b9d2e8e2dff0c9671f2343c04c3344..abb531d34f7bebc1e9f15d987ea777a250023644 100644 (file)
@@ -130,6 +130,60 @@ handlers (or hooks, or filters) in the same script.
 
 </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
@@ -795,4 +849,30 @@ hook function usually returns OK, DECLINED, or HTTP_FORBIDDEN.</p>
 </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>
index e3c5be99f79a8c5e54d6bff189d6269d76206805..7447337faefa381fe52501cbc30275d3dac4b77f 100644 (file)
@@ -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_lmodule(lua_State *L)
     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);
index 18553eb212ee1cd7465567ae236c9df8bab5b6d6..115afc64b6b15fc6720362320a4dc0ace45e7d8f 100644 (file)
@@ -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_lua, AP_LUA, int, lua_request,
 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(apr_pool_t **lifecycle_pool,
     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 : "-");
@@ -965,6 +977,131 @@ AP_LUA_DECLARE(int) ap_lua_ssl_is_https(conn_rec *c)
 
 /*******************************/
 
+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, NOT_IN_DIR_LOC_FILE);
+    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,
@@ -976,6 +1113,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,
@@ -1208,6 +1347,9 @@ static void lua_register_hooks(apr_pool_t *p)
 
     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) = {
index 2504b029a7f719f45a94fa5d288f94754b3adcb6..77020ab16fa121499411326be03766615ff06aa6 100644 (file)
@@ -127,6 +127,8 @@ typedef struct
 
     /* value of the LuaRoot directive */
     const char *root_path;
+
+    apr_hash_t *authz_providers;
 } ap_lua_server_cfg;
 
 typedef struct