mirror of
https://github.com/apache/httpd.git
synced 2025-08-07 04:02:58 +03:00
Add new directive LuaAuthzProvider to allow implementing an
authorization provider in lua git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1351020 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
3
CHANGES
3
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]
|
||||
|
||||
|
@@ -1 +1 @@
|
||||
2313
|
||||
2320
|
||||
|
@@ -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
|
||||
<Location />
|
||||
Require foo 10.1.2.3 john_doe
|
||||
</Location>
|
||||
</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
|
||||
<Location />
|
||||
Require foo bar
|
||||
</Location>
|
||||
</highlight>
|
||||
</example>
|
||||
|
||||
</usage>
|
||||
</directivesynopsis>
|
||||
|
||||
|
||||
</modulesynopsis>
|
||||
|
@@ -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);
|
||||
|
@@ -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) = {
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user