qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v7 09/11] authz: add QAuthZListFile object type


From: Philippe Mathieu-Daudé
Subject: Re: [Qemu-devel] [PATCH v7 09/11] authz: add QAuthZListFile object type for a file access control list
Date: Wed, 5 Dec 2018 18:23:24 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.3.1

On 11/30/18 3:06 PM, Daniel P. Berrangé wrote:
> Add a QAuthZListFile object type that implements the QAuthZ interface. This
> built-in implementation is a proxy around the QAuthZList object type,
> initializing it from an external file, and optionally, automatically
> reloading it whenever it changes.
> 
> To create an instance of this object via the QMP monitor, the syntax
> used would be:
> 
>       {
>         "execute": "object-add",
>         "arguments": {
>           "qom-type": "authz-list-file",
>           "id": "authz0",
>           "parameters": {

"parameters" -> "props"

>             "filename": "/etc/qemu/vnc.acl",
>           "refresh": "yes"

I had to use "refresh": yes (value unquoted) to avoid:

{
  "error": {
    "class": "GenericError",
    "desc": "Invalid parameter type for 'refresh', expected: boolean"
  }
}


>           }
>         }
>       }
> 
> If "refresh" is "yes", inotify is used to monitor the file,
> automatically reloading changes. If an error occurs during reloading,
> all authorizations will fail until the file is next successfully
> loaded.
> 
> The /etc/qemu/vnc.acl file would contain a JSON representation of a
> QAuthZList object
> 
>     {
>       "rules": [
>          { "match": "fred", "policy": "allow", "format": "exact" },
>          { "match": "bob", "policy": "allow", "format": "exact" },
>          { "match": "danb", "policy": "deny", "format": "glob" },
>          { "match": "dan*", "policy": "allow", "format": "exact" },
>       ],
>       "policy": "deny"
>     }
> 
> This sets up an authorization rule that allows 'fred', 'bob' and anyone
> whose name starts with 'dan', except for 'danb'. Everyone unmatched is
> denied.
> 
> The object can be loaded on the comand line using
> 
>    -object authz-list-file,id=authz0,filename=/etc/qemu/vnc.acl,refresh=yes
> 
> Signed-off-by: Daniel P. Berrangé <address@hidden>
> ---
>  authz/Makefile.objs         |   1 +
>  authz/listfile.c            | 283 ++++++++++++++++++++++++++++++++++++
>  authz/trace-events          |   4 +
>  include/authz/listfile.h    | 111 ++++++++++++++
>  qemu-options.hx             |  46 ++++++
>  tests/Makefile.include      |   2 +
>  tests/test-authz-listfile.c | 195 +++++++++++++++++++++++++
>  7 files changed, 642 insertions(+)
>  create mode 100644 authz/listfile.c
>  create mode 100644 include/authz/listfile.h
>  create mode 100644 tests/test-authz-listfile.c
> 
> diff --git a/authz/Makefile.objs b/authz/Makefile.objs
> index 921fa624d7..8351bf181d 100644
> --- a/authz/Makefile.objs
> +++ b/authz/Makefile.objs
> @@ -1,3 +1,4 @@
>  authz-obj-y += base.o
>  authz-obj-y += simple.o
>  authz-obj-y += list.o
> +authz-obj-y += listfile.o
> diff --git a/authz/listfile.c b/authz/listfile.c
> new file mode 100644
> index 0000000000..d4579767e7
> --- /dev/null
> +++ b/authz/listfile.c
> @@ -0,0 +1,283 @@
> +/*
> + * QEMU access control list file authorization driver
> + *
> + * Copyright (c) 2018 Red Hat, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see 
> <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "authz/listfile.h"
> +#include "authz/trace.h"
> +#include "qemu/error-report.h"
> +#include "qemu/main-loop.h"
> +#include "qemu/sockets.h"
> +#include "qemu/filemonitor.h"
> +#include "qom/object_interfaces.h"
> +#include "qapi/qapi-visit-authz.h"
> +#include "qapi/qmp/qjson.h"
> +#include "qapi/qmp/qobject.h"
> +#include "qapi/qmp/qerror.h"
> +#include "qapi/qobject-input-visitor.h"
> +
> +
> +static bool
> +qauthz_list_file_is_allowed(QAuthZ *authz,
> +                            const char *identity,
> +                            Error **errp)
> +{
> +    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(authz);
> +    if (fauthz->list) {
> +        return qauthz_is_allowed(fauthz->list, identity, errp);
> +    }
> +
> +    return false;
> +}
> +
> +
> +static QAuthZ *
> +qauthz_list_file_load(QAuthZListFile *fauthz, Error **errp)
> +{
> +    GError *err = NULL;
> +    gchar *content = NULL;
> +    gsize len;
> +    QObject *obj = NULL;
> +    QDict *pdict;
> +    Visitor *v = NULL;
> +    QAuthZ *ret = NULL;
> +
> +    trace_qauthz_list_file_load(fauthz, fauthz->filename);
> +    if (!g_file_get_contents(fauthz->filename, &content, &len, &err)) {
> +        error_setg(errp, "Unable to read '%s': %s",
> +                   fauthz->filename, err->message);
> +        goto cleanup;
> +    }
> +
> +    obj = qobject_from_json(content, errp);
> +    if (!obj) {
> +        goto cleanup;
> +    }
> +
> +    pdict = qobject_to(QDict, obj);
> +    if (!pdict) {
> +        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "obj", "dict");
> +        goto cleanup;
> +    }
> +
> +    v = qobject_input_visitor_new(obj);
> +
> +    ret = (QAuthZ *)user_creatable_add_type(TYPE_QAUTHZ_LIST,
> +                                            NULL, pdict, v, errp);
> +
> + cleanup:
> +    visit_free(v);
> +    qobject_unref(obj);
> +    if (err) {
> +        g_error_free(err);
> +    }
> +    g_free(content);
> +    return ret;
> +}
> +
> +
> +static void
> +qauthz_list_file_event(int wd G_GNUC_UNUSED,
> +                       QFileMonitorEvent ev G_GNUC_UNUSED,
> +                       const char *name G_GNUC_UNUSED,
> +                       void *opaque)
> +{
> +    QAuthZListFile *fauthz = opaque;
> +    Error *err = NULL;
> +
> +    if (ev != QFILE_MONITOR_EVENT_MODIFIED &&
> +        ev != QFILE_MONITOR_EVENT_CREATED) {
> +        return;
> +    }
> +
> +    object_unref(OBJECT(fauthz->list));
> +    fauthz->list = qauthz_list_file_load(fauthz, &err);
> +    trace_qauthz_list_file_refresh(fauthz,
> +                                   fauthz->filename, fauthz->list ? 1 : 0);
> +    if (!fauthz->list) {
> +        error_report_err(err);
> +    }
> +}
> +
> +static void
> +qauthz_list_file_complete(UserCreatable *uc, Error **errp)
> +{
> +    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(uc);
> +    gchar *dir = NULL, *file = NULL;
> +
> +    fauthz->list = qauthz_list_file_load(fauthz, errp);
> +
> +    if (!fauthz->refresh) {
> +        return;
> +    }
> +
> +    fauthz->file_monitor = qemu_file_monitor_new(errp);
> +    if (!fauthz->file_monitor) {
> +        return;
> +    }
> +
> +    dir = g_path_get_dirname(fauthz->filename);
> +    if (g_str_equal(dir, ".")) {
> +        error_setg(errp, "Filename must be an absolute path");
> +        goto cleanup;
> +    }
> +    file = g_path_get_basename(fauthz->filename);
> +    if (g_str_equal(file, ".")) {
> +        error_setg(errp, "Path has no trailing filename component");
> +        goto cleanup;
> +    }
> +
> +    fauthz->file_watch = qemu_file_monitor_add_watch(
> +        fauthz->file_monitor, dir, file,
> +        qauthz_list_file_event, fauthz, errp);
> +    if (fauthz->file_watch < 0) {
> +        goto cleanup;
> +    }
> +
> + cleanup:
> +    g_free(file);
> +    g_free(dir);
> +}
> +
> +
> +static void
> +qauthz_list_file_prop_set_filename(Object *obj,
> +                                   const char *value,
> +                                   Error **errp G_GNUC_UNUSED)
> +{
> +    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
> +
> +    g_free(fauthz->filename);
> +    fauthz->filename = g_strdup(value);
> +}
> +
> +
> +static char *
> +qauthz_list_file_prop_get_filename(Object *obj,
> +                                   Error **errp G_GNUC_UNUSED)
> +{
> +    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
> +
> +    return g_strdup(fauthz->filename);
> +}
> +
> +
> +static void
> +qauthz_list_file_prop_set_refresh(Object *obj,
> +                                  bool value,
> +                                  Error **errp G_GNUC_UNUSED)
> +{
> +    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
> +
> +    fauthz->refresh = value;
> +}
> +
> +
> +static bool
> +qauthz_list_file_prop_get_refresh(Object *obj,
> +                                  Error **errp G_GNUC_UNUSED)
> +{
> +    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
> +
> +    return fauthz->refresh;
> +}
> +
> +
> +static void
> +qauthz_list_file_finalize(Object *obj)
> +{
> +    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
> +
> +    object_unref(OBJECT(fauthz->list));
> +    g_free(fauthz->filename);
> +    qemu_file_monitor_free(fauthz->file_monitor);
> +}
> +
> +
> +static void
> +qauthz_list_file_class_init(ObjectClass *oc, void *data)
> +{
> +    UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
> +    QAuthZClass *authz = QAUTHZ_CLASS(oc);
> +
> +    ucc->complete = qauthz_list_file_complete;
> +
> +    object_class_property_add_str(oc, "filename",
> +                                  qauthz_list_file_prop_get_filename,
> +                                  qauthz_list_file_prop_set_filename,
> +                                  NULL);
> +    object_class_property_add_bool(oc, "refresh",
> +                                   qauthz_list_file_prop_get_refresh,
> +                                   qauthz_list_file_prop_set_refresh,
> +                                   NULL);
> +
> +    authz->is_allowed = qauthz_list_file_is_allowed;
> +}
> +
> +
> +static void
> +qauthz_list_file_init(Object *obj)
> +{
> +    QAuthZListFile *authz = QAUTHZ_LIST_FILE(obj);
> +
> +    authz->file_watch = -1;
> +#ifdef CONFIG_INOTIFY1
> +    authz->refresh = TRUE;
> +#endif
> +}
> +
> +
> +QAuthZListFile *qauthz_list_file_new(const char *id,
> +                                     const char *filename,
> +                                     bool refresh,
> +                                     Error **errp)
> +{
> +    return QAUTHZ_LIST_FILE(
> +        object_new_with_props(TYPE_QAUTHZ_LIST_FILE,
> +                              object_get_objects_root(),
> +                              id, errp,
> +                              "filename", filename,
> +                              "refresh", refresh ? "yes" : "no",
> +                              NULL));
> +}
> +
> +
> +static const TypeInfo qauthz_list_file_info = {
> +    .parent = TYPE_QAUTHZ,
> +    .name = TYPE_QAUTHZ_LIST_FILE,
> +    .instance_init = qauthz_list_file_init,
> +    .instance_size = sizeof(QAuthZListFile),
> +    .instance_finalize = qauthz_list_file_finalize,
> +    .class_size = sizeof(QAuthZListFileClass),
> +    .class_init = qauthz_list_file_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { TYPE_USER_CREATABLE },
> +        { }
> +    }
> +};
> +
> +
> +static void
> +qauthz_list_file_register_types(void)
> +{
> +    type_register_static(&qauthz_list_file_info);
> +}
> +
> +
> +type_init(qauthz_list_file_register_types);
> diff --git a/authz/trace-events b/authz/trace-events
> index a896d876e8..fb65349a90 100644
> --- a/authz/trace-events
> +++ b/authz/trace-events
> @@ -9,3 +9,7 @@ qauthz_simple_is_allowed(void *authz, const char 
> *wantidentity, const char *goti
>  # auth/list.c
>  qauthz_list_check_rule(void *authz, const char *identity, const char *rule, 
> int format, int policy) "AuthZ list %p check rule=%s identity=%s format=%d 
> policy=%d"
>  qauthz_list_default_policy(void *authz, const char *identity, int policy) 
> "AuthZ list %p default identity=%s policy=%d"
> +
> +# auth/listfile.c
> +qauthz_list_file_load(void *authz, const char *filename) "AuthZ file %p load 
> filename=%s"
> +qauthz_list_file_refresh(void *authz, const char *filename, int success) 
> "AuthZ file %p load filename=%s success=%d"
> diff --git a/include/authz/listfile.h b/include/authz/listfile.h
> new file mode 100644
> index 0000000000..80de9fe9c1
> --- /dev/null
> +++ b/include/authz/listfile.h
> @@ -0,0 +1,111 @@
> +/*
> + * QEMU list file authorization driver
> + *
> + * Copyright (c) 2018 Red Hat, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see 
> <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#ifndef QAUTHZ_LIST_FILE_H__
> +#define QAUTHZ_LIST_FILE_H__
> +
> +#include "authz/list.h"
> +#include "qapi/qapi-types-authz.h"
> +#include "qemu/filemonitor.h"
> +
> +#define TYPE_QAUTHZ_LIST_FILE "authz-list-file"
> +
> +#define QAUTHZ_LIST_FILE_CLASS(klass)                        \
> +    OBJECT_CLASS_CHECK(QAuthZListFileClass, (klass),        \
> +                       TYPE_QAUTHZ_LIST_FILE)
> +#define QAUTHZ_LIST_FILE_GET_CLASS(obj)              \
> +    OBJECT_GET_CLASS(QAuthZListFileClass, (obj),    \
> +                      TYPE_QAUTHZ_LIST_FILE)
> +#define QAUTHZ_LIST_FILE(obj) \
> +    INTERFACE_CHECK(QAuthZListFile, (obj),          \
> +                    TYPE_QAUTHZ_LIST_FILE)
> +
> +typedef struct QAuthZListFile QAuthZListFile;
> +typedef struct QAuthZListFileClass QAuthZListFileClass;
> +
> +
> +/**
> + * QAuthZListFile:
> + *
> + * This authorization driver provides a file mechanism
> + * for granting access by matching user names against a
> + * file of globs. Each match rule has an associated policy
> + * and a catch all policy applies if no rule matches
> + *
> + * To create an instance of this class via QMP:
> + *
> + *  {
> + *    "execute": "object-add",
> + *    "arguments": {
> + *      "qom-type": "authz-list-file",
> + *      "id": "authz0",
> + *      "parameters": {

Ditto ...

> + *        "filename": "/etc/qemu/myvm-vnc.acl",
> + *        "refresh": "yes"

Ditto.

> + *      }
> + *    }
> + *  }
> + *
> + * If 'refresh' is 'yes', inotify is used to monitor for changes
> + * to the file and auto-reload the rules.
> + *
> + * The myvm-vnc.acl file should contain the parameters for
> + * the QAuthZList object in JSON format:
> + *
> + *      {
> + *        "rules": [
> + *           { "match": "fred", "policy": "allow", "format": "exact" },
> + *           { "match": "bob", "policy": "allow", "format": "exact" },
> + *           { "match": "danb", "policy": "deny", "format": "exact" },
> + *           { "match": "dan*", "policy": "allow", "format": "glob" }
> + *        ],
> + *        "policy": "deny"
> + *      }
> + *
> + * The object can be created on the command line using
> + *
> + *   -object authz-list-file,id=authz0,\
> + *           filename=/etc/qemu/myvm-vnc.acl,refresh=yes
> + *
> + */
> +struct QAuthZListFile {
> +    QAuthZ parent_obj;
> +
> +    QAuthZ *list;
> +    char *filename;
> +    bool refresh;
> +    QFileMonitor *file_monitor;
> +    int file_watch;
> +};
> +
> +
> +struct QAuthZListFileClass {
> +    QAuthZClass parent_class;
> +};
> +
> +
> +QAuthZListFile *qauthz_list_file_new(const char *id,
> +                                     const char *filename,
> +                                     bool refresh,
> +                                     Error **errp);
> +
> +
> +#endif /* QAUTHZ_LIST_FILE_H__ */
> +
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 7732881e7a..afc90dec2c 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -4427,6 +4427,52 @@ would look like:
>  Note the use of quotes due to the x509 distinguished name containing
>  whitespace, and escaping of ','.
>  
> address@hidden -object 
> authz-listfile,address@hidden,address@hidden,address@hidden|no}
> +
> +Create an authorization object that will control access to network services.
> +
> +The @option{filename} parameter is the fully qualified path to a file
> +containing the access control list rules in JSON format.
> +
> +An example set of rules that match against SASL usernames might look
> +like:
> +
> address@hidden
> +  @{
> +    "rules": [
> +       @{ "match": "fred", "policy": "allow", "format": "exact" @},
> +       @{ "match": "bob", "policy": "allow", "format": "exact" @},
> +       @{ "match": "danb", "policy": "deny", "format": "glob" @},
> +       @{ "match": "dan*", "policy": "allow", "format": "exact" @},
> +    ],
> +    "policy": "deny"
> +  @}
> address@hidden example
> +
> +When checking access the object will iterate over all the rules and
> +the first rule to match will have its @option{policy} value returned
> +as the result. If no rules match, then the default @option{policy}
> +value is returned.
> +
> +The rules can either be an exact string match, or they can use the
> +simple UNIX glob pattern matching to allow wildcards to be used.
> +
> +If @option{refresh} is set to true the file will be monitored
> +and automatically reloaded whenever its content changes.
> +
> +As with the @code{authz-simple} object, the format of the identity
> +strings being matched depends on the network service, but is usually
> +a TLS x509 distinguished name, or a SASL username.
> +
> +An example authorization object to validate a SASL username
> +would look like:
> address@hidden
> + # $QEMU \
> +     ...
> +     -object 
> authz-simple,id=auth0,filename=/etc/qemu/vnc-sasl.acl,refresh=yes
> +     ...
> address@hidden example
> +
>  @end table
>  
>  ETEXI
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 825ea218cb..a3f9134e85 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -114,6 +114,7 @@ check-unit-$(CONFIG_INOTIFY1) += 
> tests/test-util-filemonitor$(EXESUF)
>  check-unit-y += tests/test-util-sockets$(EXESUF)
>  check-unit-y += tests/test-authz-simple$(EXESUF)
>  check-unit-y += tests/test-authz-list$(EXESUF)
> +check-unit-y += tests/test-authz-listfile$(EXESUF)
>  check-unit-y += tests/test-io-task$(EXESUF)
>  check-unit-y += tests/test-io-channel-socket$(EXESUF)
>  check-unit-y += tests/test-io-channel-file$(EXESUF)
> @@ -646,6 +647,7 @@ tests/test-util-sockets$(EXESUF): 
> tests/test-util-sockets.o \
>       tests/socket-helpers.o $(test-util-obj-y)
>  tests/test-authz-simple$(EXESUF): tests/test-authz-simple.o 
> $(test-authz-obj-y)
>  tests/test-authz-list$(EXESUF): tests/test-authz-list.o $(test-authz-obj-y)
> +tests/test-authz-listfile$(EXESUF): tests/test-authz-listfile.o 
> $(test-authz-obj-y)
>  tests/test-io-task$(EXESUF): tests/test-io-task.o $(test-io-obj-y)
>  tests/test-io-channel-socket$(EXESUF): tests/test-io-channel-socket.o \
>          tests/io-channel-helpers.o tests/socket-helpers.o $(test-io-obj-y)
> diff --git a/tests/test-authz-listfile.c b/tests/test-authz-listfile.c
> new file mode 100644
> index 0000000000..1e452fef6d
> --- /dev/null
> +++ b/tests/test-authz-listfile.c
> @@ -0,0 +1,195 @@
> +/*
> + * QEMU list authorization object tests
> + *
> + * Copyright (c) 2018 Red Hat, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see 
> <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/main-loop.h"
> +#include "authz/listfile.h"
> +
> +static char *workdir;
> +
> +static gchar *qemu_authz_listfile_test_save(const gchar *name,
> +                                            const gchar *cfg)
> +{
> +    gchar *path = g_strdup_printf("%s/default-deny.cfg", workdir);
> +    GError *gerr = NULL;
> +
> +    if (!g_file_set_contents(path, cfg, -1, &gerr)) {
> +        g_printerr("Unable to save config %s: %s\n",
> +                   path, gerr->message);
> +        g_error_free(gerr);
> +        g_free(path);
> +        rmdir(workdir);
> +        abort();
> +    }
> +
> +    return path;
> +}
> +
> +static void test_authz_default_deny(void)
> +{
> +    gchar *file = qemu_authz_listfile_test_save(
> +        "default-deny.cfg",
> +        "{ \"policy\": \"deny\" }");
> +    Error *local_err = NULL;
> +
> +    QAuthZListFile *auth = qauthz_list_file_new("auth0",
> +                                                file, false,
> +                                                &local_err);
> +    unlink(file);
> +    g_free(file);
> +    g_assert(local_err == NULL);
> +    g_assert(!qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort));
> +
> +    object_unparent(OBJECT(auth));
> +}
> +
> +static void test_authz_default_allow(void)
> +{
> +    gchar *file = qemu_authz_listfile_test_save(
> +        "default-allow.cfg",
> +        "{ \"policy\": \"allow\" }");
> +    Error *local_err = NULL;
> +
> +    QAuthZListFile *auth = qauthz_list_file_new("auth0",
> +                                                file, false,
> +                                                &local_err);
> +    unlink(file);
> +    g_free(file);
> +    g_assert(local_err == NULL);
> +    g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort));
> +
> +    object_unparent(OBJECT(auth));
> +}
> +
> +static void test_authz_explicit_deny(void)
> +{
> +    gchar *file = qemu_authz_listfile_test_save(
> +        "explicit-deny.cfg",
> +        "{ \"rules\": [ "
> +        "    { \"match\": \"fred\","
> +        "      \"policy\": \"deny\","
> +        "      \"format\": \"exact\" } ],"
> +        "  \"policy\": \"allow\" }");
> +    Error *local_err = NULL;
> +
> +    QAuthZListFile *auth = qauthz_list_file_new("auth0",
> +                                                file, false,
> +                                                &local_err);
> +    unlink(file);
> +    g_free(file);
> +    g_assert(local_err == NULL);
> +
> +    g_assert(!qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort));
> +
> +    object_unparent(OBJECT(auth));
> +}
> +
> +static void test_authz_explicit_allow(void)
> +{
> +    gchar *file = qemu_authz_listfile_test_save(
> +        "explicit-allow.cfg",
> +        "{ \"rules\": [ "
> +        "    { \"match\": \"fred\","
> +        "      \"policy\": \"allow\","
> +        "      \"format\": \"exact\" } ],"
> +        "  \"policy\": \"deny\" }");
> +    Error *local_err = NULL;
> +
> +    QAuthZListFile *auth = qauthz_list_file_new("auth0",
> +                                                file, false,
> +                                                &local_err);
> +    unlink(file);
> +    g_free(file);
> +    g_assert(local_err == NULL);
> +
> +    g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort));
> +
> +    object_unparent(OBJECT(auth));
> +}
> +
> +
> +static void test_authz_complex(void)
> +{
> +    gchar *file = qemu_authz_listfile_test_save(
> +        "complex.cfg",
> +        "{ \"rules\": [ "
> +        "    { \"match\": \"fred\","
> +        "      \"policy\": \"allow\","
> +        "      \"format\": \"exact\" },"
> +        "    { \"match\": \"bob\","
> +        "      \"policy\": \"allow\","
> +        "      \"format\": \"exact\" },"
> +        "    { \"match\": \"dan\","
> +        "      \"policy\": \"deny\","
> +        "      \"format\": \"exact\" },"
> +        "    { \"match\": \"dan*\","
> +        "      \"policy\": \"allow\","
> +        "      \"format\": \"glob\" } ],"
> +        "  \"policy\": \"deny\" }");
> +
> +    Error *local_err = NULL;
> +
> +    QAuthZListFile *auth = qauthz_list_file_new("auth0",
> +                                                file, false,
> +                                                &local_err);
> +    unlink(file);
> +    g_free(file);
> +    g_assert(local_err == NULL);
> +
> +    g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort));
> +    g_assert(qauthz_is_allowed(QAUTHZ(auth), "bob", &error_abort));
> +    g_assert(!qauthz_is_allowed(QAUTHZ(auth), "dan", &error_abort));
> +    g_assert(qauthz_is_allowed(QAUTHZ(auth), "danb", &error_abort));
> +
> +    object_unparent(OBJECT(auth));
> +}
> +
> +
> +int main(int argc, char **argv)
> +{
> +    int ret;
> +    GError *gerr = NULL;
> +
> +    g_test_init(&argc, &argv, NULL);
> +
> +    module_call_init(MODULE_INIT_QOM);
> +
> +    workdir = g_dir_make_tmp("qemu-test-authz-listfile-XXXXXX",
> +                             &gerr);
> +    if (!workdir) {
> +        g_printerr("Unable to create temporary dir: %s\n",
> +                   gerr->message);
> +        g_error_free(gerr);
> +        abort();
> +    }
> +
> +    g_test_add_func("/auth/list/default/deny", test_authz_default_deny);
> +    g_test_add_func("/auth/list/default/allow", test_authz_default_allow);
> +    g_test_add_func("/auth/list/explicit/deny", test_authz_explicit_deny);
> +    g_test_add_func("/auth/list/explicit/allow", test_authz_explicit_allow);
> +    g_test_add_func("/auth/list/complex", test_authz_complex);
> +
> +    ret = g_test_run();
> +
> +    rmdir(workdir);
> +    g_free(workdir);
> +
> +    return ret;
> +}
> 
Tested-by: Philippe Mathieu-Daudé <address@hidden>

Except qauthz_list_file_event() which I'm not confident because I need
to understand better how events works, rest of the patch:
Reviewed-by: Philippe Mathieu-Daudé <address@hidden>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]