From 73be741bfd2e4ed144923d5150e737d84573f823 Mon Sep 17 00:00:00 2001 From: Joris Vink Date: Wed, 10 Aug 2022 10:13:01 +0200 Subject: [PATCH] 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) }) --- 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 index c6a1517..86b0376 100644 --- 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 index 62f2c22..e129fb0 100644 --- 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 index 25a7ef3..dac7488 100644 --- 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 index 628b72f..ab6079a 100644 --- 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 index a2a29ca..5cb032c 100644 --- 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 index 5ad9157..cb57638 100644 --- 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); }