kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit 73be741bfd2e4ed144923d5150e737d84573f823
parent 8a0aad31fe7f3c46426782531cbe68accaba8baa
Author: Joris Vink <joris@coders.se>
Date:   Wed, 10 Aug 2022 10:13:01 +0200

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)
	})

Diffstat:
conf/kore.conf.example | 2+-
include/kore/kore.h | 5+++--
src/config.c | 6+++---
src/filemap.c | 23++++++++++++++++-------
src/python.c | 45++++++++++++++++++++++++++++++++++++++++-----
tools/kore-serve/src/kore-serve.c | 2+-
6 files changed, 64 insertions(+), 19 deletions(-)

diff --git a/conf/kore.conf.example b/conf/kore.conf.example @@ -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. diff --git a/include/kore/kore.h b/include/kore/kore.h @@ -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 */ diff --git a/src/config.c b/src/config.c @@ -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); } diff --git a/src/filemap.c b/src/filemap.c @@ -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 diff --git a/src/python.c b/src/python.c @@ -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; diff --git a/tools/kore-serve/src/kore-serve.c b/tools/kore-serve/src/kore-serve.c @@ -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); }