Allow authenticators on filemaps.

This commit introduces the ability to add authenticators to filemaps.
Just like in normal routes, the authenticators will be resolved first
before allowing access to the filemap entries.

Configuration wise, the authenticator is an optional value after the
filemap config directive:

	filemap / webroot myauth

In the Python API you can now pass the authenticator for a filemap entry
but turning the value of the filemap into a tuple with the first entry
being the path and the second being the auth dict:

	AUTH AUTH={
	    "type": "cookie",
	    "value": "cookiename",
	    "redirect": "/auth/",
	    "verify": verify_cookie
	}

	domain.filemaps({
	    "/css/": "webroot/css",
	    "/secret/": ("webroot/secret", AUTH)
	})
This commit is contained in:
Joris Vink 2022-08-10 10:13:01 +02:00
parent 8a0aad31fe
commit 73be741bfd
6 changed files with 64 additions and 19 deletions

View File

@ -352,7 +352,7 @@ domain localhost {
#
# Note the directory given must be relative to the root configuration
# option.
filemap /files/ static_files
filemap /files/ static_files [auth]
}
# Example redirect 80->443.

View File

@ -982,10 +982,11 @@ int kore_msg_register(u_int8_t,
/* filemap.c */
void kore_filemap_init(void);
void kore_filemap_resolve_paths(void);
int kore_filemap_create(struct kore_domain *, const char *,
const char *);
extern char *kore_filemap_ext;
extern char *kore_filemap_index;
struct kore_route *kore_filemap_create(struct kore_domain *, const char *,
const char *, const char *);
#endif
/* fileref.c */

View File

@ -1335,21 +1335,21 @@ configure_redirect(char *options)
static int
configure_filemap(char *options)
{
char *argv[3];
char *argv[4];
if (current_domain == NULL) {
kore_log(LOG_ERR, "filemap keyword not in domain context");
return (KORE_RESULT_ERROR);
}
kore_split_string(options, " ", argv, 3);
kore_split_string(options, " ", argv, 4);
if (argv[0] == NULL || argv[1] == NULL) {
kore_log(LOG_ERR, "missing parameters for filemap");
return (KORE_RESULT_ERROR);
}
if (!kore_filemap_create(current_domain, argv[1], argv[0])) {
if (!kore_filemap_create(current_domain, argv[1], argv[0], argv[2])) {
kore_log(LOG_ERR, "cannot create filemap for %s", argv[1]);
return (KORE_RESULT_ERROR);
}

View File

@ -52,8 +52,9 @@ kore_filemap_init(void)
TAILQ_INIT(&maps);
}
int
kore_filemap_create(struct kore_domain *dom, const char *path, const char *root)
struct kore_route *
kore_filemap_create(struct kore_domain *dom, const char *path,
const char *root, const char *auth)
{
size_t sz;
struct stat st;
@ -64,10 +65,10 @@ kore_filemap_create(struct kore_domain *dom, const char *path, const char *root)
sz = strlen(root);
if (sz == 0)
return (KORE_RESULT_ERROR);
return (NULL);
if (root[0] != '/' || root[sz - 1] != '/')
return (KORE_RESULT_ERROR);
return (NULL);
if (worker_privsep.root != NULL) {
len = snprintf(fpath, sizeof(fpath), "%s/%s",
@ -82,7 +83,7 @@ kore_filemap_create(struct kore_domain *dom, const char *path, const char *root)
if (stat(fpath, &st) == -1) {
kore_log(LOG_ERR, "%s: failed to stat '%s': %s", __func__,
fpath, errno_s);
return (KORE_RESULT_ERROR);
return (NULL);
}
len = snprintf(regex, sizeof(regex), "^%s.*$", root);
@ -90,7 +91,15 @@ kore_filemap_create(struct kore_domain *dom, const char *path, const char *root)
fatal("kore_filemap_create: buffer too small");
if ((rt = kore_route_create(dom, regex, HANDLER_TYPE_DYNAMIC)) == NULL)
return (KORE_RESULT_ERROR);
return (NULL);
if (auth != NULL) {
rt->auth = kore_auth_lookup(auth);
if (rt->auth == NULL) {
fatal("filemap for '%s' has unknown auth '%s'",
path, auth);
}
}
kore_route_callback(rt, "filemap_resolve");
rt->methods = HTTP_METHOD_GET | HTTP_METHOD_HEAD;
@ -109,7 +118,7 @@ kore_filemap_create(struct kore_domain *dom, const char *path, const char *root)
TAILQ_INSERT_TAIL(&maps, entry, list);
return (KORE_RESULT_OK);
return (rt);
}
void

View File

@ -5396,8 +5396,9 @@ static PyObject *
pydomain_filemaps(struct pydomain *domain, PyObject *args)
{
Py_ssize_t idx;
struct kore_route *rt;
const char *url, *path;
PyObject *dict, *key, *value;
PyObject *dict, *key, *value, *auth;
if (!PyArg_ParseTuple(args, "O", &dict))
return (NULL);
@ -5409,22 +5410,56 @@ pydomain_filemaps(struct pydomain *domain, PyObject *args)
idx = 0;
while (PyDict_Next(dict, &idx, &key, &value)) {
if (!PyUnicode_CheckExact(key) ||
!PyUnicode_CheckExact(value)) {
if (!PyUnicode_CheckExact(key)) {
PyErr_SetString(PyExc_RuntimeError,
"filemap entries not strings");
"filemap key not a string");
return (NULL);
}
url = PyUnicode_AsUTF8(key);
if (!PyUnicode_CheckExact(value) &&
!PyTuple_CheckExact(value)) {
PyErr_SetString(PyExc_RuntimeError,
"filemap value can be either be a string or tuple");
return (NULL);
}
if (PyTuple_CheckExact(value)) {
auth = PyTuple_GetItem(value, 1);
if (!PyDict_CheckExact(auth)) {
PyErr_SetString(PyExc_RuntimeError,
"filemap value tuple auth is not a dict");
return (NULL);
}
value = PyTuple_GetItem(value, 0);
if (!PyUnicode_CheckExact(value)) {
PyErr_SetString(PyExc_RuntimeError,
"filemap value tuple path is invalid");
return (NULL);
}
} else {
auth = NULL;
}
path = PyUnicode_AsUTF8(value);
if (!kore_filemap_create(domain->config, path, url)) {
rt = kore_filemap_create(domain->config, path, url, NULL);
if (rt == NULL) {
PyErr_Format(PyExc_RuntimeError,
"failed to create filemap %s->%s for %s",
url, path, domain->config->domain);
return (NULL);
}
if (auth != NULL) {
if (!python_route_auth(auth, rt)) {
kore_python_log_error("python_route_auth");
kore_route_free(rt);
return (KORE_RESULT_ERROR);
}
}
}
Py_RETURN_NONE;

View File

@ -90,6 +90,6 @@ kore_parent_configure(int argc, char *argv[])
dom = kore_domain_new("*");
kore_domain_attach(dom, srv);
if (!kore_filemap_create(dom, rpath, "/"))
if (!kore_filemap_create(dom, rpath, "/", NULL))
fatal("failed to create filemap for %s", rpath);
}