From 711d2d431b27b7232de735c6f96b39cd94dd23c6 Mon Sep 17 00:00:00 2001 From: Martin Schanzenbach Date: Fri, 20 Oct 2023 00:06:56 +0200 Subject: REST: Remove plugins. Hardcode features --- src/Makefile.am | 1 - src/include/gnunet_rest_plugin.h | 21 +- src/meson.build | 1 - src/rest-plugin/Makefile.am | 6 - src/rest-plugin/gns/Makefile.am | 61 - src/rest-plugin/gns/meson.build | 13 - src/rest-plugin/gns/plugin_rest_gns.c | 485 --- src/rest-plugin/gns/test_plugin_rest_gns.sh | 76 - src/rest-plugin/identity/Makefile.am | 26 - src/rest-plugin/identity/meson.build | 11 - src/rest-plugin/identity/plugin_rest_identity.c | 1286 -------- src/rest-plugin/meson.build | 7 - src/rest-plugin/namestore/Makefile.am | 53 - src/rest-plugin/namestore/meson.build | 14 - src/rest-plugin/namestore/plugin_rest_namestore.c | 1364 --------- src/rest-plugin/reclaim/Makefile.am | 81 - src/rest-plugin/reclaim/json_reclaim.c | 398 --- src/rest-plugin/reclaim/json_reclaim.h | 57 - src/rest-plugin/reclaim/meson.build | 29 - src/rest-plugin/reclaim/oidc_helper.c | 1026 ------- src/rest-plugin/reclaim/oidc_helper.h | 196 -- .../reclaim/plugin_rest_openid_connect.c | 3162 ------------------- src/rest-plugin/reclaim/plugin_rest_pabc.c | 667 ---- src/rest-plugin/reclaim/plugin_rest_reclaim.c | 1564 ---------- src/rest-plugin/rest/Makefile.am | 37 - src/rest-plugin/rest/meson.build | 18 - src/rest-plugin/rest/plugin_rest_config.c | 455 --- src/rest-plugin/rest/plugin_rest_copying.c | 238 -- src/service/Makefile.am | 4 +- src/service/meson.build | 4 +- src/service/rest/Makefile.am | 18 +- src/service/rest/config_plugin.c | 438 +++ src/service/rest/config_plugin.h | 37 + src/service/rest/copying_plugin.c | 233 ++ src/service/rest/copying_plugin.h | 36 + src/service/rest/gns_plugin.c | 486 +++ src/service/rest/gns_plugin.h | 36 + src/service/rest/gnunet-rest-server.c | 145 +- src/service/rest/identity_plugin.c | 1287 ++++++++ src/service/rest/identity_plugin.h | 36 + src/service/rest/json_reclaim.c | 398 +++ src/service/rest/json_reclaim.h | 57 + src/service/rest/meson.build | 26 +- src/service/rest/namestore_plugin.c | 1364 +++++++++ src/service/rest/namestore_plugin.h | 37 + src/service/rest/oidc_helper.c | 1026 +++++++ src/service/rest/oidc_helper.h | 196 ++ src/service/rest/openid_plugin.c | 3169 ++++++++++++++++++++ src/service/rest/openid_plugin.h | 36 + src/service/rest/pabc_plugin.c | 667 ++++ src/service/rest/reclaim_plugin.c | 1565 ++++++++++ src/service/rest/reclaim_plugin.h | 36 + 52 files changed, 11299 insertions(+), 11391 deletions(-) delete mode 100644 src/rest-plugin/Makefile.am delete mode 100644 src/rest-plugin/gns/Makefile.am delete mode 100644 src/rest-plugin/gns/meson.build delete mode 100644 src/rest-plugin/gns/plugin_rest_gns.c delete mode 100755 src/rest-plugin/gns/test_plugin_rest_gns.sh delete mode 100644 src/rest-plugin/identity/Makefile.am delete mode 100644 src/rest-plugin/identity/meson.build delete mode 100644 src/rest-plugin/identity/plugin_rest_identity.c delete mode 100644 src/rest-plugin/meson.build delete mode 100644 src/rest-plugin/namestore/Makefile.am delete mode 100644 src/rest-plugin/namestore/meson.build delete mode 100644 src/rest-plugin/namestore/plugin_rest_namestore.c delete mode 100644 src/rest-plugin/reclaim/Makefile.am delete mode 100644 src/rest-plugin/reclaim/json_reclaim.c delete mode 100644 src/rest-plugin/reclaim/json_reclaim.h delete mode 100644 src/rest-plugin/reclaim/meson.build delete mode 100644 src/rest-plugin/reclaim/oidc_helper.c delete mode 100644 src/rest-plugin/reclaim/oidc_helper.h delete mode 100644 src/rest-plugin/reclaim/plugin_rest_openid_connect.c delete mode 100644 src/rest-plugin/reclaim/plugin_rest_pabc.c delete mode 100644 src/rest-plugin/reclaim/plugin_rest_reclaim.c delete mode 100644 src/rest-plugin/rest/Makefile.am delete mode 100644 src/rest-plugin/rest/meson.build delete mode 100644 src/rest-plugin/rest/plugin_rest_config.c delete mode 100644 src/rest-plugin/rest/plugin_rest_copying.c create mode 100644 src/service/rest/config_plugin.c create mode 100644 src/service/rest/config_plugin.h create mode 100644 src/service/rest/copying_plugin.c create mode 100644 src/service/rest/copying_plugin.h create mode 100644 src/service/rest/gns_plugin.c create mode 100644 src/service/rest/gns_plugin.h create mode 100644 src/service/rest/identity_plugin.c create mode 100644 src/service/rest/identity_plugin.h create mode 100644 src/service/rest/json_reclaim.c create mode 100644 src/service/rest/json_reclaim.h create mode 100644 src/service/rest/namestore_plugin.c create mode 100644 src/service/rest/namestore_plugin.h create mode 100644 src/service/rest/oidc_helper.c create mode 100644 src/service/rest/oidc_helper.h create mode 100644 src/service/rest/openid_plugin.c create mode 100644 src/service/rest/openid_plugin.h create mode 100644 src/service/rest/pabc_plugin.c create mode 100644 src/service/rest/reclaim_plugin.c create mode 100644 src/service/rest/reclaim_plugin.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index c0c5309b2..524b989c1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,6 +7,5 @@ SUBDIRS = \ lib \ plugin \ service \ - rest-plugin \ cli \ contrib diff --git a/src/include/gnunet_rest_plugin.h b/src/include/gnunet_rest_plugin.h index 45b391ca1..3a8af5389 100644 --- a/src/include/gnunet_rest_plugin.h +++ b/src/include/gnunet_rest_plugin.h @@ -63,24 +63,13 @@ struct GNUNET_REST_Plugin * e.g. http://hostname:port/name */ char *name; - - /** - * Function to process a REST call - * - * @param method the HTTP method called - * @param url the relative url accessed - * @param data the REST data (can be NULL) - * @param data_size the length of the data - * @param proc the callback for result - * @param proc_cls closure for callback - * @return GNUNET_YES if the request was processed - */ - enum GNUNET_GenericReturnValue (*process_request)( - struct GNUNET_REST_RequestHandle *handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls); }; +typedef enum GNUNET_GenericReturnValue (*GNUNET_REST_ProcessingFunction)( + void *plugin, + struct GNUNET_REST_RequestHandle *handle, + GNUNET_REST_ResultProcessor proc, + void *proc_cls); #if 0 /* keep Emacsens' auto-indent happy */ { diff --git a/src/meson.build b/src/meson.build index 0a2dab664..8f8342a4d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -6,6 +6,5 @@ subdir('include') subdir('lib') subdir('plugin') subdir('service') -subdir('rest-plugin') subdir('cli') subdir('contrib') diff --git a/src/rest-plugin/Makefile.am b/src/rest-plugin/Makefile.am deleted file mode 100644 index 3379cb24e..000000000 --- a/src/rest-plugin/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -SUBDIRS = \ - rest \ - identity \ - namestore \ - gns \ - reclaim diff --git a/src/rest-plugin/gns/Makefile.am b/src/rest-plugin/gns/Makefile.am deleted file mode 100644 index 48b278df6..000000000 --- a/src/rest-plugin/gns/Makefile.am +++ /dev/null @@ -1,61 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include - -if HAVE_LIBIDN - LIBIDN= -lidn -else - LIBIDN= -endif - -if HAVE_LIBIDN2 - LIBIDN2= -lidn2 -else - LIBIDN2= -endif - -USE_VPN = $(top_builddir)/src/service/vpn/libgnunetvpn.la - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 -endif - -pkgcfgdir = $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -plugindir = $(libdir)/gnunet - -REST_PLUGIN = libgnunet_plugin_rest_gns.la - -plugin_LTLIBRARIES = \ - $(REST_PLUGIN) - - -libgnunet_plugin_rest_gns_la_SOURCES = \ - plugin_rest_gns.c -libgnunet_plugin_rest_gns_la_LIBADD = \ - $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \ - $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecordjson.la \ - $(top_builddir)/src/service/gns/libgnunetgns.la \ - $(top_builddir)/src/service/rest/libgnunetrest.la \ - $(top_builddir)/src/service/identity/libgnunetidentity.la \ - $(top_builddir)/src/lib/json/libgnunetjson.la \ - $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson $(MHD_LIBS) -libgnunet_plugin_rest_gns_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) -libgnunet_plugin_rest_gns_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS) - - -check_SCRIPTS = \ - test_plugin_rest_gns.sh - -EXTRA_DIST = \ - test_plugin_rest_gns.sh - -if ENABLE_TEST_RUN -if HAVE_SQLITE - AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; - TESTS = $(check_SCRIPTS) -endif -endif diff --git a/src/rest-plugin/gns/meson.build b/src/rest-plugin/gns/meson.build deleted file mode 100644 index 7a4deffed..000000000 --- a/src/rest-plugin/gns/meson.build +++ /dev/null @@ -1,13 +0,0 @@ -shared_module('gnunet_plugin_rest_gns', - ['plugin_rest_gns.c'], - dependencies: [libgnunetrest_dep, - libgnunetgnsrecord_dep, - libgnunetgnsrecordjson_dep, - libgnunetgns_dep, - libgnunetutil_dep, - json_dep, - mhd_dep], - include_directories: [incdir, configuration_inc], - install: true, - install_dir: get_option('libdir') / 'gnunet') - diff --git a/src/rest-plugin/gns/plugin_rest_gns.c b/src/rest-plugin/gns/plugin_rest_gns.c deleted file mode 100644 index 659b77493..000000000 --- a/src/rest-plugin/gns/plugin_rest_gns.c +++ /dev/null @@ -1,485 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ -/** - * @author Philippe Buschmann - * @file gns/plugin_rest_gns.c - * @brief GNUnet Gns REST plugin - */ - -#include "platform.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_rest_lib.h" -#include "gnunet_json_lib.h" -#include "gnunet_gnsrecord_lib.h" -#include "gnunet_gnsrecord_json_lib.h" -#include "gnunet_gns_service.h" -#include "microhttpd.h" -#include - -/** - * Rest API GNS Namespace - */ -#define GNUNET_REST_API_NS_GNS "/gns" - -/** - * Rest API GNS Parameter record_type - */ -#define GNUNET_REST_GNS_PARAM_RECORD_TYPE "record_type" - -/** - * Rest API GNS ERROR Unknown Error - */ -#define GNUNET_REST_GNS_ERROR_UNKNOWN "Unknown Error" - -/** - * Rest API GNS ERROR Record not found - */ -#define GNUNET_REST_GNS_NOT_FOUND "Record not found" - -/** - * The configuration handle - */ -const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * HTTP methods allows for this plugin - */ -static char *allow_methods; - -/** - * Connection to GNS - */ -static struct GNUNET_GNS_Handle *gns; - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - -/** - * The request handle - */ -struct RequestHandle -{ - /** - * DLL - */ - struct RequestHandle *next; - - /** - * DLL - */ - struct RequestHandle *prev; - - /** - * Active GNS lookup - */ - struct GNUNET_GNS_LookupWithTldRequest *gns_lookup; - - /** - * Name to look up - */ - char *name; - - /** - * Record type to look up - */ - int record_type; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * Desired timeout for the lookup (default is no timeout). - */ - struct GNUNET_TIME_Relative timeout; - - /** - * ID of a task associated with the resolution process. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * Error response message - */ - char *emsg; - - /** - * Response code - */ - int response_code; -}; - -/** - * DLL - */ -static struct RequestHandle *requests_head; - -/** - * DLL - */ -static struct RequestHandle *requests_tail; - -/** - * Cleanup lookup handle - * @param cls `struct RequestHandle` to clean up - */ -static void -cleanup_handle (void *cls) -{ - struct RequestHandle *handle = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); - - if (NULL != handle->gns_lookup) - { - GNUNET_GNS_lookup_with_tld_cancel (handle->gns_lookup); - handle->gns_lookup = NULL; - } - if (NULL != handle->timeout_task) - { - GNUNET_SCHEDULER_cancel (handle->timeout_task); - handle->timeout_task = NULL; - } - if (NULL != handle->url) - GNUNET_free (handle->url); - if (NULL != handle->name) - GNUNET_free (handle->name); - if (NULL != handle->emsg) - GNUNET_free (handle->emsg); - - GNUNET_CONTAINER_DLL_remove (requests_head, - requests_tail, - handle); - GNUNET_free (handle); -} - - -/** - * Task run on errors. Reports an error and cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - json_t *json_error = json_object (); - char *response; - - if (NULL != handle->timeout_task) - GNUNET_SCHEDULER_cancel (handle->timeout_task); - handle->timeout_task = NULL; - if (NULL == handle->emsg) - handle->emsg = GNUNET_strdup (GNUNET_REST_GNS_ERROR_UNKNOWN); - - json_object_set_new (json_error, "error", json_string (handle->emsg)); - - if (0 == handle->response_code) - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - response = json_dumps (json_error, 0); - resp = GNUNET_REST_create_response (response); - MHD_add_response_header (resp, "Content-Type", "application/json"); - handle->proc (handle->proc_cls, resp, handle->response_code); - json_decref (json_error); - GNUNET_free (response); - cleanup_handle(handle); -} - - -static void -do_timeout (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->timeout_task = NULL; - handle->response_code = MHD_HTTP_REQUEST_TIMEOUT; - do_error (handle); -} - - -/** - * Iterator called on obtained result for a GNS lookup. - * - * @param cls closure with the object - * @param was_gns #GNUNET_NO if name was not a GNS name - * @param rd_count number of records in @a rd - * @param rd the records in reply - */ -static void -handle_gns_response (void *cls, - int was_gns, - uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - json_t *result_obj; - char *result; - - handle->gns_lookup = NULL; - - if (GNUNET_NO == was_gns) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup (GNUNET_REST_GNS_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - result_obj = GNUNET_GNSRECORD_JSON_from_gnsrecord (handle->name, rd, rd_count); - - result = json_dumps (result_obj, 0); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result); - resp = GNUNET_REST_create_response (result); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Content-Type", - "application/json")); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (result); - json_decref (result_obj); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Handle gns GET request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_HashCode key; - char *record_type; - char *name; - - name = NULL; - handle->name = NULL; - if (strlen (GNUNET_REST_API_NS_GNS) < strlen (handle->url)) - { - name = &handle->url[strlen (GNUNET_REST_API_NS_GNS) + 1]; - } - - if (NULL == name) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup (GNUNET_REST_GNS_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (0 >= strlen (name)) - { - handle->response_code = MHD_HTTP_NOT_FOUND; - handle->emsg = GNUNET_strdup (GNUNET_REST_GNS_NOT_FOUND); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->name = GNUNET_strdup (name); - - handle->record_type = UINT32_MAX; - GNUNET_CRYPTO_hash (GNUNET_REST_GNS_PARAM_RECORD_TYPE, - strlen (GNUNET_REST_GNS_PARAM_RECORD_TYPE), - &key); - if (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key)) - { - record_type = - GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key); - handle->record_type = GNUNET_GNSRECORD_typename_to_number (record_type); - } - - if (UINT32_MAX == handle->record_type) - { - handle->record_type = GNUNET_GNSRECORD_TYPE_ANY; - } - - handle->gns_lookup = GNUNET_GNS_lookup_with_tld (gns, - handle->name, - handle->record_type, - GNUNET_GNS_LO_DEFAULT, - &handle_gns_response, - handle); -} - - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - // independent of path return all options - resp = GNUNET_REST_create_response (NULL); - MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); - return; -} - - -/** - * Function processing the REST call - * - * @param method HTTP method - * @param url URL of the HTTP request - * @param data body of the HTTP request (optional) - * @param data_size length of the body - * @param proc callback function for the result - * @param proc_cls closure for callback function - * @return GNUNET_OK if request accepted - */ -static enum GNUNET_GenericReturnValue -rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = - { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_GNS, &get_gns_cont }, - { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_GNS, &options_cont }, - GNUNET_REST_HANDLER_END }; - - handle->response_code = 0; - handle->timeout = - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60); - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->rest_handle = rest_handle; - handle->url = GNUNET_strdup (rest_handle->url); - handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle); - GNUNET_CONTAINER_DLL_insert (requests_head, - requests_tail, - handle); - if (handle->url[strlen (handle->url) - 1] == '/') - handle->url[strlen (handle->url) - 1] = '\0'; - if (GNUNET_NO == - GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle)) - { - cleanup_handle (handle); - return GNUNET_NO; - } - - - return GNUNET_YES; -} - - -/** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_gns_init (void *cls) -{ - static struct Plugin plugin; - struct GNUNET_REST_Plugin *api; - - cfg = cls; - memset (&plugin, 0, sizeof(struct Plugin)); - plugin.cfg = cfg; - api = GNUNET_new (struct GNUNET_REST_Plugin); - api->cls = &plugin; - api->name = GNUNET_REST_API_NS_GNS; - api->process_request = &rest_process_request; - GNUNET_asprintf (&allow_methods, - "%s, %s, %s, %s, %s", - MHD_HTTP_METHOD_GET, - MHD_HTTP_METHOD_POST, - MHD_HTTP_METHOD_PUT, - MHD_HTTP_METHOD_DELETE, - MHD_HTTP_METHOD_OPTIONS); - gns = GNUNET_GNS_connect (cfg); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Gns REST API initialized\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_rest_gns_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct RequestHandle *request; - struct Plugin *plugin; - - while (NULL != (request = requests_head)) - do_error (request); - - if (NULL != gns) - GNUNET_GNS_disconnect (gns); - - plugin = api->cls; - - plugin->cfg = NULL; - - GNUNET_free (allow_methods); - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Gns REST plugin is finished\n"); - return NULL; -} - - -/* end of plugin_rest_gns.c */ diff --git a/src/rest-plugin/gns/test_plugin_rest_gns.sh b/src/rest-plugin/gns/test_plugin_rest_gns.sh deleted file mode 100755 index 3bcfb5a08..000000000 --- a/src/rest-plugin/gns/test_plugin_rest_gns.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/sh -# This file is in the public domain. -trap "gnunet-arm -e -c test_gns_lookup.conf" INT -LOCATION=$(which gnunet-config) -if [ -z $LOCATION ] -then - LOCATION="gnunet-config" -fi -$LOCATION --version 1> /dev/null -if test $? != 0 -then - echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" - exit 77 -fi - -rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME` - -gns_link="http://localhost:7776/gns" -wrong_link="http://localhost:7776/gnsandmore" - -curl_get () { - #$1 is link - #$2 is grep - XURL=`which curl` - if [ "" = "$XURL" ] - then - echo "HTTP client (curl) not found, exiting" - exit 77 - fi - sleep 0.5 - cache="$(${XURL} -v "$1" 2>&1 | grep "$2")" - #echo "$cache" - if [ "" = "$cache" ] - then - gnunet-identity -D "$TEST_TLD" -c test_gns_lookup.conf > /dev/null 2>&1 - gnunet-arm -e -c test_gns_lookup.conf - echo "Download of $1 using $XURL failed, expected $2" - exit 1 - fi -} -TEST_TLD="testtld" - -gnunet-arm -s -c test_gns_lookup.conf - -curl_get "$gns_link/www.$TEST_TLD" "error" - -gnunet-identity -C "$TEST_TLD" -c test_gns_lookup.conf -sleep 0.5 -curl_get "$gns_link/www.$TEST_TLD" "\[\]" - -gnunet-namestore -z "$TEST_TLD" -p -a -n www -e 1d -V 1.1.1.1 -t A -c test_gns_lookup.conf - -curl_get "$gns_link/www.$TEST_TLD" "1.1.1.1" - -gnunet-namestore -z "$TEST_TLD" -p -a -n www -e 1d -V 1::1 -t AAAA -c test_gns_lookup.conf - -curl_get "$gns_link/www.$TEST_TLD" "1::1.*1.1.1.1" - -gnunet-namestore -z "$TEST_TLD" -p -a -n www -e 1d -V 1.1.1.2 -t A -c test_gns_lookup.conf - -curl_get "$gns_link/www.$TEST_TLD" "1.1.1.2.*1::1.*1.1.1.1" -curl_get "$gns_link/www.$TEST_TLD?record_type=A" "1.1.1.2.*1.1.1.1" -curl_get "$gns_link/www.$TEST_TLD?record_type=AAAA" "1::1" -curl_get "$gns_link/www.$TEST_TLD?record_type=WRONG_TYPE" "1.1.1.2.*1::1.*1.1.1.1" - -gnunet-namestore -z "$TEST_TLD" -p -a -n www1 -e 1d -V 1.1.1.1 -t A -c test_gns_lookup.conf -curl_get "$gns_link/www1.$TEST_TLD" "1.1.1.1" - -gnunet-namestore -z "$TEST_TLD" -d -n www1 -c test_gns_lookup.conf -gnunet-namestore -z "$TEST_TLD" -d -n www -c test_gns_lookup.conf - -gnunet-identity -D "$TEST_TLD" -c test_gns_lookup.conf > /dev/null 2>&1 - -curl_get "$gns_link/www1.$TEST_TLD" "error" -gnunet-arm -e -c test_gns_lookup.conf -exit 0 diff --git a/src/rest-plugin/identity/Makefile.am b/src/rest-plugin/identity/Makefile.am deleted file mode 100644 index bcad0c2dd..000000000 --- a/src/rest-plugin/identity/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include - -plugindir = $(libdir)/gnunet - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 - XLIB = -lgcov -endif - -plugin_LTLIBRARIES = libgnunet_plugin_rest_identity.la - -pkgcfgdir= $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -libgnunet_plugin_rest_identity_la_SOURCES = \ - plugin_rest_identity.c -libgnunet_plugin_rest_identity_la_LIBADD = \ - $(top_builddir)/src/service/identity/libgnunetidentity.la \ - $(top_builddir)/src/service/rest/libgnunetrest.la \ - $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson $(MHD_LIBS) -libgnunet_plugin_rest_identity_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) -libgnunet_plugin_rest_identity_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS) diff --git a/src/rest-plugin/identity/meson.build b/src/rest-plugin/identity/meson.build deleted file mode 100644 index f459918db..000000000 --- a/src/rest-plugin/identity/meson.build +++ /dev/null @@ -1,11 +0,0 @@ -shared_module('gnunet_plugin_rest_identity', - ['plugin_rest_identity.c'], - dependencies: [libgnunetrest_dep, - libgnunetidentity_dep, - libgnunetutil_dep, - json_dep, - mhd_dep], - include_directories: [incdir, configuration_inc], - install: true, - install_dir: get_option('libdir') / 'gnunet') - diff --git a/src/rest-plugin/identity/plugin_rest_identity.c b/src/rest-plugin/identity/plugin_rest_identity.c deleted file mode 100644 index e7b7f8a9c..000000000 --- a/src/rest-plugin/identity/plugin_rest_identity.c +++ /dev/null @@ -1,1286 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ -/** - * @author Martin Schanzenbach - * @author Philippe Buschmann - * @file identity/plugin_rest_identity.c - * @brief GNUnet Identity REST plugin - */ - -#include "platform.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_identity_service.h" -#include "gnunet_rest_lib.h" -#include "../../service/identity/identity.h" -#include "gnunet_util_lib.h" -#include "microhttpd.h" -#include - -/** - * Identity Namespace - */ -#define GNUNET_REST_API_NS_IDENTITY "/identity" - -/** - * Identity Namespace with public key specifier - */ -#define GNUNET_REST_API_NS_IDENTITY_PUBKEY "/identity/pubkey" - -/** - * Identity Namespace with public key specifier - */ -#define GNUNET_REST_API_NS_IDENTITY_NAME "/identity/name" - -/** - * Identity Namespace with sign specifier - */ -#define GNUNET_REST_API_NS_SIGN "/sign" - -/** - * Parameter public key - */ -#define GNUNET_REST_IDENTITY_PARAM_PUBKEY "pubkey" - -/** - * Parameter private key - */ -#define GNUNET_REST_IDENTITY_PARAM_PRIVKEY "privkey" - -/** - * Parameter name - */ -#define GNUNET_REST_IDENTITY_PARAM_NAME "name" - -/** - * Parameter new name - */ -#define GNUNET_REST_IDENTITY_PARAM_NEWNAME "newname" - -/** - * Error message Missing identity name - */ -#define GNUNET_REST_IDENTITY_MISSING_NAME "Missing identity name" - -/** - * Error message Missing identity name - */ -#define GNUNET_REST_IDENTITY_MISSING_PUBKEY "Missing identity public key" - -/** - * Error message No data - */ -#define GNUNET_REST_ERROR_NO_DATA "No data" - -/** - * Error message Data invalid - */ -#define GNUNET_REST_ERROR_DATA_INVALID "Data invalid" - -/** - * State while collecting all egos - */ -#define ID_REST_STATE_INIT 0 - -/** - * Done collecting egos - */ -#define ID_REST_STATE_POST_INIT 1 - -/** - * The configuration handle - */ -const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * HTTP methods allows for this plugin - */ -static char *allow_methods; - -/** - * Ego list - */ -static struct EgoEntry *ego_head; - -/** - * Ego list - */ -static struct EgoEntry *ego_tail; - -/** - * The processing state - */ -static int state; - -/** - * Handle to Identity service. - */ -static struct GNUNET_IDENTITY_Handle *identity_handle; - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - -/** - * The ego list - */ -struct EgoEntry -{ - /** - * DLL - */ - struct EgoEntry *next; - - /** - * DLL - */ - struct EgoEntry *prev; - - /** - * Ego Identifier - */ - char *identifier; - - /** - * Public key string - */ - char *keystring; - - /** - * The Ego - */ - struct GNUNET_IDENTITY_Ego *ego; -}; - -/** - * The request handle - */ -struct RequestHandle -{ - /** - * DLL - */ - struct RequestHandle *next; - - /** - * DLL - */ - struct RequestHandle *prev; - - /** - * The data from the REST request - */ - const char *data; - - /** - * The name to look up - */ - char *name; - - /** - * the length of the REST data - */ - size_t data_size; - - /** - * IDENTITY Operation - */ - struct GNUNET_IDENTITY_Operation *op; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * Desired timeout for the lookup (default is no timeout). - */ - struct GNUNET_TIME_Relative timeout; - - /** - * ID of a task associated with the resolution process. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * Error code - */ - enum GNUNET_ErrorCode ec; -}; - -/** - * DLL - */ -static struct RequestHandle *requests_head; - -/** - * DLL - */ -static struct RequestHandle *requests_tail; - -/** - * Cleanup lookup handle - * @param cls Handle to clean up - */ -static void -cleanup_handle (void *cls) -{ - struct RequestHandle *handle = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); - if (NULL != handle->timeout_task) - { - GNUNET_SCHEDULER_cancel (handle->timeout_task); - handle->timeout_task = NULL; - } - - if (NULL != handle->url) - GNUNET_free (handle->url); - if (NULL != handle->name) - GNUNET_free (handle->name); - GNUNET_CONTAINER_DLL_remove (requests_head, - requests_tail, - handle); - GNUNET_free (handle); -} - - -/** - * Task run on errors. Reports an error and cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - json_t *json_error = json_object (); - char *response; - int response_code; - - json_object_set_new (json_error, "error", - json_string (GNUNET_ErrorCode_get_hint (handle->ec))); - json_object_set_new (json_error, "error_code", json_integer (handle->ec)); - response_code = GNUNET_ErrorCode_get_http_status (handle->ec); - if (0 == response_code) - response_code = MHD_HTTP_OK; - response = json_dumps (json_error, 0); - resp = GNUNET_REST_create_response (response); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Content-Type", - "application/json")); - handle->proc (handle->proc_cls, resp, response_code); - json_decref (json_error); - GNUNET_free (response); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Get EgoEntry from list with either a public key or a name - * If public key and name are not NULL, it returns the public key result first - * - * @param handle the RequestHandle - * @param pubkey the public key of an identity (only one can be NULL) - * @param name the name of an identity (only one can be NULL) - * @return EgoEntry or NULL if not found - */ -struct EgoEntry * -get_egoentry (struct RequestHandle *handle, char *pubkey, char *name) -{ - struct EgoEntry *ego_entry; - - if (NULL != pubkey) - { - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (0 != strcasecmp (pubkey, ego_entry->keystring)) - continue; - return ego_entry; - } - } - if (NULL != name) - { - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (0 != strcasecmp (name, ego_entry->identifier)) - continue; - return ego_entry; - } - } - return NULL; -} - - -/** - * Handle identity GET request - responds with all identities - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_get_all (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct MHD_Response *resp; - struct GNUNET_HashCode key; - json_t *json_root; - json_t *json_ego; - char *result_str; - char *privkey_str; - - json_root = json_array (); - // Return ego/egos - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - json_ego = json_object (); - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_PUBKEY, - json_string (ego_entry->keystring)); - GNUNET_CRYPTO_hash ("private", strlen ("private"), &key); - if (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->url_param_map, &key)) - { - privkey_str = GNUNET_CRYPTO_private_key_to_string ( - GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego)); - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_PRIVKEY, - json_string (privkey_str)); - GNUNET_free (privkey_str); - } - - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_NAME, - json_string (ego_entry->identifier)); - json_array_append (json_root, json_ego); - json_decref (json_ego); - } - - result_str = json_dumps (json_root, 0); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Content-Type", - "application/json")); - json_decref (json_root); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (result_str); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Responds with the ego_entry identity - * - * @param handle the struct RequestHandle - * @param ego_entry the struct EgoEntry for the response - */ -void -ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry) -{ - struct MHD_Response *resp; - struct GNUNET_HashCode key; - json_t *json_ego; - char *result_str; - char *privkey_str; - - json_ego = json_object (); - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_PUBKEY, - json_string (ego_entry->keystring)); - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_NAME, - json_string (ego_entry->identifier)); - GNUNET_CRYPTO_hash ("private", strlen ("private"), &key); - if (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->url_param_map, &key)) - { - privkey_str = GNUNET_CRYPTO_private_key_to_string ( - GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego)); - json_object_set_new (json_ego, - GNUNET_REST_IDENTITY_PARAM_PRIVKEY, - json_string (privkey_str)); - GNUNET_free (privkey_str); - } - - result_str = json_dumps (json_ego, 0); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Content-Type", - "application/json")); - json_decref (json_ego); - GNUNET_free (result_str); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Handle identity GET request with a public key - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *keystring; - - keystring = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) + 1]; - ego_entry = get_egoentry (handle, keystring, NULL); - - if (NULL == ego_entry) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - ego_get_response (handle, ego_entry); -} - - -/** - * Handle identity GET request with a name - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_get_name (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *egoname; - - egoname = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME) + 1]; - ego_entry = get_egoentry (handle, NULL, egoname); - - if (NULL == ego_entry) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - ego_get_response (handle, ego_entry); -} - - -/** - * Processing finished - * - * @param cls request handle - * @param ec error code - */ -static void -do_finished (void *cls, enum GNUNET_ErrorCode ec) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - int response_code; - - handle->op = NULL; - handle->ec = ec; - if (GNUNET_EC_NONE != ec) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (GNUNET_EC_NONE == handle->ec) - response_code = MHD_HTTP_NO_CONTENT; - else - response_code = GNUNET_ErrorCode_get_http_status (ec); - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, response_code); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Processing finished, when creating an ego. - * - * @param cls request handle - * @param pk private key of the ego, or NULL on error - * @param ec error code - */ -static void -do_finished_create (void *cls, - const struct GNUNET_CRYPTO_PrivateKey *pk, - enum GNUNET_ErrorCode ec) -{ - struct RequestHandle *handle = cls; - - (void) pk; - do_finished (handle, ec); -} - - -/** - * Processing edit ego with EgoEntry ego_entry - * - * @param handle the struct RequestHandle - * @param ego_entry the struct EgoEntry we want to edit - */ -void -ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry) -{ - json_t *data_js; - json_error_t err; - char *newname; - char term_data[handle->data_size + 1]; - int json_state; - - // if no data - if (0 >= handle->data_size) - { - handle->ec = GNUNET_EC_IDENTITY_INVALID; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - // if not json - term_data[handle->data_size] = '\0'; - GNUNET_memcpy (term_data, handle->data, handle->data_size); - data_js = json_loads (term_data, JSON_DECODE_ANY, &err); - - if (NULL == data_js) - { - handle->ec = GNUNET_EC_IDENTITY_INVALID; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - newname = NULL; - // NEW NAME - json_state = 0; - json_state = json_unpack (data_js, - "{s:s!}", - GNUNET_REST_IDENTITY_PARAM_NEWNAME, - &newname); - // Change name with pubkey or name identifier - if (0 != json_state) - { - handle->ec = GNUNET_EC_IDENTITY_INVALID; - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (NULL == newname) - { - handle->ec = GNUNET_EC_IDENTITY_INVALID; - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (0 >= strlen (newname)) - { - handle->ec = GNUNET_EC_IDENTITY_INVALID; - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - handle->op = GNUNET_IDENTITY_rename (identity_handle, - ego_entry->identifier, - newname, - &do_finished, - handle); - if (NULL == handle->op) - { - handle->ec = GNUNET_EC_UNKNOWN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - json_decref (data_js); - return; -} - - -/** - * Handle identity PUT request with public key - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *keystring; - - keystring = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) + 1]; - ego_entry = get_egoentry (handle, keystring, NULL); - - if (NULL == ego_entry) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - ego_edit (handle, ego_entry); -} - - -/** - * Handle identity PUT request with name - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *name; - - name = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME) + 1]; - ego_entry = get_egoentry (handle, NULL, name); - - if (NULL == ego_entry) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - ego_edit (handle, ego_entry); -} - - -/** - * Handle identity POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_create (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - json_t *data_js; - json_error_t err; - char *egoname; - char *privkey; - struct GNUNET_CRYPTO_PrivateKey pk; - struct GNUNET_CRYPTO_PrivateKey *pk_ptr; - int json_unpack_state; - char term_data[handle->data_size + 1]; - - if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url)) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - if (0 >= handle->data_size) - { - handle->ec = GNUNET_EC_IDENTITY_INVALID; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - term_data[handle->data_size] = '\0'; - GNUNET_memcpy (term_data, handle->data, handle->data_size); - data_js = json_loads (term_data, JSON_DECODE_ANY, &err); - if (NULL == data_js) - { - handle->ec = GNUNET_EC_IDENTITY_INVALID; - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - json_unpack_state = 0; - privkey = NULL; - json_unpack_state = - json_unpack (data_js, "{s:s, s?:s!}", - GNUNET_REST_IDENTITY_PARAM_NAME, &egoname, - GNUNET_REST_IDENTITY_PARAM_PRIVKEY, &privkey); - if (0 != json_unpack_state) - { - handle->ec = GNUNET_EC_IDENTITY_INVALID; - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - - if (NULL == egoname) - { - handle->ec = GNUNET_EC_IDENTITY_INVALID; - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - if (0 >= strlen (egoname)) - { - handle->ec = GNUNET_EC_IDENTITY_INVALID; - json_decref (data_js); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - GNUNET_STRINGS_utf8_tolower (egoname, egoname); - handle->name = GNUNET_strdup (egoname); - if (NULL != privkey) - { - GNUNET_STRINGS_string_to_data (privkey, - strlen (privkey), - &pk, - sizeof(struct - GNUNET_CRYPTO_PrivateKey)); - pk_ptr = &pk; - } - else - pk_ptr = NULL; - json_decref (data_js); - handle->op = GNUNET_IDENTITY_create (identity_handle, - handle->name, - pk_ptr, - GNUNET_PUBLIC_KEY_TYPE_ECDSA, - &do_finished_create, - handle); -} - - -/** - * Handle identity DELETE request with public key - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *keystring; - - keystring = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url)) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) + 1]; - ego_entry = get_egoentry (handle, keystring, NULL); - - if (NULL == ego_entry) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - handle->op = GNUNET_IDENTITY_delete (identity_handle, - ego_entry->identifier, - &do_finished, - handle); -} - - -/** - * Handle identity DELETE request with name - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *name; - - name = NULL; - - if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url)) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME) + 1]; - ego_entry = get_egoentry (handle, NULL, name); - - if (NULL == ego_entry) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - handle->op = GNUNET_IDENTITY_delete (identity_handle, - ego_entry->identifier, - &do_finished, - handle); -} - -struct ego_sign_data_cls -{ - void *data; - struct RequestHandle *handle; -}; - -void -ego_sign_data_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego) -{ - struct RequestHandle *handle = ((struct ego_sign_data_cls *) cls)->handle; - unsigned char *data - = (unsigned char *) ((struct ego_sign_data_cls *) cls)->data; // data is url decoded - struct MHD_Response *resp; - struct GNUNET_CRYPTO_EddsaSignature sig; - char *sig_str; - char *result; - - if (ego == NULL) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - if (ntohl (ego->pk.type) != GNUNET_PUBLIC_KEY_TYPE_EDDSA) - { - handle->ec = GNUNET_EC_IDENTITY_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - if ( GNUNET_OK != GNUNET_CRYPTO_eddsa_sign_raw (&(ego->pk.eddsa_key), - (void *) data, - strlen ( (char*) data), - &sig)) - { - handle->ec = GNUNET_EC_UNKNOWN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - GNUNET_STRINGS_base64url_encode (&sig, - sizeof (struct GNUNET_CRYPTO_EddsaSignature), - &sig_str); - - GNUNET_asprintf (&result, - "{\"signature\": \"%s\"}", - sig_str); - - resp = GNUNET_REST_create_response (result); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - - free (data); - free (sig_str); - free (result); - free (cls); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - -/** - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -ego_sign_data (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - // TODO: replace with precompiler #define - const char *username_key = "user"; - const char *data_key = "data"; - - struct RequestHandle *handle = cls; - struct GNUNET_HashCode cache_key_username; - struct GNUNET_HashCode cache_key_data; - char *username; - char *data; - - struct ego_sign_data_cls *cls2; - - GNUNET_CRYPTO_hash (username_key, strlen (username_key), &cache_key_username); - GNUNET_CRYPTO_hash (data_key, strlen (data_key), &cache_key_data); - - if ((GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->url_param_map, - &cache_key_username)) || - (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->url_param_map, - &cache_key_data))) - { - handle->ec = GNUNET_EC_UNKNOWN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - username = (char *) GNUNET_CONTAINER_multihashmap_get ( - handle->rest_handle->url_param_map, - &cache_key_username); - - data = (char *) GNUNET_CONTAINER_multihashmap_get ( - handle->rest_handle->url_param_map, - &cache_key_data); - - cls2 = malloc (sizeof(struct ego_sign_data_cls)); - cls2->data = (void *) GNUNET_strdup (data); - cls2->handle = handle; - - GNUNET_IDENTITY_ego_lookup (cfg, - username, - ego_sign_data_cb, - cls2); -} - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - // For now, independent of path return all options - resp = GNUNET_REST_create_response (NULL); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - allow_methods)); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); - return; -} - - -static void -list_ego (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *identifier) -{ - struct EgoEntry *ego_entry; - struct GNUNET_CRYPTO_PublicKey pk; - - if ((NULL == ego) && (ID_REST_STATE_INIT == state)) - { - state = ID_REST_STATE_POST_INIT; - return; - } - if (NULL == ego) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Called with NULL ego\n"); - return; - } - if (ID_REST_STATE_INIT == state) - { - ego_entry = GNUNET_new (struct EgoEntry); - GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = GNUNET_CRYPTO_public_key_to_string (&pk); - ego_entry->ego = ego; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail (ego_head, - ego_tail, - ego_entry); - } - /* Ego renamed or added */ - if (identifier != NULL) - { - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (ego_entry->ego == ego) - { - /* Rename */ - GNUNET_free (ego_entry->identifier); - ego_entry->identifier = GNUNET_strdup (identifier); - break; - } - } - if (NULL == ego_entry) - { - /* Add */ - ego_entry = GNUNET_new (struct EgoEntry); - GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = GNUNET_CRYPTO_public_key_to_string (&pk); - ego_entry->ego = ego; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail (ego_head, - ego_tail, - ego_entry); - } - } - else - { - /* Delete */ - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (ego_entry->ego == ego) - break; - } - if (NULL == ego_entry) - return; /* Not found */ - - GNUNET_CONTAINER_DLL_remove (ego_head, - ego_tail, - ego_entry); - GNUNET_free (ego_entry->identifier); - GNUNET_free (ego_entry->keystring); - GNUNET_free (ego_entry); - return; - } - -} - - -/** - * Function processing the REST call - * - * @param method HTTP method - * @param url URL of the HTTP request - * @param data body of the HTTP request (optional) - * @param data_size length of the body - * @param proc callback function for the result - * @param proc_cls closure for callback function - * @return GNUNET_OK if request accepted - */ -static enum GNUNET_GenericReturnValue -rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = - { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PUBKEY, - &ego_get_pubkey }, - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_get_name }, - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_get_all }, - { MHD_HTTP_METHOD_PUT, - GNUNET_REST_API_NS_IDENTITY_PUBKEY, - &ego_edit_pubkey }, - { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_edit_name }, - { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create }, - { MHD_HTTP_METHOD_DELETE, - GNUNET_REST_API_NS_IDENTITY_PUBKEY, - &ego_delete_pubkey }, - { MHD_HTTP_METHOD_DELETE, - GNUNET_REST_API_NS_IDENTITY_NAME, - &ego_delete_name }, - { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont }, - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_SIGN, &ego_sign_data}, - GNUNET_REST_HANDLER_END }; - - - handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->rest_handle = rest_handle; - handle->data = rest_handle->data; - handle->data_size = rest_handle->data_size; - - handle->url = GNUNET_strdup (rest_handle->url); - if (handle->url[strlen (handle->url) - 1] == '/') - handle->url[strlen (handle->url) - 1] = '\0'; - handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle); - GNUNET_CONTAINER_DLL_insert (requests_head, - requests_tail, - handle); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); - if (GNUNET_NO == - GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle)) - { - cleanup_handle (handle); - return GNUNET_NO; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); - return GNUNET_YES; -} - - -/** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_identity_init (void *cls) -{ - static struct Plugin plugin; - struct GNUNET_REST_Plugin *api; - - cfg = cls; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof(struct Plugin)); - plugin.cfg = cfg; - api = GNUNET_new (struct GNUNET_REST_Plugin); - api->cls = &plugin; - api->name = GNUNET_REST_API_NS_IDENTITY; - api->process_request = &rest_process_request; - GNUNET_asprintf (&allow_methods, - "%s, %s, %s, %s, %s", - MHD_HTTP_METHOD_GET, - MHD_HTTP_METHOD_POST, - MHD_HTTP_METHOD_PUT, - MHD_HTTP_METHOD_DELETE, - MHD_HTTP_METHOD_OPTIONS); - state = ID_REST_STATE_INIT; - identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Identity REST API initialized\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_rest_identity_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - struct EgoEntry *ego_entry; - struct EgoEntry *ego_tmp; - - plugin->cfg = NULL; - while (NULL != requests_head) - cleanup_handle (requests_head); - if (NULL != identity_handle) - GNUNET_IDENTITY_disconnect (identity_handle); - - for (ego_entry = ego_head; NULL != ego_entry;) - { - ego_tmp = ego_entry; - ego_entry = ego_entry->next; - GNUNET_free (ego_tmp->identifier); - GNUNET_free (ego_tmp->keystring); - GNUNET_free (ego_tmp); - } - - GNUNET_free (allow_methods); - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n"); - return NULL; -} - - -/* end of plugin_rest_identity.c */ diff --git a/src/rest-plugin/meson.build b/src/rest-plugin/meson.build deleted file mode 100644 index 09cd2ad8c..000000000 --- a/src/rest-plugin/meson.build +++ /dev/null @@ -1,7 +0,0 @@ -if get_option('monolith') == false - subdir('rest') -endif -subdir('identity') -subdir('namestore') -subdir('gns') -subdir('reclaim') diff --git a/src/rest-plugin/namestore/Makefile.am b/src/rest-plugin/namestore/Makefile.am deleted file mode 100644 index 93da51dbc..000000000 --- a/src/rest-plugin/namestore/Makefile.am +++ /dev/null @@ -1,53 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS) - -plugindir = $(libdir)/gnunet - -pkgcfgdir= $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -sqldir = $(prefix)/share/gnunet/sql/ - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 - XLIBS = -lgcov -endif - - -if ENABLE_TEST_RUN -AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; -TESTS = \ - $(check_PROGRAMS) \ - $(check_SCRIPTS) -endif - -REST_PLUGIN = libgnunet_plugin_rest_namestore.la - -plugin_LTLIBRARIES = \ - $(SQLITE_PLUGIN) \ - $(POSTGRES_PLUGIN) \ - $(REST_PLUGIN) - - -libgnunet_plugin_rest_namestore_la_SOURCES = \ - plugin_rest_namestore.c -libgnunet_plugin_rest_namestore_la_LIBADD = \ - $(top_builddir)/src/service/namestore/libgnunetnamestore.la \ - $(top_builddir)/src/service/rest/libgnunetrest.la \ - $(top_builddir)/src/service/identity/libgnunetidentity.la \ - $(top_builddir)/src/lib/json/libgnunetjson.la \ - $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \ - $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecordjson.la \ - $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson $(MHD_LIBS) -libgnunet_plugin_rest_namestore_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) -libgnunet_plugin_rest_namestore_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS) - - -check_SCRIPTS = \ - test_plugin_rest_namestore.sh - -EXTRA_DIST = \ - $(check_SCRIPTS) diff --git a/src/rest-plugin/namestore/meson.build b/src/rest-plugin/namestore/meson.build deleted file mode 100644 index f96e7cd44..000000000 --- a/src/rest-plugin/namestore/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -shared_module('gnunet_plugin_rest_namestore', - ['plugin_rest_namestore.c'], - dependencies: [ - libgnunetrest_dep, - libgnunetgnsrecordjson_dep, - libgnunetgnsrecord_dep, - libgnunetjson_dep, - libgnunetutil_dep, - json_dep, - mhd_dep], - include_directories: [incdir, configuration_inc], - install: true, - install_dir: get_option('libdir') / 'gnunet') - diff --git a/src/rest-plugin/namestore/plugin_rest_namestore.c b/src/rest-plugin/namestore/plugin_rest_namestore.c deleted file mode 100644 index 31e78e6dd..000000000 --- a/src/rest-plugin/namestore/plugin_rest_namestore.c +++ /dev/null @@ -1,1364 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ -/** - * @author Martin Schanzenbach - * @author Philippe Buschmann - * @file namestore/plugin_rest_namestore.c - * @brief GNUnet Namestore REST plugin - */ - -#include "platform.h" -#include "gnunet_error_codes.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_gns_service.h" -#include "gnunet_namestore_service.h" -#include "gnunet_identity_service.h" -#include "gnunet_rest_lib.h" -#include "gnunet_gnsrecord_json_lib.h" -#include "microhttpd.h" -#include - -/** - * Namestore namespace - */ -#define GNUNET_REST_API_NS_NAMESTORE "/namestore" - -/** - * Namestore import API namespace - */ -#define GNUNET_REST_API_NS_NAMESTORE_IMPORT "/namestore/import" - -/** - * State while collecting all egos - */ -#define ID_REST_STATE_INIT 0 - -/** - * Done collecting egos - */ -#define ID_REST_STATE_POST_INIT 1 -/** - * The configuration handle - */ -const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * HTTP methods allows for this plugin - */ -static char *allow_methods; - -/** - * Ego list - */ -static struct EgoEntry *ego_head; - -/** - * Ego list - */ -static struct EgoEntry *ego_tail; - -/** - * The processing state - */ -static int state; - -/** - * Handle to NAMESTORE - */ -static struct GNUNET_NAMESTORE_Handle *ns_handle; - -/** - * Handle to Identity service. - */ -static struct GNUNET_IDENTITY_Handle *identity_handle; - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - -/** - * The default namestore ego - */ -struct EgoEntry -{ - /** - * DLL - */ - struct EgoEntry *next; - - /** - * DLL - */ - struct EgoEntry *prev; - - /** - * Ego Identifier - */ - char *identifier; - - /** - * Public key string - */ - char *keystring; - - /** - * The Ego - */ - struct GNUNET_IDENTITY_Ego *ego; -}; - - -enum UpdateStrategy -{ - UPDATE_STRATEGY_REPLACE, - UPDATE_STRATEGY_APPEND -}; - -/** - * The request handle - */ -struct RequestHandle -{ - /** - * DLL - */ - struct RequestHandle *next; - - /** - * DLL - */ - struct RequestHandle *prev; - - /** - * Records to store - */ - char *record_name; - - /** - * Record type filter - */ - uint32_t record_type; - - /** - * How to update the record set - */ - enum UpdateStrategy update_strategy; - - /** - * Records to store - */ - struct GNUNET_GNSRECORD_Data *rd; - - /** - * Number of records in rd - */ - unsigned int rd_count; - - /** - * RecordInfo array - */ - struct GNUNET_NAMESTORE_RecordInfo *ri; - - /** - * Size of record info - */ - unsigned int rd_set_count; - - /** - * Position of record info - */ - unsigned int rd_set_pos; - - /** - * NAMESTORE Operation - */ - struct GNUNET_NAMESTORE_QueueEntry *ns_qe; - - /** - * For bulk import, we need a dedicated Namestore handle - */ - struct GNUNET_NAMESTORE_Handle *nc; - - /** - * Response object - */ - json_t *resp_object; - - - /** - * Handle to NAMESTORE it - */ - struct GNUNET_NAMESTORE_ZoneIterator *list_it; - - /** - * Private key for the zone - */ - const struct GNUNET_CRYPTO_PrivateKey *zone_pkey; - - /** - * IDENTITY Operation - */ - struct EgoEntry *ego_entry; - - /** - * IDENTITY Operation - */ - struct GNUNET_IDENTITY_Operation *op; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * Desired timeout for the lookup (default is no timeout). - */ - struct GNUNET_TIME_Relative timeout; - - /** - * ID of a task associated with the resolution process. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * Error code - */ - enum GNUNET_ErrorCode ec; - -}; - -/** - * DLL - */ -static struct RequestHandle *requests_head; - -/** - * DLL - */ -static struct RequestHandle *requests_tail; - - -/** - * Cleanup lookup handle - * @param cls Handle to clean up - */ -static void -cleanup_handle (void *cls) -{ - struct RequestHandle *handle = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); - if (NULL != handle->timeout_task) - { - GNUNET_SCHEDULER_cancel (handle->timeout_task); - handle->timeout_task = NULL; - } - if (NULL != handle->record_name) - GNUNET_free (handle->record_name); - if (NULL != handle->url) - GNUNET_free (handle->url); - if (NULL != handle->rd) - { - for (int i = 0; i < handle->rd_count; i++) - { - if (NULL != handle->rd[i].data) - GNUNET_free_nz ((void *) handle->rd[i].data); - } - GNUNET_free (handle->rd); - } - if (NULL != handle->timeout_task) - GNUNET_SCHEDULER_cancel (handle->timeout_task); - if (NULL != handle->list_it) - GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it); - if (NULL != handle->ns_qe) - GNUNET_NAMESTORE_cancel (handle->ns_qe); - if (NULL != handle->nc) - GNUNET_NAMESTORE_disconnect (handle->nc); - if (NULL != handle->resp_object) - { - json_decref (handle->resp_object); - } - GNUNET_CONTAINER_DLL_remove (requests_head, - requests_tail, - handle); - GNUNET_free (handle); -} - - -/** - * Task run on errors. Reports an error and cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - json_t *json_error = json_object (); - char *response; - const char* emsg; - int response_code; - - emsg = GNUNET_ErrorCode_get_hint (handle->ec); - json_object_set_new (json_error, "error", json_string (emsg)); - json_object_set_new (json_error, "error_code", json_integer (handle->ec)); - response_code = GNUNET_ErrorCode_get_http_status (handle->ec); - if (0 == response_code) - response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - response = json_dumps (json_error, 0); - resp = GNUNET_REST_create_response (response); - GNUNET_assert (MHD_YES == - MHD_add_response_header (resp, "Content-Type", - "application/json")); - handle->proc (handle->proc_cls, resp, response_code); - json_decref (json_error); - GNUNET_free (response); - cleanup_handle (handle); -} - - -/** - * Get EgoEntry from list with either a public key or a name - * If public key and name are not NULL, it returns the public key result first - * - * @param handle the RequestHandle - * @param pubkey the public key of an identity (only one can be NULL) - * @param name the name of an identity (only one can be NULL) - * @return EgoEntry or NULL if not found - */ -struct EgoEntry * -get_egoentry_namestore (struct RequestHandle *handle, char *name) -{ - struct EgoEntry *ego_entry; - char *copy = GNUNET_strdup (name); - char *tmp; - - if (NULL == name) - return NULL; - tmp = strtok (copy, "/"); - if (NULL == tmp) - return NULL; - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (0 != strcasecmp (tmp, ego_entry->identifier)) - continue; - GNUNET_free (copy); - return ego_entry; - } - GNUNET_free (copy); - return NULL; -} - - -/** - * Does internal server error when iteration failed. - * - * @param cls the `struct RequestHandle` - */ -static void -namestore_iteration_error (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->ec = GNUNET_EC_NAMESTORE_ITERATION_FAILED; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; -} - - -static void -create_finished (void *cls, enum GNUNET_ErrorCode ec) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - handle->ns_qe = NULL; - handle->ec = ec; - if (GNUNET_EC_NONE != ec) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -static void -del_finished (void *cls, enum GNUNET_ErrorCode ec) -{ - struct RequestHandle *handle = cls; - - handle->ns_qe = NULL; - handle->ec = ec; - if (GNUNET_EC_NONE != ec) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->proc (handle->proc_cls, - GNUNET_REST_create_response (NULL), - MHD_HTTP_NO_CONTENT); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Iteration over all results finished, build final - * response. - * - * @param cls the `struct RequestHandle` - */ -static void -namestore_list_finished (void *cls) -{ - struct RequestHandle *handle = cls; - char *result_str; - struct MHD_Response *resp; - - handle->list_it = NULL; - - if (NULL == handle->resp_object) - { - handle->ec = GNUNET_EC_NAMESTORE_ZONE_EMPTY; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - result_str = json_dumps (handle->resp_object, 0); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - GNUNET_assert (MHD_YES == - MHD_add_response_header (resp, "Content-Type", - "application/json")); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (result_str); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Create a response with requested records - * - * @param handle the RequestHandle - */ -static void -namestore_list_iteration (void *cls, - const struct GNUNET_CRYPTO_PrivateKey *zone_key, - const char *rname, - unsigned int rd_len, - const struct GNUNET_GNSRECORD_Data *rd, - struct GNUNET_TIME_Absolute expiry) -{ - struct RequestHandle *handle = cls; - struct GNUNET_GNSRECORD_Data rd_filtered[rd_len]; - json_t *record_obj; - int i = 0; - int j = 0; - - if (rd_len == 0) - { - /** skip **/ - GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1); - return; - } - - for (i = 0; i < rd_len; i++) - { - if ((GNUNET_GNSRECORD_TYPE_ANY != handle->record_type) && - (rd[i].record_type != handle->record_type)) - continue; /* Apply filter */ - rd_filtered[j] = rd[i]; - rd_filtered[j].data = rd[i].data; - j++; - } - /** Only add if not empty **/ - if (j > 0) - { - if (NULL == handle->resp_object) - handle->resp_object = json_array (); - record_obj = GNUNET_GNSRECORD_JSON_from_gnsrecord (rname, - rd_filtered, - j); - json_array_append_new (handle->resp_object, record_obj); - } - GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1); -} - - -/** - * Handle lookup error - * - * @param cls the request handle - */ -static void -ns_lookup_error_cb (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->ec = GNUNET_EC_NAMESTORE_LOOKUP_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); -} - - -static void -ns_get_lookup_cb (void *cls, - const struct GNUNET_CRYPTO_PrivateKey *zone, - const char *label, - unsigned int rd_len, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - struct GNUNET_GNSRECORD_Data rd_filtered[rd_len]; - int i = 0; - int j = 0; - - handle->ns_qe = NULL; - for (i = 0; i < rd_len; i++) - { - if ((GNUNET_GNSRECORD_TYPE_ANY != handle->record_type) && - (rd[i].record_type != handle->record_type)) - continue; /* Apply filter */ - rd_filtered[j] = rd[i]; - rd_filtered[j].data = rd[i].data; - j++; - } - /** Return 404 if no set was found **/ - if (j == 0) - { - handle->ec = GNUNET_EC_NAMESTORE_RECORD_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->resp_object = GNUNET_GNSRECORD_JSON_from_gnsrecord (label, - rd_filtered, - j); - GNUNET_SCHEDULER_add_now (&namestore_list_finished, handle); -} - - -/** - * Handle namestore GET request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -namestore_get (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct GNUNET_HashCode key; - enum GNUNET_GNSRECORD_Filter filter_flags; - char *egoname; - char *labelname; - char *typename; - char *boolstring; - - egoname = NULL; - ego_entry = NULL; - - // set zone to name if given - if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url)) - { - handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1]; - ego_entry = get_egoentry_namestore (handle, egoname); - if (NULL == ego_entry) - { - handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - - GNUNET_CRYPTO_hash ("record_type", strlen ("record_type"), &key); - handle->record_type = GNUNET_GNSRECORD_TYPE_ANY; - if (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key)) - { - typename = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, - &key); - if (NULL != typename) - handle->record_type = GNUNET_GNSRECORD_typename_to_number (typename); - } - GNUNET_CRYPTO_hash ("omit_private", strlen ("omit_private"), &key); - filter_flags = GNUNET_GNSRECORD_FILTER_NONE; - if (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key)) - { - boolstring = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, - &key); - if ((0 == strcmp (boolstring, "1")) || - (0 == strcmp (boolstring, "yes")) || - (0 == strcmp (boolstring, "true"))) - filter_flags = GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE; - } - GNUNET_CRYPTO_hash ("include_maintenance", strlen ("include_maintenance"), - &key); - if (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key)) - { - boolstring = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, - &key); - if ((0 == strcmp (boolstring, "1")) || - (0 == strcmp (boolstring, "yes")) || - (0 == strcmp (boolstring, "true"))) - filter_flags |= GNUNET_GNSRECORD_FILTER_INCLUDE_MAINTENANCE; - } - labelname = &egoname[strlen (ego_entry->identifier)]; - if (1 >= strlen (labelname)) - { - /* Iterate over all records */ - handle->list_it = - GNUNET_NAMESTORE_zone_iteration_start2 (ns_handle, - handle->zone_pkey, - &namestore_iteration_error, - handle, - &namestore_list_iteration, - handle, - &namestore_list_finished, - handle, - filter_flags); - if (NULL == handle->list_it) - { - handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - return; - } - handle->record_name = GNUNET_strdup (labelname + 1); - handle->ns_qe = GNUNET_NAMESTORE_records_lookup2 (ns_handle, - handle->zone_pkey, - handle->record_name, - &ns_lookup_error_cb, - handle, - &ns_get_lookup_cb, - handle, - filter_flags); - if (NULL == handle->ns_qe) - { - handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } -} - - -static void -ns_lookup_cb (void *cls, - const struct GNUNET_CRYPTO_PrivateKey *zone, - const char *label, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - struct GNUNET_GNSRECORD_Data rd_new[rd_count + handle->rd_count]; - int i = 0; - int j = 0; - - if (UPDATE_STRATEGY_APPEND == handle->update_strategy) - { - for (i = 0; i < rd_count; i++) - rd_new[i] = rd[i]; - } - for (j = 0; j < handle->rd_count; j++) - rd_new[i + j] = handle->rd[j]; - handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, - handle->zone_pkey, - handle->record_name, - i + j, - rd_new, - &create_finished, - handle); - if (NULL == handle->ns_qe) - { - handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } -} - - -static void -bulk_tx_commit_cb (void *cls, enum GNUNET_ErrorCode ec) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - handle->ns_qe = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Commit finished (%d)\n", ec); - handle->ec = ec; - if (GNUNET_EC_NONE != ec) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -static void -import_next_cb (void *cls, enum GNUNET_ErrorCode ec) -{ - struct RequestHandle *handle = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Import finished (%d)\n", ec); - handle->ns_qe = NULL; - handle->ec = ec; - if (GNUNET_EC_NONE != ec) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - unsigned int remaining = handle->rd_set_count - handle->rd_set_pos; - if (0 == remaining) - { - handle->ns_qe = GNUNET_NAMESTORE_transaction_commit (handle->nc, - &bulk_tx_commit_cb, - handle); - return; - } - unsigned int sent_rds = 0; - // Find the smallest set of records we can send with our message size - // restriction of 16 bit - handle->ns_qe = GNUNET_NAMESTORE_records_store2 (handle->nc, - handle->zone_pkey, - remaining, - &handle->ri[handle-> - rd_set_pos], - &sent_rds, - &import_next_cb, - handle); - if ((NULL == handle->ns_qe) && (0 == sent_rds)) - { - handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->rd_set_pos += sent_rds; -} - -static void -bulk_tx_start (void *cls, enum GNUNET_ErrorCode ec) -{ - struct RequestHandle *handle = cls; - json_t *data_js; - json_error_t err; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transaction started...\n"); - handle->ec = ec; - if (GNUNET_EC_NONE != ec) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (0 >= handle->rest_handle->data_size) - { - handle->ec = GNUNET_EC_NAMESTORE_NO_RECORDS_GIVEN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - char term_data[handle->rest_handle->data_size + 1]; - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_js = json_loads (term_data, JSON_DECODE_ANY, &err); - if (NULL == data_js) - { - handle->ec = GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error parsing data: %s", err.text); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (! json_is_array (data_js)) - { - handle->ec = GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID; - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - handle->rd_set_count = json_array_size (data_js); - handle->ri = GNUNET_malloc (handle->rd_set_count - * sizeof (struct GNUNET_NAMESTORE_RecordInfo)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got record set of size %d\n", handle->rd_set_count); - char *albl; - size_t index; - json_t *value; - json_array_foreach (data_js, index, value) { - { - struct GNUNET_GNSRECORD_Data *rd; - struct GNUNET_JSON_Specification gnsspec[] = - { GNUNET_GNSRECORD_JSON_spec_gnsrecord (&rd, - &handle->ri[index].a_rd_count, - &albl), - GNUNET_JSON_spec_end () }; - if (GNUNET_OK != GNUNET_JSON_parse (value, gnsspec, NULL, NULL)) - { - handle->ec = GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID; - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - handle->ri[index].a_rd = rd; - handle->ri[index].a_label = albl; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Parsed record set for name %s\n", - handle->ri[index].a_label); - } - } - // json_decref (data_js); - - unsigned int sent_rds = 0; - // Find the smallest set of records we can send with our message size - // restriction of 16 bit - handle->ns_qe = GNUNET_NAMESTORE_records_store2 (handle->nc, - handle->zone_pkey, - handle->rd_set_count, - handle->ri, - &sent_rds, - &import_next_cb, - handle); - if ((NULL == handle->ns_qe) && (0 == sent_rds)) - { - handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->rd_set_pos += sent_rds; -} - - -/** - * Handle namestore POST import - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -namestore_import (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *egoname; - - // set zone to name if given - if (strlen (GNUNET_REST_API_NS_NAMESTORE_IMPORT) + 1 >= strlen ( - handle->url)) - { - handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - ego_entry = NULL; - - egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE_IMPORT) + 1]; - ego_entry = get_egoentry_namestore (handle, egoname); - - if (NULL == ego_entry) - { - handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - - // We need a per-client connection for a transactional bulk import - handle->nc = GNUNET_NAMESTORE_connect (cfg); - if (NULL == handle->nc) - { - handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->ns_qe = GNUNET_NAMESTORE_transaction_begin (handle->nc, - &bulk_tx_start, - handle); -} - -/** - * Handle namestore POST/PUT request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -namestore_add_or_update (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *egoname; - json_t *data_js; - json_error_t err; - - char term_data[handle->rest_handle->data_size + 1]; - - if (0 >= handle->rest_handle->data_size) - { - handle->ec = GNUNET_EC_NAMESTORE_NO_RECORDS_GIVEN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_js = json_loads (term_data, JSON_DECODE_ANY, &err); - struct GNUNET_JSON_Specification gnsspec[] = - { GNUNET_GNSRECORD_JSON_spec_gnsrecord (&handle->rd, &handle->rd_count, - &handle->record_name), - GNUNET_JSON_spec_end () }; - if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL)) - { - handle->ec = GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID; - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - GNUNET_JSON_parse_free (gnsspec); - if (0 >= strlen (handle->record_name)) - { - handle->ec = GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID; - GNUNET_SCHEDULER_add_now (&do_error, handle); - json_decref (data_js); - return; - } - json_decref (data_js); - - egoname = NULL; - ego_entry = NULL; - - // set zone to name if given - if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url)) - { - handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1]; - ego_entry = get_egoentry_namestore (handle, egoname); - - if (NULL == ego_entry) - { - handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - handle->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle, - handle->zone_pkey, - handle->record_name, - &ns_lookup_error_cb, - handle, - &ns_lookup_cb, - handle); - if (NULL == handle->ns_qe) - { - handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } -} - - -/** - * Handle namestore PUT request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -namestore_update (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - handle->update_strategy = UPDATE_STRATEGY_REPLACE; - namestore_add_or_update (con_handle, url, cls); -} - - -/** - * Handle namestore POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -namestore_add (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - handle->update_strategy = UPDATE_STRATEGY_APPEND; - namestore_add_or_update (con_handle, url, cls); -} - - -/** - * Handle namestore DELETE request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -void -namestore_delete (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *egoname; - char *labelname; - - egoname = NULL; - ego_entry = NULL; - - // set zone to name if given - if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url)) - { - handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1]; - ego_entry = get_egoentry_namestore (handle, egoname); - if (NULL == ego_entry) - { - handle->ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - labelname = &egoname[strlen (ego_entry->identifier)]; - // set zone to name if given - if (1 >= strlen (labelname)) - { - /* label is only "/" */ - handle->ec = GNUNET_EC_NAMESTORE_NO_LABEL_GIVEN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - } - - handle->record_name = GNUNET_strdup (labelname + 1); - handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, - handle->zone_pkey, - handle->record_name, - 0, - NULL, - &del_finished, - handle); - if (NULL == handle->ns_qe) - { - handle->ec = GNUNET_EC_NAMESTORE_UNKNOWN; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } -} - - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - // independent of path return all options - resp = GNUNET_REST_create_response (NULL); - GNUNET_assert (MHD_YES == - MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - allow_methods)); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); - return; -} - - -static void -list_ego (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *identifier) -{ - struct EgoEntry *ego_entry; - struct GNUNET_CRYPTO_PublicKey pk; - - if ((NULL == ego) && (ID_REST_STATE_INIT == state)) - { - state = ID_REST_STATE_POST_INIT; - return; - } - if (NULL == ego) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Called with NULL ego\n"); - return; - } - if (ID_REST_STATE_INIT == state) - { - ego_entry = GNUNET_new (struct EgoEntry); - GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = GNUNET_CRYPTO_public_key_to_string (&pk); - ego_entry->ego = ego; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail (ego_head, - ego_tail, - ego_entry); - } - /* Ego renamed or added */ - if (identifier != NULL) - { - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (ego_entry->ego == ego) - { - /* Rename */ - GNUNET_free (ego_entry->identifier); - ego_entry->identifier = GNUNET_strdup (identifier); - break; - } - } - if (NULL == ego_entry) - { - /* Add */ - ego_entry = GNUNET_new (struct EgoEntry); - GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = GNUNET_CRYPTO_public_key_to_string (&pk); - ego_entry->ego = ego; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail (ego_head, - ego_tail, - ego_entry); - } - } - else - { - /* Delete */ - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (ego_entry->ego == ego) - break; - } - if (NULL == ego_entry) - return; /* Not found */ - - GNUNET_CONTAINER_DLL_remove (ego_head, - ego_tail, - ego_entry); - GNUNET_free (ego_entry->identifier); - GNUNET_free (ego_entry->keystring); - GNUNET_free (ego_entry); - return; - } - -} - - -/** - * Function processing the REST call - * - * @param method HTTP method - * @param url URL of the HTTP request - * @param data body of the HTTP request (optional) - * @param data_size length of the body - * @param proc callback function for the result - * @param proc_cls closure for callback function - * @return GNUNET_OK if request accepted - */ -static enum GNUNET_GenericReturnValue -rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = - { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get }, - { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE_IMPORT, - &namestore_import }, - { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add }, - { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_update }, - { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, - &namestore_delete }, - { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont }, - GNUNET_REST_HANDLER_END }; - - handle->ec = GNUNET_EC_NONE; - handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->rest_handle = rest_handle; - handle->zone_pkey = NULL; - handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle); - handle->url = GNUNET_strdup (rest_handle->url); - if (handle->url[strlen (handle->url) - 1] == '/') - handle->url[strlen (handle->url) - 1] = '\0'; - GNUNET_CONTAINER_DLL_insert (requests_head, - requests_tail, - handle); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); - if (GNUNET_NO == - GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, - handle)) - { - cleanup_handle (handle); - return GNUNET_NO; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); - return GNUNET_YES; -} - - -/** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_namestore_init (void *cls) -{ - static struct Plugin plugin; - struct GNUNET_REST_Plugin *api; - - cfg = cls; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof(struct Plugin)); - plugin.cfg = cfg; - api = GNUNET_new (struct GNUNET_REST_Plugin); - api->cls = &plugin; - api->name = GNUNET_REST_API_NS_NAMESTORE; - api->process_request = &rest_process_request; - state = ID_REST_STATE_INIT; - GNUNET_asprintf (&allow_methods, - "%s, %s, %s, %s, %s", - MHD_HTTP_METHOD_GET, - MHD_HTTP_METHOD_POST, - MHD_HTTP_METHOD_PUT, - MHD_HTTP_METHOD_DELETE, - MHD_HTTP_METHOD_OPTIONS); - ns_handle = GNUNET_NAMESTORE_connect (cfg); - identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ( - "Namestore REST API initialized\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_rest_namestore_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - struct RequestHandle *request; - struct EgoEntry *ego_entry; - struct EgoEntry *ego_tmp; - - plugin->cfg = NULL; - while (NULL != (request = requests_head)) - do_error (request); - if (NULL != identity_handle) - GNUNET_IDENTITY_disconnect (identity_handle); - if (NULL != ns_handle) - GNUNET_NAMESTORE_disconnect (ns_handle); - - for (ego_entry = ego_head; NULL != ego_entry;) - { - ego_tmp = ego_entry; - ego_entry = ego_entry->next; - GNUNET_free (ego_tmp->identifier); - GNUNET_free (ego_tmp->keystring); - GNUNET_free (ego_tmp); - } - - GNUNET_free (allow_methods); - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore REST plugin is finished\n"); - return NULL; -} - - -/* end of plugin_rest_namestore.c */ diff --git a/src/rest-plugin/reclaim/Makefile.am b/src/rest-plugin/reclaim/Makefile.am deleted file mode 100644 index 7bc305bef..000000000 --- a/src/rest-plugin/reclaim/Makefile.am +++ /dev/null @@ -1,81 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include - - plugindir = $(libdir)/gnunet - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 - XLIB = -lgcov -endif - - -REST_PLUGIN = \ - libgnunet_plugin_rest_reclaim.la - -if HAVE_JOSE -REST_PLUGIN += libgnunet_plugin_rest_openid_connect.la -endif - -if HAVE_PABC - REST_PLUGIN += libgnunet_plugin_rest_pabc.la -endif - -pkgcfgdir= $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -plugin_LTLIBRARIES = \ - $(REST_PLUGIN) - -libgnunet_plugin_rest_reclaim_la_SOURCES = \ - plugin_rest_reclaim.c \ - json_reclaim.h \ - json_reclaim.c -libgnunet_plugin_rest_reclaim_la_LIBADD = \ - $(top_builddir)/src/service/identity/libgnunetidentity.la \ - $(top_builddir)/src/service/reclaim/libgnunetreclaim.la \ - $(top_builddir)/src/lib/json/libgnunetjson.la \ - $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \ - $(top_builddir)/src/service/rest/libgnunetrest.la \ - $(top_builddir)/src/service/namestore/libgnunetnamestore.la \ - $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson $(MHD_LIBS) -libgnunet_plugin_rest_reclaim_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) -libgnunet_plugin_rest_reclaim_la_CFLAGS = \ - $(MHD_CFLAGS) $(AM_CFLAGS) - -if HAVE_JOSE -libgnunet_plugin_rest_openid_connect_la_SOURCES = \ - plugin_rest_openid_connect.c \ - oidc_helper.h \ - oidc_helper.c -libgnunet_plugin_rest_openid_connect_la_LIBADD = \ - $(top_builddir)/src/service/identity/libgnunetidentity.la \ - $(top_builddir)/src/service/reclaim/libgnunetreclaim.la \ - $(top_builddir)/src/service/rest/libgnunetrest.la \ - $(top_builddir)/src/service/namestore/libgnunetnamestore.la \ - $(top_builddir)/src/service/gns/libgnunetgns.la \ - $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \ - $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson -ljose $(MHD_LIBS) \ - $(LIBGCRYPT_LIBS) -libgnunet_plugin_rest_openid_connect_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) -libgnunet_plugin_rest_openid_connect_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS) -endif - -if HAVE_PABC -libgnunet_plugin_rest_pabc_la_SOURCES = \ - plugin_rest_pabc.c \ - $(top_builddir)/src/plugin/reclaim/pabc_helper.c -libgnunet_plugin_rest_pabc_la_LIBADD = \ - $(top_builddir)/src/service/reclaim/libgnunetreclaim.la \ - $(top_builddir)/src/lib/json/libgnunetjson.la \ - $(top_builddir)/src/service/rest/libgnunetrest.la \ - $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson -lpabc $(MHD_LIBS) -libgnunet_plugin_rest_pabc_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) -libgnunet_plugin_rest_pabc_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS) -endif diff --git a/src/rest-plugin/reclaim/json_reclaim.c b/src/rest-plugin/reclaim/json_reclaim.c deleted file mode 100644 index b1ca7a4a5..000000000 --- a/src/rest-plugin/reclaim/json_reclaim.c +++ /dev/null @@ -1,398 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2009-2018 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file rest-plugins/json_reclaim.c - * @brief JSON handling of reclaim data - * @author Martin Schanzenbach - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_json_lib.h" -#include "gnunet_reclaim_lib.h" -#include "gnunet_reclaim_service.h" - - -/** - * Parse given JSON object to a claim - * - * @param cls closure, NULL - * @param root the json object representing data - * @param spec where to write the data - * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error - */ -static int -parse_attr (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) -{ - struct GNUNET_RECLAIM_Attribute *attr; - const char *name_str = NULL; - const char *val_str = NULL; - const char *type_str = NULL; - const char *id_str = NULL; - const char *cred_str = NULL; - const char *flag_str = NULL; - char *data; - int unpack_state; - uint32_t type; - size_t data_size; - - GNUNET_assert (NULL != root); - - if (! json_is_object (root)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error json is not array nor object!\n"); - return GNUNET_SYSERR; - } - // interpret single attribute - unpack_state = json_unpack (root, - "{s:s, s?s, s?s, s:s, s:s, s?s!}", - "name", - &name_str, - "id", - &id_str, - "credential", - &cred_str, - "type", - &type_str, - "value", - &val_str, - "flag", - &flag_str); - if ((0 != unpack_state) || (NULL == name_str) || (NULL == val_str) || - (NULL == type_str)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error json object has a wrong format!\n"); - return GNUNET_SYSERR; - } - type = GNUNET_RECLAIM_attribute_typename_to_number (type_str); - if (GNUNET_SYSERR == - (GNUNET_RECLAIM_attribute_string_to_value (type, - val_str, - (void **) &data, - &data_size))) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attribute value invalid!\n"); - return GNUNET_SYSERR; - } - attr = GNUNET_RECLAIM_attribute_new (name_str, NULL, - type, data, data_size); - GNUNET_free (data); - if ((NULL != cred_str) && (0 != strlen (cred_str))) - { - GNUNET_STRINGS_string_to_data (cred_str, - strlen (cred_str), - &attr->credential, - sizeof(attr->credential)); - } - if ((NULL == id_str) || (0 == strlen (id_str))) - memset (&attr->id, 0, sizeof (attr->id)); - else - GNUNET_STRINGS_string_to_data (id_str, - strlen (id_str), - &attr->id, - sizeof(attr->id)); - - *(struct GNUNET_RECLAIM_Attribute **) spec->ptr = attr; - return GNUNET_OK; -} - - -/** - * Cleanup data left from parsing RSA public key. - * - * @param cls closure, NULL - * @param[out] spec where to free the data - */ -static void -clean_attr (void *cls, struct GNUNET_JSON_Specification *spec) -{ - struct GNUNET_RECLAIM_Attribute **attr; - - attr = (struct GNUNET_RECLAIM_Attribute **) spec->ptr; - if (NULL != *attr) - { - GNUNET_free (*attr); - *attr = NULL; - } -} - - -/** - * JSON Specification for Reclaim claims. - * - * @param ticket struct of GNUNET_RECLAIM_Attribute to fill - * @return JSON Specification - */ -struct GNUNET_JSON_Specification -GNUNET_RECLAIM_JSON_spec_attribute (struct GNUNET_RECLAIM_Attribute **attr) -{ - struct GNUNET_JSON_Specification ret = { .parser = &parse_attr, - .cleaner = &clean_attr, - .cls = NULL, - .field = NULL, - .ptr = attr, - .ptr_size = 0, - .size_ptr = NULL }; - - *attr = NULL; - return ret; -} - - -/** - * Parse given JSON object to a ticket - * - * @param cls closure, NULL - * @param root the json object representing data - * @param spec where to write the data - * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error - */ -static int -parse_ticket (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) -{ - struct GNUNET_RECLAIM_Ticket *ticket; - const char *rnd_str; - const char *aud_str; - const char *id_str; - int unpack_state; - - GNUNET_assert (NULL != root); - - if (! json_is_object (root)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error json is not array nor object!\n"); - return GNUNET_SYSERR; - } - // interpret single ticket - unpack_state = json_unpack (root, - "{s:s, s:s, s:s!}", - "rnd", - &rnd_str, - "audience", - &aud_str, - "issuer", - &id_str); - if (0 != unpack_state) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Error json object has a wrong format!\n"); - return GNUNET_SYSERR; - } - ticket = GNUNET_new (struct GNUNET_RECLAIM_Ticket); - if (GNUNET_OK != GNUNET_STRINGS_string_to_data (rnd_str, - strlen (rnd_str), - &ticket->rnd, - sizeof(ticket->rnd))) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Rnd invalid\n"); - GNUNET_free (ticket); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (id_str, - strlen (id_str), - &ticket->identity, - sizeof(ticket->identity))) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Identity invalid\n"); - GNUNET_free (ticket); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (aud_str, - strlen (aud_str), - &ticket->audience, - sizeof(ticket->audience))) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Audience invalid\n"); - GNUNET_free (ticket); - return GNUNET_SYSERR; - } - - *(struct GNUNET_RECLAIM_Ticket **) spec->ptr = ticket; - return GNUNET_OK; -} - - -/** - * Cleanup data left from parsing RSA public key. - * - * @param cls closure, NULL - * @param[out] spec where to free the data - */ -static void -clean_ticket (void *cls, struct GNUNET_JSON_Specification *spec) -{ - struct GNUNET_RECLAIM_Ticket **ticket; - - ticket = (struct GNUNET_RECLAIM_Ticket **) spec->ptr; - if (NULL != *ticket) - { - GNUNET_free (*ticket); - *ticket = NULL; - } -} - - -/** - * JSON Specification for Reclaim tickets. - * - * @param ticket struct of GNUNET_RECLAIM_Ticket to fill - * @return JSON Specification - */ -struct GNUNET_JSON_Specification -GNUNET_RECLAIM_JSON_spec_ticket (struct GNUNET_RECLAIM_Ticket **ticket) -{ - struct GNUNET_JSON_Specification ret = { .parser = &parse_ticket, - .cleaner = &clean_ticket, - .cls = NULL, - .field = NULL, - .ptr = ticket, - .ptr_size = 0, - .size_ptr = NULL }; - - *ticket = NULL; - return ret; -} - - -/** - * Parse given JSON object to a credential claim - * - * @param cls closure, NULL - * @param root the json object representing data - * @param spec where to write the data - * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error - */ -static int -parse_credential (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) -{ - struct GNUNET_RECLAIM_Credential *cred; - const char *name_str = NULL; - const char *type_str = NULL; - const char *id_str = NULL; - json_t *val_json; - char *data = NULL; - char *val_str = NULL; - int unpack_state; - uint32_t type; - size_t data_size; - - GNUNET_assert (NULL != root); - - if (! json_is_object (root)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error json is not array nor object!\n"); - return GNUNET_SYSERR; - } - // interpret single attribute - unpack_state = json_unpack (root, - "{s:s, s?s, s:s, s:o!}", - "name", - &name_str, - "id", - &id_str, - "type", - &type_str, - "value", - &val_json); - if ((0 != unpack_state) || (NULL == name_str) || (NULL == val_json) || - (NULL == type_str)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error json object has a wrong format!\n"); - return GNUNET_SYSERR; - } - if (json_is_string (val_json)) { - val_str = GNUNET_strdup (json_string_value (val_json)); - } else { - val_str = json_dumps (val_json, JSON_COMPACT); - } - type = GNUNET_RECLAIM_credential_typename_to_number (type_str); - if (GNUNET_SYSERR == - (GNUNET_RECLAIM_credential_string_to_value (type, - val_str, - (void **) &data, - &data_size))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Credential value invalid!\n"); - return GNUNET_SYSERR; - } - cred = GNUNET_RECLAIM_credential_new (name_str, type, data, data_size); - GNUNET_free (data); - if ((NULL == id_str) || (0 == strlen (id_str))) - memset (&cred->id, 0, sizeof (cred->id)); - else - GNUNET_STRINGS_string_to_data (id_str, - strlen (id_str), - &cred->id, - sizeof(cred->id)); - - *(struct GNUNET_RECLAIM_Credential **) spec->ptr = cred; - return GNUNET_OK; -} - - -/** - * Cleanup data left from parsing RSA public key. - * - * @param cls closure, NULL - * @param[out] spec where to free the data - */ -static void -clean_credential (void *cls, struct GNUNET_JSON_Specification *spec) -{ - struct GNUNET_RECLAIM_Credential **attr; - - attr = (struct GNUNET_RECLAIM_Credential **) spec->ptr; - if (NULL != *attr) - { - GNUNET_free (*attr); - *attr = NULL; - } -} - - -/** - * JSON Specification for credential claims. - * - * @param attr struct of GNUNET_RECLAIM_Credential to fill - * @return JSON Specification - */ -struct GNUNET_JSON_Specification -GNUNET_RECLAIM_JSON_spec_credential (struct - GNUNET_RECLAIM_Credential **cred) -{ - struct GNUNET_JSON_Specification ret = { .parser = &parse_credential, - .cleaner = &clean_credential, - .cls = NULL, - .field = NULL, - .ptr = cred, - .ptr_size = 0, - .size_ptr = NULL }; - - *cred = NULL; - return ret; -} diff --git a/src/rest-plugin/reclaim/json_reclaim.h b/src/rest-plugin/reclaim/json_reclaim.h deleted file mode 100644 index 613ddf873..000000000 --- a/src/rest-plugin/reclaim/json_reclaim.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2009-2018 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file rest-plugins/json_reclaim.h - * @brief JSON handling of reclaim data - * @author Martin Schanzenbach - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_json_lib.h" -#include "gnunet_reclaim_service.h" -#include "gnunet_reclaim_lib.h" - -/** - * JSON Specification for Reclaim claims. - * - * @param attr struct of GNUNET_RECLAIM_Attribute to fill - * @return JSON Specification - */ -struct GNUNET_JSON_Specification -GNUNET_RECLAIM_JSON_spec_attribute (struct GNUNET_RECLAIM_Attribute **attr); - -/** - * JSON Specification for Reclaim tickets. - * - * @param ticket struct of GNUNET_RECLAIM_Ticket to fill - * @return JSON Specification - */ -struct GNUNET_JSON_Specification -GNUNET_RECLAIM_JSON_spec_ticket (struct GNUNET_RECLAIM_Ticket **ticket); - -/** - * JSON Specification for credentials. - * - * @param cred struct of GNUNET_RECLAIM_Credential to fill - * @return JSON Specification - */ -struct GNUNET_JSON_Specification -GNUNET_RECLAIM_JSON_spec_credential (struct GNUNET_RECLAIM_Credential **cred); diff --git a/src/rest-plugin/reclaim/meson.build b/src/rest-plugin/reclaim/meson.build deleted file mode 100644 index da4406850..000000000 --- a/src/rest-plugin/reclaim/meson.build +++ /dev/null @@ -1,29 +0,0 @@ -shared_module('gnunet_plugin_rest_reclaim', - ['plugin_rest_reclaim.c', 'json_reclaim.c'], - dependencies: [libgnunetrest_dep, - libgnunetidentity_dep, - libgnunetreclaim_dep, - libgnunetjson_dep, - libgnunetutil_dep, - json_dep, - mhd_dep], - include_directories: [incdir, configuration_inc], - install: true, - install_dir: get_option('libdir') / 'gnunet') - -shared_module('gnunet_plugin_rest_openid_connect', - ['plugin_rest_openid_connect.c', 'oidc_helper.c'], - dependencies: [libgnunetrest_dep, - libgnunetreclaim_dep, - libgnunetidentity_dep, - libgnunetgns_dep, - libgnunetutil_dep, - jose_dep, - gcrypt_dep, - json_dep, - mhd_dep], - include_directories: [incdir, configuration_inc], - install: true, - install_dir: get_option('libdir') / 'gnunet') - - diff --git a/src/rest-plugin/reclaim/oidc_helper.c b/src/rest-plugin/reclaim/oidc_helper.c deleted file mode 100644 index a2da7312b..000000000 --- a/src/rest-plugin/reclaim/oidc_helper.c +++ /dev/null @@ -1,1026 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2010-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file reclaim/oidc_helper.c - * @brief helper library for OIDC related functions - * @author Martin Schanzenbach - * @author Tristan Schwieren - */ -#include "platform.h" -#include -#include -#include -#include "gnunet_util_lib.h" -#include "gnunet_reclaim_lib.h" -#include "gnunet_reclaim_service.h" -#include "gnunet_signatures.h" -#include "oidc_helper.h" -// #include "benchmark.h" -#include - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * The signature used to generate the authorization code - */ -struct OIDC_Parameters -{ - /** - * The reclaim ticket - */ - struct GNUNET_RECLAIM_Ticket ticket; - - /** - * The nonce length - */ - uint32_t nonce_len GNUNET_PACKED; - - /** - * The length of the PKCE code_challenge - */ - uint32_t code_challenge_len GNUNET_PACKED; - - /** - * The length of the attributes list - */ - uint32_t attr_list_len GNUNET_PACKED; - - /** - * The length of the presentation list - */ - uint32_t pres_list_len GNUNET_PACKED; -}; - -GNUNET_NETWORK_STRUCT_END - -/** - * Standard claims represented by the "profile" scope in OIDC - */ -static char OIDC_profile_claims[14][32] = { - "name", "family_name", "given_name", "middle_name", "nickname", - "preferred_username", "profile", "picture", "website", "gender", "birthdate", - "zoneinfo", "locale", "updated_at" -}; - -/** - * Standard claims represented by the "email" scope in OIDC - */ -static char OIDC_email_claims[2][16] = { - "email", "email_verified" -}; - -/** - * Standard claims represented by the "phone" scope in OIDC - */ -static char OIDC_phone_claims[2][32] = { - "phone_number", "phone_number_verified" -}; - -/** - * Standard claims represented by the "address" scope in OIDC - */ -static char OIDC_address_claims[5][32] = { - "street_address", "locality", "region", "postal_code", "country" -}; - -static enum GNUNET_GenericReturnValue -is_claim_in_address_scope (const char *claim) -{ - int i; - for (i = 0; i < 5; i++) - { - if (0 == strcmp (claim, OIDC_address_claims[i])) - { - return GNUNET_YES; - } - } - return GNUNET_NO; -} - - -static char * -create_jwt_hmac_header (void) -{ - json_t *root; - char *json_str; - - root = json_object (); - json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE_HMAC)); - json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE)); - - json_str = json_dumps (root, JSON_INDENT (0) | JSON_COMPACT); - json_decref (root); - return json_str; -} - - -static void -replace_char (char *str, char find, char replace) -{ - char *current_pos = strchr (str, find); - - while (current_pos) - { - *current_pos = replace; - current_pos = strchr (current_pos, find); - } -} - - -// RFC4648 -static void -fix_base64 (char *str) -{ - // Replace + with - - replace_char (str, '+', '-'); - - // Replace / with _ - replace_char (str, '/', '_'); -} - - -static json_t* -generate_userinfo_json (const struct GNUNET_CRYPTO_PublicKey *sub_key, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct - GNUNET_RECLAIM_PresentationList *presentations) -{ - struct GNUNET_RECLAIM_AttributeListEntry *le; - struct GNUNET_RECLAIM_PresentationListEntry *ple; - char *subject; - char *source_name; - char *attr_val_str; - char *pres_val_str; - json_t *body; - json_t *aggr_names; - json_t *aggr_sources; - json_t *aggr_sources_jwt; - json_t *addr_claim = NULL; - int num_presentations = 0; - for (le = attrs->list_head; NULL != le; le = le->next) - { - if (GNUNET_NO == GNUNET_RECLAIM_id_is_zero (&le->attribute->credential)) - num_presentations++; - } - - subject = - GNUNET_STRINGS_data_to_string_alloc (sub_key, - sizeof(struct - GNUNET_CRYPTO_PublicKey)); - body = json_object (); - aggr_names = json_object (); - aggr_sources = json_object (); - - // iss REQUIRED case sensitive server uri with https - // The issuer is the local reclaim instance (e.g. - // https://reclaim.id/api/openid) - json_object_set_new (body, "iss", json_string (SERVER_ADDRESS)); - // sub REQUIRED public key identity, not exceed 255 ASCII length - json_object_set_new (body, "sub", json_string (subject)); - GNUNET_free (subject); - pres_val_str = NULL; - source_name = NULL; - int i = 0; - for (ple = presentations->list_head; NULL != ple; ple = ple->next) - { - // New presentation - GNUNET_asprintf (&source_name, - "src%d", - i); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Adding new presentation source #%d\n", i); - aggr_sources_jwt = json_object (); - pres_val_str = - GNUNET_RECLAIM_presentation_value_to_string (ple->presentation->type, - ple->presentation->data, - ple->presentation->data_size); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Presentation is: %s\n", pres_val_str); - json_object_set_new (aggr_sources_jwt, - GNUNET_RECLAIM_presentation_number_to_typename ( - ple->presentation->type), - json_string (pres_val_str) ); - json_object_set_new (aggr_sources, source_name, aggr_sources_jwt); - GNUNET_free (pres_val_str); - GNUNET_free (source_name); - source_name = NULL; - i++; - } - - int addr_is_aggregated = GNUNET_NO; - int addr_is_normal = GNUNET_NO; - for (le = attrs->list_head; NULL != le; le = le->next) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Processing %s for userinfo body\n", - le->attribute->name); - if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&le->attribute->credential)) - { - attr_val_str = - GNUNET_RECLAIM_attribute_value_to_string (le->attribute->type, - le->attribute->data, - le->attribute->data_size); - /** - * There is this weird quirk that the individual address claim(s) must be - * inside a JSON object of the "address" claim. - */ - if (GNUNET_YES == is_claim_in_address_scope (le->attribute->name)) - { - if (GNUNET_YES == addr_is_aggregated) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Address is set as aggregated claim. Skipping self-issued value...\n"); - GNUNET_free (attr_val_str); - continue; - } - addr_is_normal = GNUNET_YES; - - if (NULL == addr_claim) - { - addr_claim = json_object (); - json_object_set_new (body, "address", addr_claim); - } - json_object_set_new (addr_claim, le->attribute->name, - json_string (attr_val_str)); - - } - else - { - json_object_set_new (body, le->attribute->name, - json_string (attr_val_str)); - } - GNUNET_free (attr_val_str); - } - else - { - // Check if presentation is there - int j = 0; - for (ple = presentations->list_head; NULL != ple; ple = ple->next) - { - if (GNUNET_YES == - GNUNET_RECLAIM_id_is_equal (&ple->presentation->credential_id, - &le->attribute->credential)) - break; - j++; - } - if (NULL == ple) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Presentation for `%s' missing...\n", - le->attribute->name); - continue; - } - /** - * There is this weird quirk that the individual address claim(s) must be - * inside a JSON object of the "address" claim. - */ - if (GNUNET_YES == is_claim_in_address_scope (le->attribute->name)) - { - if (GNUNET_YES == addr_is_normal) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Address is already set as normal claim. Skipping attested value...\n"); - continue; - } - addr_is_aggregated = GNUNET_YES; - /** This is/can only be set once! **/ - if (NULL != addr_claim) - continue; - addr_claim = json_object (); - GNUNET_asprintf (&source_name, - "src%d", - j); - json_object_set_new (aggr_names, "address", - json_string (source_name)); - GNUNET_free (source_name); - } - else - { - // Presentation exists, hence take the respective source str - GNUNET_asprintf (&source_name, - "src%d", - j); - json_object_set_new (aggr_names, le->attribute->name, - json_string (source_name)); - GNUNET_free (source_name); - } - } - } - if (0 != i) - { - json_object_set_new (body, "_claim_names", aggr_names); - json_object_set_new (body, "_claim_sources", aggr_sources); - } - - return body; -} - - -/** - * Generate userinfo JSON as string - * - * @param sub_key the subject (user) - * @param attrs user attribute list - * @param presentations credential presentation list (may be empty) - * @return Userinfo JSON - */ -char * -OIDC_generate_userinfo (const struct GNUNET_CRYPTO_PublicKey *sub_key, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct - GNUNET_RECLAIM_PresentationList *presentations) -{ - char *body_str; - json_t*body = generate_userinfo_json (sub_key, - attrs, - presentations); - body_str = json_dumps (body, JSON_INDENT (0) | JSON_COMPACT); - json_decref (body); - return body_str; -} - - -char * -generate_id_token_body (const struct GNUNET_CRYPTO_PublicKey *aud_key, - const struct GNUNET_CRYPTO_PublicKey *sub_key, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct - GNUNET_RECLAIM_PresentationList *presentations, - const struct GNUNET_TIME_Relative *expiration_time, - const char *nonce) -{ - struct GNUNET_TIME_Absolute exp_time; - struct GNUNET_TIME_Absolute time_now; - json_t *body; - char *audience; - char *subject; - char *body_str; - - body = generate_userinfo_json (sub_key, - attrs, - presentations); - // iat REQUIRED time now - time_now = GNUNET_TIME_absolute_get (); - // exp REQUIRED time expired from config - exp_time = GNUNET_TIME_absolute_add (time_now, *expiration_time); - // auth_time only if max_age - // nonce only if nonce - // OPTIONAL acr,amr,azp - subject = - GNUNET_STRINGS_data_to_string_alloc (sub_key, - sizeof(struct - GNUNET_CRYPTO_PublicKey)); - audience = - GNUNET_STRINGS_data_to_string_alloc (aud_key, - sizeof(struct - GNUNET_CRYPTO_PublicKey)); - - // aud REQUIRED public key client_id must be there - json_object_set_new (body, "aud", json_string (audience)); - // iat - json_object_set_new (body, - "iat", - json_integer (time_now.abs_value_us / (1000 * 1000))); - // exp - json_object_set_new (body, - "exp", - json_integer (exp_time.abs_value_us / (1000 * 1000))); - // nbf - json_object_set_new (body, - "nbf", - json_integer (time_now.abs_value_us / (1000 * 1000))); - // nonce - if (NULL != nonce) - json_object_set_new (body, "nonce", json_string (nonce)); - - // Error checking - body_str = json_dumps (body, JSON_INDENT (2) | JSON_COMPACT); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"ID-Token: %s\n", body_str); - - json_decref (body); - GNUNET_free (subject); - GNUNET_free (audience); - - return body_str; -} - - -char * -OIDC_generate_id_token_rsa (const struct GNUNET_CRYPTO_PublicKey *aud_key, - const struct GNUNET_CRYPTO_PublicKey *sub_key, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct - GNUNET_RECLAIM_PresentationList *presentations, - const struct GNUNET_TIME_Relative *expiration_time, - const char *nonce, - const json_t *secret_rsa_key) -{ - json_t *jws; - char *body_str; - char *result; - - // Generate the body of the JSON Web Signature - body_str = generate_id_token_body (aud_key, - sub_key, - attrs, - presentations, - expiration_time, - nonce); - - if (NULL == body_str) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Body for the JWS could not be generated\n"); - return NULL; - } - - // Creating the JSON Web Signature. - jws = json_pack ("{s:o}", "payload", - jose_b64_enc (body_str, strlen (body_str))); - GNUNET_free (body_str); - - if (! jose_jws_sig (NULL, jws, NULL, secret_rsa_key)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Signature generation failed\n"); - return NULL; - } - - // Encoding JSON as compact JSON Web Signature - GNUNET_asprintf (&result, "%s.%s.%s", - json_string_value (json_object_get (jws, "protected")), - json_string_value (json_object_get (jws, "payload")), - json_string_value (json_object_get (jws, "signature")) ); - - json_decref (jws); - return result; -} - -/** - * Create a JWT using HMAC (HS256) from attributes - * - * @param aud_key the public of the audience - * @param sub_key the public key of the subject - * @param attrs the attribute list - * @param presentations credential presentation list (may be empty) - * @param expiration_time the validity of the token - * @param secret_key the key used to sign the JWT - * @return a new base64-encoded JWT string. - */ -char * -OIDC_generate_id_token_hmac (const struct GNUNET_CRYPTO_PublicKey *aud_key, - const struct GNUNET_CRYPTO_PublicKey *sub_key, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct - GNUNET_RECLAIM_PresentationList *presentations, - const struct GNUNET_TIME_Relative *expiration_time, - const char *nonce, - const char *secret_key) -{ - struct GNUNET_HashCode signature; - char *header; - char *header_base64; - char *body_str; - char *body_base64; - char *signature_target; - char *signature_base64; - char *result; - - // Generate and encode Header - header = create_jwt_hmac_header (); - if (NULL == header) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Header for the JWS could not be generated\n"); - return NULL; - } - GNUNET_STRINGS_base64url_encode (header, strlen (header), &header_base64); - GNUNET_free (header); - fix_base64 (header_base64); - - // Generate and encode the body of the JSON Web Signature - body_str = generate_id_token_body (aud_key, - sub_key, - attrs, - presentations, - expiration_time, - nonce); - - if (NULL == body_str) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Body for the JWS could not be generated\n"); - GNUNET_free (header_base64); - return NULL; - } - - GNUNET_STRINGS_base64url_encode (body_str, strlen (body_str), &body_base64); - fix_base64 (body_base64); - - /** - * Creating the JWT signature. This might not be - * standards compliant, check. - */ - GNUNET_asprintf (&signature_target, "%s.%s", header_base64, body_base64); - GNUNET_CRYPTO_hmac_raw (secret_key, - strlen (secret_key), - signature_target, - strlen (signature_target), - &signature); - GNUNET_STRINGS_base64url_encode ((const char *) &signature, - sizeof(struct GNUNET_HashCode), - &signature_base64); - fix_base64 (signature_base64); - - GNUNET_asprintf (&result, - "%s.%s.%s", - header_base64, - body_base64, - signature_base64); - - GNUNET_free (header_base64); - GNUNET_free (body_str); - GNUNET_free (body_base64); - GNUNET_free (signature_target); - GNUNET_free (signature_base64); - return result; -} - - -/** - * Builds an OIDC authorization code including - * a reclaim ticket and nonce - * - * @param issuer the issuer of the ticket, used to sign the ticket and nonce - * @param ticket the ticket to include in the code - * @param attrs list of attributes which are shared - * @param presentations credential presentation list (may be empty) - * @param nonce the nonce to include in the code - * @param code_challenge PKCE code challenge - * @return a new authorization code (caller must free) - */ -char * -OIDC_build_authz_code (const struct GNUNET_CRYPTO_PrivateKey *issuer, - const struct GNUNET_RECLAIM_Ticket *ticket, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct - GNUNET_RECLAIM_PresentationList *presentations, - const char *nonce_str, - const char *code_challenge) -{ - struct OIDC_Parameters params; - char *code_payload; - char *payload; - char *tmp; - char *code_str; - char *buf_ptr = NULL; - size_t payload_len; - size_t code_payload_len; - size_t attr_list_len = 0; - size_t pres_list_len = 0; - size_t code_challenge_len = 0; - uint32_t nonce_len = 0; - struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; - - /** PLAINTEXT **/ - // Assign ticket - memset (¶ms, 0, sizeof(params)); - params.ticket = *ticket; - // Assign nonce - payload_len = sizeof(struct OIDC_Parameters); - if ((NULL != nonce_str) && (strcmp ("", nonce_str) != 0)) - { - nonce_len = strlen (nonce_str); - payload_len += nonce_len; - } - params.nonce_len = htonl (nonce_len); - // Assign code challenge - if (NULL != code_challenge) - code_challenge_len = strlen (code_challenge); - payload_len += code_challenge_len; - params.code_challenge_len = htonl (code_challenge_len); - // Assign attributes - if (NULL != attrs) - { - // Get length - attr_list_len = GNUNET_RECLAIM_attribute_list_serialize_get_size (attrs); - params.attr_list_len = htonl (attr_list_len); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Length of serialized attributes: %lu\n", - attr_list_len); - // Get serialized attributes - payload_len += attr_list_len; - } - if (NULL != presentations) - { - // Get length - // FIXME only add presentations relevant for attribute list!!! - // This is important because of the distinction between id_token and - // userinfo in OIDC - pres_list_len = - GNUNET_RECLAIM_presentation_list_serialize_get_size (presentations); - params.pres_list_len = htonl (pres_list_len); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Length of serialized presentations: %lu\n", - pres_list_len); - // Get serialized attributes - payload_len += pres_list_len; - } - - // Get plaintext length - payload = GNUNET_malloc (payload_len); - memcpy (payload, ¶ms, sizeof(params)); - tmp = payload + sizeof(params); - if (0 < code_challenge_len) - { - memcpy (tmp, code_challenge, code_challenge_len); - tmp += code_challenge_len; - } - if (0 < nonce_len) - { - memcpy (tmp, nonce_str, nonce_len); - tmp += nonce_len; - } - if (0 < attr_list_len) - GNUNET_RECLAIM_attribute_list_serialize (attrs, tmp); - tmp += attr_list_len; - if (0 < pres_list_len) - GNUNET_RECLAIM_presentation_list_serialize (presentations, tmp); - tmp += pres_list_len; - - /** END **/ - - // Get length - code_payload_len = sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) - + payload_len + sizeof(struct - GNUNET_CRYPTO_Signature); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Length of data to encode: %lu\n", - code_payload_len); - - // Initialize code payload - code_payload = GNUNET_malloc (code_payload_len); - GNUNET_assert (NULL != code_payload); - purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload; - purpose->size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) - + payload_len); - purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN); - // Store pubkey - buf_ptr = (char *) &purpose[1]; - memcpy (buf_ptr, payload, payload_len); - GNUNET_free (payload); - buf_ptr += payload_len; - // Sign and store signature - if (GNUNET_SYSERR == - GNUNET_CRYPTO_sign_ (issuer, - purpose, - (struct GNUNET_CRYPTO_Signature *) - buf_ptr)) - { - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to sign code\n"); - GNUNET_free (code_payload); - return NULL; - } - GNUNET_STRINGS_base64url_encode (code_payload, code_payload_len, &code_str); - GNUNET_free (code_payload); - return code_str; -} - - -enum GNUNET_GenericReturnValue -check_code_challenge (const char *code_challenge, - uint32_t code_challenge_len, - const char *code_verifier) -{ - char *code_verifier_hash; - char *expected_code_challenge; - - if (0 == code_challenge_len) /* Only check if this code requires a CV */ - return GNUNET_OK; - if (NULL == code_verifier) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected code verifier!\n"); - return GNUNET_SYSERR; - } - code_verifier_hash = GNUNET_malloc (256 / 8); - // hash code verifier - gcry_md_hash_buffer (GCRY_MD_SHA256, - code_verifier_hash, - code_verifier, - strlen (code_verifier)); - // encode code verifier - GNUNET_STRINGS_base64url_encode (code_verifier_hash, 256 / 8, - &expected_code_challenge); - GNUNET_free (code_verifier_hash); - if (0 != - strncmp (expected_code_challenge, code_challenge, code_challenge_len)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid code verifier! Expected: %s, Got: %.*s\n", - expected_code_challenge, - code_challenge_len, - code_challenge); - GNUNET_free (expected_code_challenge); - return GNUNET_SYSERR; - } - GNUNET_free (expected_code_challenge); - return GNUNET_OK; -} - - -/** - * Parse reclaim ticket and nonce from - * authorization code. - * This also verifies the signature in the code. - * - * @param audience the expected audience of the code - * @param code the string representation of the code - * @param code_verfier PKCE code verifier. Optional, must be provided - * if used in request. - * @param ticket where to store the ticket - * @param attrs the attributes in the code - * @param presentations credential presentation list - * @param nonce_str where to store the nonce (if contained) - * @return GNUNET_OK if successful, else GNUNET_SYSERR - */ -int -OIDC_parse_authz_code (const struct GNUNET_CRYPTO_PublicKey *audience, - const char *code, - const char *code_verifier, - struct GNUNET_RECLAIM_Ticket *ticket, - struct GNUNET_RECLAIM_AttributeList **attrs, - struct GNUNET_RECLAIM_PresentationList **presentations, - char **nonce_str, - enum OIDC_VerificationOptions opts) -{ - char *code_payload; - char *ptr; - char *plaintext; - char *attrs_ser; - char *presentations_ser; - char *code_challenge; - struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; - struct GNUNET_CRYPTO_Signature *signature; - uint32_t code_challenge_len; - uint32_t attrs_ser_len; - uint32_t pres_ser_len; - size_t plaintext_len; - size_t code_payload_len; - uint32_t nonce_len = 0; - struct OIDC_Parameters *params; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to decode `%s'\n", code); - code_payload = NULL; - code_payload_len = - GNUNET_STRINGS_base64url_decode (code, strlen (code), - (void **) &code_payload); - if (code_payload_len < sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) - + sizeof(struct OIDC_Parameters) - + sizeof(struct GNUNET_CRYPTO_Signature)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Authorization code malformed\n"); - GNUNET_free (code_payload); - return GNUNET_SYSERR; - } - - purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload; - plaintext_len = code_payload_len; - plaintext_len -= sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose); - ptr = (char *) &purpose[1]; - plaintext_len -= sizeof(struct GNUNET_CRYPTO_Signature); - plaintext = ptr; - ptr += plaintext_len; - signature = (struct GNUNET_CRYPTO_Signature *) ptr; - params = (struct OIDC_Parameters *) plaintext; - - // cmp code_challenge code_verifier - code_challenge_len = ntohl (params->code_challenge_len); - code_challenge = ((char *) ¶ms[1]); - if (! (opts & OIDC_VERIFICATION_NO_CODE_VERIFIER)) - { - if (GNUNET_OK != check_code_challenge (code_challenge, - code_challenge_len, - code_verifier)) - { - GNUNET_free (code_payload); - return GNUNET_SYSERR; - } - } - nonce_len = ntohl (params->nonce_len); - if (0 != nonce_len) - { - *nonce_str = GNUNET_strndup (code_challenge + code_challenge_len, - nonce_len); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got nonce: %s\n", *nonce_str); - } - - // Ticket - memcpy (ticket, ¶ms->ticket, sizeof(params->ticket)); - // Signature - // GNUNET_CRYPTO_ecdsa_key_get_public (ecdsa_priv, &ecdsa_pub); - if (0 != GNUNET_memcmp (audience, &ticket->audience)) - { - GNUNET_free (code_payload); - if (NULL != *nonce_str) - GNUNET_free (*nonce_str); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Audience in ticket does not match client!\n"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CRYPTO_signature_verify_ ( - GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN, - purpose, - signature, - &(ticket->identity))) - { - GNUNET_free (code_payload); - if (NULL != *nonce_str) - GNUNET_free (*nonce_str); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signature of AuthZ code invalid!\n"); - return GNUNET_SYSERR; - } - // Attributes - attrs_ser = ((char *) ¶ms[1]) + code_challenge_len + nonce_len; - attrs_ser_len = ntohl (params->attr_list_len); - *attrs = GNUNET_RECLAIM_attribute_list_deserialize (attrs_ser, attrs_ser_len); - presentations_ser = ((char*) attrs_ser) + attrs_ser_len; - pres_ser_len = ntohl (params->pres_list_len); - *presentations = - GNUNET_RECLAIM_presentation_list_deserialize (presentations_ser, - pres_ser_len); - - GNUNET_free (code_payload); - return GNUNET_OK; -} - - -/** - * Build a token response for a token request - * TODO: Maybe we should add the scope here? - * - * @param access_token the access token to include - * @param id_token the id_token to include - * @param expiration_time the expiration time of the token(s) - * @param token_response where to store the response - */ -void -OIDC_build_token_response (const char *access_token, - const char *id_token, - const struct GNUNET_TIME_Relative *expiration_time, - char **token_response) -{ - json_t *root_json; - - root_json = json_object (); - - GNUNET_assert (NULL != access_token); - GNUNET_assert (NULL != id_token); - GNUNET_assert (NULL != expiration_time); - json_object_set_new (root_json, "access_token", json_string (access_token)); - json_object_set_new (root_json, "token_type", json_string ("Bearer")); - json_object_set_new (root_json, - "expires_in", - json_integer (expiration_time->rel_value_us - / (1000 * 1000))); - json_object_set_new (root_json, "id_token", json_string (id_token)); - *token_response = json_dumps (root_json, JSON_INDENT (0) | JSON_COMPACT); - json_decref (root_json); -} - - -/** - * Generate a new access token - */ -char * -OIDC_access_token_new (const struct GNUNET_RECLAIM_Ticket *ticket) -{ - char *access_token; - - GNUNET_STRINGS_base64_encode (ticket, - sizeof(*ticket), - &access_token); - return access_token; -} - - -/** - * Parse an access token - */ -int -OIDC_access_token_parse (const char *token, - struct GNUNET_RECLAIM_Ticket **ticket) -{ - size_t sret; - char *decoded; - sret = GNUNET_STRINGS_base64_decode (token, - strlen (token), - (void**) &decoded); - if (sizeof (struct GNUNET_RECLAIM_Ticket) != sret) - { - GNUNET_free (decoded); - return GNUNET_SYSERR; - } - *ticket = (struct GNUNET_RECLAIM_Ticket *) decoded; - return GNUNET_OK; -} - - -/** - * Checks if a claim is implicitly requested through standard - * scope(s) or explicitly through non-standard scope. - * - * @param scopes the scopes which have been requested - * @param attr the attribute name to check - * @return GNUNET_YES if attribute is implcitly requested - */ -enum GNUNET_GenericReturnValue -OIDC_check_scopes_for_claim_request (const char*scopes, - const char*attr) -{ - char *scope_variables; - char *scope_variable; - char delimiter[] = " "; - int i; - - scope_variables = GNUNET_strdup (scopes); - scope_variable = strtok (scope_variables, delimiter); - while (NULL != scope_variable) - { - if (0 == strcmp ("profile", scope_variable)) - { - for (i = 0; i < 14; i++) - { - if (0 == strcmp (attr, OIDC_profile_claims[i])) - { - GNUNET_free (scope_variables); - return GNUNET_YES; - } - } - } - else if (0 == strcmp ("address", scope_variable)) - { - for (i = 0; i < 5; i++) - { - if (0 == strcmp (attr, OIDC_address_claims[i])) - { - GNUNET_free (scope_variables); - return GNUNET_YES; - } - } - } - else if (0 == strcmp ("email", scope_variable)) - { - for (i = 0; i < 2; i++) - { - if (0 == strcmp (attr, OIDC_email_claims[i])) - { - GNUNET_free (scope_variables); - return GNUNET_YES; - } - } - } - else if (0 == strcmp ("phone", scope_variable)) - { - for (i = 0; i < 2; i++) - { - if (0 == strcmp (attr, OIDC_phone_claims[i])) - { - GNUNET_free (scope_variables); - return GNUNET_YES; - } - } - - } - else if (0 == strcmp (attr, scope_variable)) - { - /** attribute matches requested scope **/ - GNUNET_free (scope_variables); - return GNUNET_YES; - } - scope_variable = strtok (NULL, delimiter); - } - GNUNET_free (scope_variables); - return GNUNET_NO; - -} diff --git a/src/rest-plugin/reclaim/oidc_helper.h b/src/rest-plugin/reclaim/oidc_helper.h deleted file mode 100644 index de788fbdb..000000000 --- a/src/rest-plugin/reclaim/oidc_helper.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2010-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file reclaim/oidc_helper.h - * @brief helper library for OIDC related functions - * @author Martin Schanzenbach - */ - -#ifndef JWT_H -#define JWT_H - -#define JWT_ALG "alg" -#define JWT_TYP "typ" -#define JWT_TYP_VALUE "jwt" - -#define JWT_ALG_VALUE_HMAC "HS512" -#define JWT_ALG_VALUE_RSA "RS256" - -#define SERVER_ADDRESS "http://localhost:7776" - -enum OIDC_VerificationOptions -{ - /** - * Strict verification - */ - OIDC_VERIFICATION_DEFAULT = 0, - - /** - * Do not check code verifier even if expected - */ - OIDC_VERIFICATION_NO_CODE_VERIFIER = 1 -}; - -/** - * Create a JWT using RSA256 algorithm from attributes - * - * @param aud_key the public of the audience - * @param sub_key the public key of the subject - * @param attrs the attribute list - * @param presentations credential presentation list (may be empty) - * @param expiration_time the validity of the token - * @param secret_rsa_key the key used to sign the JWT - * @return a new base64-encoded JWT string. - */ -char * -OIDC_generate_id_token_rsa (const struct GNUNET_CRYPTO_PublicKey *aud_key, - const struct GNUNET_CRYPTO_PublicKey *sub_key, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct - GNUNET_RECLAIM_PresentationList *presentations, - const struct GNUNET_TIME_Relative *expiration_time, - const char *nonce, - const json_t *secret_rsa_key); - -/** - * Create a JWT using HMAC (HS256) from attributes - * - * @param aud_key the public of the audience - * @param sub_key the public key of the subject - * @param attrs the attribute list - * @param presentations credential presentation list (may be empty) - * @param expiration_time the validity of the token - * @param secret_key the key used to sign the JWT - * @return a new base64-encoded JWT string. - */ -char* -OIDC_generate_id_token_hmac (const struct GNUNET_CRYPTO_PublicKey *aud_key, - const struct GNUNET_CRYPTO_PublicKey *sub_key, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct - GNUNET_RECLAIM_PresentationList *presentations, - const struct GNUNET_TIME_Relative *expiration_time, - const char *nonce, - const char *secret_key); - -/** - * Builds an OIDC authorization code including - * a reclaim ticket and nonce - * - * @param issuer the issuer of the ticket, used to sign the ticket and nonce - * @param ticket the ticket to include in the code - * @param attrs list of attributes to share - * @param presentations credential presentation list - * @param nonce the nonce to include in the code - * @param code_challenge PKCE code challenge - * @param opts verification options - * @return a new authorization code (caller must free) - */ -char* -OIDC_build_authz_code (const struct GNUNET_CRYPTO_PrivateKey *issuer, - const struct GNUNET_RECLAIM_Ticket *ticket, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct - GNUNET_RECLAIM_PresentationList *presentations, - const char *nonce, - const char *code_challenge); - -/** - * Parse reclaim ticket and nonce from - * authorization code. - * This also verifies the signature in the code. - * - * @param ecdsa_priv the audience of the ticket - * @param code the string representation of the code - * @param code_verfier PKCE code verifier - * @param ticket where to store the ticket - * @param attrs the attributes found in the code - * @param presentations credential presentation list - * @param nonce where to store the nonce - * @return GNUNET_OK if successful, else GNUNET_SYSERR - */ -int -OIDC_parse_authz_code (const struct GNUNET_CRYPTO_PublicKey *ecdsa_pub, - const char *code, - const char *code_verifier, - struct GNUNET_RECLAIM_Ticket *ticket, - struct GNUNET_RECLAIM_AttributeList **attrs, - struct GNUNET_RECLAIM_PresentationList **presentations, - char **nonce, - enum OIDC_VerificationOptions opts); - -/** - * Build a token response for a token request - * TODO: Maybe we should add the scope here? - * - * @param access_token the access token to include - * @param id_token the id_token to include - * @param expiration_time the expiration time of the token(s) - * @param token_response where to store the response - */ -void -OIDC_build_token_response (const char *access_token, - const char *id_token, - const struct GNUNET_TIME_Relative *expiration_time, - char **token_response); - -/** - * Generate a new access token - */ -char* -OIDC_access_token_new (const struct GNUNET_RECLAIM_Ticket *ticket); - -/** - * Parse an access token - */ -int -OIDC_access_token_parse (const char *token, - struct GNUNET_RECLAIM_Ticket **ticket); - - -/** - * Checks if a claim is implicitly requested through standard - * scope(s) - * - * @param scopes the scopes which have been requested - * @param attr the attribute name to check - * @return GNUNET_YES if attribute is implcitly requested - */ -enum GNUNET_GenericReturnValue -OIDC_check_scopes_for_claim_request (const char *scopes, - const char *attr); - - -/** - * Generate userinfo JSON as string - * - * @param sub_key the subject (user) - * @param attrs user attribute list - * @param presentations credential presentation list - * @return Userinfo JSON - */ -char * -OIDC_generate_userinfo (const struct GNUNET_CRYPTO_PublicKey *sub_key, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct - GNUNET_RECLAIM_PresentationList *presentations); - -#endif diff --git a/src/rest-plugin/reclaim/plugin_rest_openid_connect.c b/src/rest-plugin/reclaim/plugin_rest_openid_connect.c deleted file mode 100644 index d0aee043e..000000000 --- a/src/rest-plugin/reclaim/plugin_rest_openid_connect.c +++ /dev/null @@ -1,3162 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2018 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ -/** - * @author Martin Schanzenbach - * @author Philippe Buschmann - * @author Tristan Schwieren - * @file identity/plugin_rest_openid_connect.c - * @brief GNUnet Namestore REST plugin - * - */ -#include "platform.h" -#include -#include -#include - -#include "gnunet_util_lib.h" -#include "gnunet_gns_service.h" -#include "gnunet_gnsrecord_lib.h" -#include "gnunet_identity_service.h" -#include "gnunet_namestore_service.h" -#include "gnunet_reclaim_lib.h" -#include "gnunet_reclaim_service.h" -#include "gnunet_rest_lib.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_signatures.h" -#include "microhttpd.h" -#include "oidc_helper.h" - -/** - * REST root namespace - */ -#define GNUNET_REST_API_NS_OIDC "/openid" - -/** - * OIDC config - */ -#define GNUNET_REST_API_NS_OIDC_CONFIG "/.well-known/openid-configuration" - -/** - * Authorize endpoint - */ -#define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize" - -/** - * Token endpoint - */ -#define GNUNET_REST_API_NS_TOKEN "/openid/token" - -/** - * JSON Web Keys endpoint - */ -#define GNUNET_REST_API_JWKS "/jwks.json" - -/** - * UserInfo endpoint - */ -#define GNUNET_REST_API_NS_USERINFO "/openid/userinfo" - -/** - * Login namespace - */ -#define GNUNET_REST_API_NS_LOGIN "/openid/login" - -/** - * State while collecting all egos - */ -#define ID_REST_STATE_INIT 0 - -/** - * Done collecting egos - */ -#define ID_REST_STATE_POST_INIT 1 - -/** - * OIDC grant_type key - */ -#define OIDC_GRANT_TYPE_KEY "grant_type" - -/** - * OIDC grant_type key - */ -#define OIDC_GRANT_TYPE_VALUE "authorization_code" - -/** - * OIDC code key - */ -#define OIDC_CODE_KEY "code" - -/** - * OIDC response_type key - */ -#define OIDC_RESPONSE_TYPE_KEY "response_type" - -/** - * OIDC client_id key - */ -#define OIDC_CLIENT_ID_KEY "client_id" - -/** - * OIDC scope key - */ -#define OIDC_SCOPE_KEY "scope" - -/** - * OIDC redirect_uri key - */ -#define OIDC_REDIRECT_URI_KEY "redirect_uri" - -/** - * OIDC state key - */ -#define OIDC_STATE_KEY "state" - -/** - * OIDC nonce key - */ -#define OIDC_NONCE_KEY "nonce" - -/** - * OIDC claims key - */ -#define OIDC_CLAIMS_KEY "claims" - -/** - * OIDC PKCE code challenge - */ -#define OIDC_CODE_CHALLENGE_KEY "code_challenge" - -/** - * OIDC PKCE code verifier - */ -#define OIDC_CODE_VERIFIER_KEY "code_verifier" - -/** - * OIDC cookie expiration (in seconds) - */ -#define OIDC_COOKIE_EXPIRATION 3 - -/** - * OIDC cookie header key - */ -#define OIDC_COOKIE_HEADER_KEY "cookie" - -/** - * OIDC cookie header information key - */ -#define OIDC_AUTHORIZATION_HEADER_KEY "authorization" - -/** - * OIDC cookie header information key - */ -#define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity=" - -/** - * OIDC cookie header if user cancelled - */ -#define OIDC_COOKIE_HEADER_ACCESS_DENIED "Identity=Denied" - -/** - * OIDC expected response_type while authorizing - */ -#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code" - -/** - * OIDC expected scope part while authorizing - */ -#define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid" - -/** - * OIDC error key for invalid client - */ -#define OIDC_ERROR_KEY_INVALID_CLIENT "invalid_client" - -/** - * OIDC error key for invalid scopes - */ -#define OIDC_ERROR_KEY_INVALID_SCOPE "invalid_scope" - -/** - * OIDC error key for invalid requests - */ -#define OIDC_ERROR_KEY_INVALID_REQUEST "invalid_request" - -/** - * OIDC error key for invalid tokens - */ -#define OIDC_ERROR_KEY_INVALID_TOKEN "invalid_token" - -/** - * OIDC error key for invalid cookies - */ -#define OIDC_ERROR_KEY_INVALID_COOKIE "invalid_cookie" - -/** - * OIDC error key for generic server errors - */ -#define OIDC_ERROR_KEY_SERVER_ERROR "server_error" - -/** - * OIDC error key for unsupported grants - */ -#define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE "unsupported_grant_type" - -/** - * OIDC error key for unsupported response types - */ -#define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE "unsupported_response_type" - -/** - * OIDC error key for unauthorized clients - */ -#define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT "unauthorized_client" - -/** - * OIDC error key for denied access - */ -#define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied" - -/** - * OIDC key store file name - */ -#define OIDC_JWK_RSA_FILENAME "jwk_rsa.json" - -/** - * How long to wait for a consume in userinfo endpoint - */ -#define CONSUME_TIMEOUT GNUNET_TIME_relative_multiply ( \ - GNUNET_TIME_UNIT_SECONDS,2) - -/** - * OIDC ignored parameter array - */ -static char *OIDC_ignored_parameter_array[] = { "display", - "prompt", - "ui_locales", - "response_mode", - "id_token_hint", - "login_hint", - "acr_values" }; - -/** - * OIDC hashmap for cached access tokens and codes - */ -struct GNUNET_CONTAINER_MultiHashMap *oidc_code_cache; - -/** - * OIDC hashmap that keeps track of issued cookies - */ -struct GNUNET_CONTAINER_MultiHashMap *OIDC_cookie_jar_map; - -/** - * The configuration handle - */ -const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * HTTP methods allows for this plugin - */ -static char *allow_methods; - -/** - * Ego list - */ -static struct EgoEntry *ego_head; - -/** - * Ego list - */ -static struct EgoEntry *ego_tail; - -/** - * The processing state - */ -static int state; - -/** - * Handle to Identity service. - */ -static struct GNUNET_IDENTITY_Handle *identity_handle; - -/** - * GNS handle - */ -static struct GNUNET_GNS_Handle *gns_handle; - -/** - * Identity Provider - */ -static struct GNUNET_RECLAIM_Handle *idp; - -/** - * Timeout for consume call on userinfo - */ -static struct GNUNET_TIME_Relative consume_timeout; - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - -/** - * @brief The RSA key used by the oidc enpoint - */ -json_t *oidc_jwk; - -/** - * OIDC needed variables - */ -struct OIDC_Variables -{ - /** - * The RP client public key - */ - struct GNUNET_CRYPTO_PublicKey client_pkey; - - /** - * The OIDC client id of the RP - */ - char *client_id; - - /** - * The OIDC redirect uri - */ - char *redirect_uri; - - /** - * The list of oidc scopes - */ - char *scope; - - /** - * The OIDC state - */ - char *state; - - /** - * The OIDC nonce - */ - char *nonce; - - /** - * The OIDC claims - */ - char *claims; - - /** - * The OIDC response type - */ - char *response_type; - - /** - * The identity chosen by the user to login - */ - char *login_identity; - - /** - * User cancelled authorization/login - */ - int user_cancelled; - - /** - * The PKCE code_challenge - */ - char *code_challenge; - - /** - * The PKCE code_verifier - */ - char *code_verifier; - -}; - -/** - * The ego list - */ -struct EgoEntry -{ - /** - * DLL - */ - struct EgoEntry *next; - - /** - * DLL - */ - struct EgoEntry *prev; - - /** - * Ego Identifier - */ - char *identifier; - - /** - * Public key string - */ - char *keystring; - - /** - * The Ego - */ - struct GNUNET_IDENTITY_Ego *ego; -}; - - -struct RequestHandle -{ - /** - * DLL - */ - struct RequestHandle *next; - - /** - * DLL - */ - struct RequestHandle *prev; - - /** - * Selected ego - */ - struct EgoEntry *ego_entry; - - /** - * Pointer to ego private key - */ - struct GNUNET_CRYPTO_PrivateKey priv_key; - - /** - * OIDC variables - */ - struct OIDC_Variables *oidc; - - /** - * GNS lookup op - */ - struct GNUNET_GNS_LookupRequest *gns_op; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * Attribute claim list for id_token - */ - struct GNUNET_RECLAIM_AttributeList *attr_idtoken_list; - - /** - * Attribute claim list for userinfo - */ - struct GNUNET_RECLAIM_AttributeList *attr_userinfo_list; - - /** - * Credentials - */ - struct GNUNET_RECLAIM_CredentialList *credentials; - - /** - * Presentations - */ - struct GNUNET_RECLAIM_PresentationList *presentations; - - /** - * IDENTITY Operation - */ - struct GNUNET_IDENTITY_Operation *op; - - - /** - * Idp Operation - */ - struct GNUNET_RECLAIM_Operation *idp_op; - - /** - * Timeout task for consume - */ - struct GNUNET_SCHEDULER_Task *consume_timeout_op; - - /** - * Attribute iterator - */ - struct GNUNET_RECLAIM_AttributeIterator *attr_it; - - /** - * Credential iterator - */ - struct GNUNET_RECLAIM_CredentialIterator *cred_it; - - - /** - * Ticket iterator - */ - struct GNUNET_RECLAIM_TicketIterator *ticket_it; - - /** - * A ticket - */ - struct GNUNET_RECLAIM_Ticket ticket; - - /** - * Desired timeout for the lookup (default is no timeout). - */ - struct GNUNET_TIME_Relative timeout; - - /** - * ID of a task associated with the resolution process. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * The passed access token - */ - char *access_token; - - /** - * The tld for redirect - */ - char *tld; - - /** - * The redirect prefix - */ - char *redirect_prefix; - - /** - * The redirect suffix - */ - char *redirect_suffix; - - /** - * Error response message - */ - char *emsg; - - /** - * Error response description - */ - char *edesc; - - /** - * Response code - */ - int response_code; - - /** - * Public client - */ - int public_client; -}; - -/** - * DLL - */ -static struct RequestHandle *requests_head; - -/** - * DLL - */ -static struct RequestHandle *requests_tail; - - -/** - * Cleanup lookup handle - * @param handle Handle to clean up - */ -static void -cleanup_handle (struct RequestHandle *handle) -{ - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); - if (NULL != handle->timeout_task) - GNUNET_SCHEDULER_cancel (handle->timeout_task); - if (NULL != handle->attr_it) - GNUNET_RECLAIM_get_attributes_stop (handle->attr_it); - if (NULL != handle->cred_it) - GNUNET_RECLAIM_get_credentials_stop (handle->cred_it); - if (NULL != handle->ticket_it) - GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it); - if (NULL != handle->idp_op) - GNUNET_RECLAIM_cancel (handle->idp_op); - if (NULL != handle->consume_timeout_op) - GNUNET_SCHEDULER_cancel (handle->consume_timeout_op); - GNUNET_free (handle->url); - GNUNET_free (handle->tld); - GNUNET_free (handle->redirect_prefix); - GNUNET_free (handle->redirect_suffix); - GNUNET_free (handle->emsg); - GNUNET_free (handle->edesc); - if (NULL != handle->gns_op) - GNUNET_GNS_lookup_cancel (handle->gns_op); - if (NULL != handle->oidc) - { - GNUNET_free (handle->oidc->client_id); - GNUNET_free (handle->oidc->login_identity); - GNUNET_free (handle->oidc->nonce); - GNUNET_free (handle->oidc->redirect_uri); - GNUNET_free (handle->oidc->response_type); - GNUNET_free (handle->oidc->scope); - GNUNET_free (handle->oidc->state); - if (NULL != handle->oidc->claims) - GNUNET_free (handle->oidc->claims); - if (NULL != handle->oidc->code_challenge) - GNUNET_free (handle->oidc->code_challenge); - GNUNET_free (handle->oidc); - } - if (NULL!=handle->attr_idtoken_list) - GNUNET_RECLAIM_attribute_list_destroy (handle->attr_idtoken_list); - if (NULL!=handle->attr_userinfo_list) - GNUNET_RECLAIM_attribute_list_destroy (handle->attr_userinfo_list); - if (NULL!=handle->credentials) - GNUNET_RECLAIM_credential_list_destroy (handle->credentials); - if (NULL!=handle->presentations) - GNUNET_RECLAIM_presentation_list_destroy (handle->presentations); - GNUNET_CONTAINER_DLL_remove (requests_head, - requests_tail, - handle); - if (NULL != handle->access_token) - GNUNET_free (handle->access_token); - GNUNET_free (handle); -} - - -/** - * Task run on error, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *json_error; - - GNUNET_asprintf (&json_error, - "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}", - handle->emsg, - (NULL != handle->edesc) ? handle->edesc : "", - (NULL != handle->oidc->state) ? ", \"state\":\"" : "", - (NULL != handle->oidc->state) ? handle->oidc->state : "", - (NULL != handle->oidc->state) ? "\"" : ""); - if (0 == handle->response_code) - handle->response_code = MHD_HTTP_BAD_REQUEST; - resp = GNUNET_REST_create_response (json_error); - if (MHD_HTTP_UNAUTHORIZED == handle->response_code) - GNUNET_assert (MHD_NO != - MHD_add_response_header (resp, - MHD_HTTP_HEADER_WWW_AUTHENTICATE, - "Basic")); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - MHD_HTTP_HEADER_CONTENT_TYPE, - "application/json")); - handle->proc (handle->proc_cls, resp, handle->response_code); - cleanup_handle (handle); - GNUNET_free (json_error); -} - - -/** - * Task run on error in userinfo endpoint, sends error header. Cleans up - * everything - * - * @param cls the `struct RequestHandle` - */ -static void -do_userinfo_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *error; - - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error: %s\n", handle->edesc); - GNUNET_asprintf (&error, - "error=\"%s\", error_description=\"%s\"", - handle->emsg, - (NULL != handle->edesc) ? handle->edesc : ""); - resp = GNUNET_REST_create_response (""); - GNUNET_assert (MHD_NO != - MHD_add_response_header (resp, - MHD_HTTP_HEADER_WWW_AUTHENTICATE, - "Bearer")); - handle->proc (handle->proc_cls, resp, handle->response_code); - cleanup_handle (handle); - GNUNET_free (error); -} - - -/** - * Task run on error, sends error message and redirects. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_redirect_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *redirect; - - GNUNET_asprintf (&redirect, - "%s?error=%s&error_description=%s%s%s", - handle->oidc->redirect_uri, - handle->emsg, - handle->edesc, - (NULL != handle->oidc->state) ? "&state=" : "", - (NULL != handle->oidc->state) ? handle->oidc->state : ""); - resp = GNUNET_REST_create_response (""); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Location", redirect)); - handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); - cleanup_handle (handle); - GNUNET_free (redirect); -} - - -/** - * Task run on timeout, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_timeout (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->timeout_task = NULL; - do_error (handle); -} - - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - // For now, independent of path return all options - resp = GNUNET_REST_create_response (NULL); - MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - cleanup_handle (handle); - return; -} - - -/** - * Interprets cookie header and pass its identity keystring to handle - */ -static void -cookie_identity_interpretation (struct RequestHandle *handle) -{ - struct GNUNET_HashCode cache_key; - char *cookies; - struct GNUNET_TIME_Absolute current_time, *relog_time; - char delimiter[] = "; "; - char *tmp_cookies; - char *token; - char *value; - - // gets identity of login try with cookie - GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, - strlen (OIDC_COOKIE_HEADER_KEY), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle - ->header_param_map, - &cache_key)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cookie found\n"); - return; - } - // splits cookies and find 'Identity' cookie - tmp_cookies = - GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map, - &cache_key); - cookies = GNUNET_strdup (tmp_cookies); - token = strtok (cookies, delimiter); - handle->oidc->user_cancelled = GNUNET_NO; - handle->oidc->login_identity = NULL; - if (NULL == token) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse cookie: %s\n", - cookies); - GNUNET_free (cookies); - return; - } - - while (NULL != token) - { - if (0 == strcmp (token, OIDC_COOKIE_HEADER_ACCESS_DENIED)) - { - handle->oidc->user_cancelled = GNUNET_YES; - GNUNET_free (cookies); - return; - } - if (NULL != strstr (token, OIDC_COOKIE_HEADER_INFORMATION_KEY)) - break; - token = strtok (NULL, delimiter); - } - if (NULL == token) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No cookie value to process: %s\n", - cookies); - GNUNET_free (cookies); - return; - } - GNUNET_CRYPTO_hash (token, strlen (token), &cache_key); - if (GNUNET_NO == - GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key)) - { - GNUNET_log ( - GNUNET_ERROR_TYPE_WARNING, - "Found cookie `%s', but no corresponding expiration entry present...\n", - token); - GNUNET_free (cookies); - return; - } - relog_time = - GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key); - current_time = GNUNET_TIME_absolute_get (); - // 30 min after old login -> redirect to login - if (current_time.abs_value_us > relog_time->abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Found cookie `%s', but it is expired.\n", - token); - GNUNET_free (cookies); - return; - } - value = strtok (token, OIDC_COOKIE_HEADER_INFORMATION_KEY); - GNUNET_assert (NULL != value); - handle->oidc->login_identity = GNUNET_strdup (value); - GNUNET_free (cookies); -} - - -/** - * @brief Read the the JSON Web Key in the given file and return it. - * Return NULL and emit warning if JSON can not be decoded or the key is - * invalid - * - * @param filename the file to read the JWK from - * @return json_t* the reed JWK - */ -json_t * -read_jwk_from_file (const char *filename) -{ - json_t *jwk; - json_error_t error; - - jwk = json_load_file (filename, JSON_DECODE_ANY, &error); - - if (! jwk) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - ("Could not read OIDC RSA key from config file; %s\n"), - error.text); - } - - return jwk; -} - -/** - * @brief Write the JWK to file. If unsuccessful emit warning - * - * @param filename the name of the file the JWK is writen to - * @param jwk the JWK that is going to be written - * @return int Return GNUNET_OK if write is sucessfull - */ -static int -write_jwk_to_file (const char *filename, - json_t *jwk) -{ - if (json_dump_file (jwk, filename, JSON_INDENT (2))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - ("Could not write OIDC RSA key to file %s\n"), - filename); - return GNUNET_ERROR_TYPE_WARNING; - } - else - return GNUNET_OK; -} - -/** - * @brief Generate a new RSA JSON Web Key - * - * @return json_t* the generated JWK - */ -json_t * -generate_jwk () -{ - json_t *jwk; - jwk = json_pack ("{s:s,s:i}", "kty", "RSA", "bits", 2048); - jose_jwk_gen (NULL, jwk); - json_incref (jwk); - return jwk; -} - -/** - * Return the path to the oidc directory path - * - * @param cls the RequestHandle - */ -char * -get_oidc_dir_path (void *cls) -{ - char *oidc_directory; - struct RequestHandle *handle = cls; - - // Read OIDC directory from config - if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, - "reclaim-rest-plugin", - "oidc_dir", - &oidc_directory)) - { - // Could not read Config file - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); - handle->edesc = GNUNET_strdup ("gnunet configuration failed"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return NULL; - } - - return oidc_directory; -} - -/** - * Return the path to the RSA JWK key file - * - * @param cls the RequestHandle - */ -char * -get_oidc_jwk_path (void *cls) -{ - char *oidc_directory; - char *oidc_jwk_path; - - oidc_directory = get_oidc_dir_path (cls); - - // Create path to file - GNUNET_asprintf (&oidc_jwk_path, "%s/%s", oidc_directory, - OIDC_JWK_RSA_FILENAME); - - return oidc_jwk_path; -} - - -/** - * Redirects to login page stored in configuration file - */ -static void -login_redirect (void *cls) -{ - char *login_base_url; - char *new_redirect; - char *tmp; - struct MHD_Response *resp; - struct GNUNET_Buffer buf = { 0 }; - struct RequestHandle *handle = cls; - - if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, - "reclaim-rest-plugin", - "address", - &login_base_url)) - { - GNUNET_buffer_write_str (&buf, login_base_url); - GNUNET_buffer_write_fstr (&buf, - "?%s=%s", - OIDC_RESPONSE_TYPE_KEY, - handle->oidc->response_type); - GNUNET_buffer_write_fstr (&buf, - "&%s=%s", - OIDC_CLIENT_ID_KEY, - handle->oidc->client_id); - GNUNET_STRINGS_urlencode (handle->oidc->redirect_uri, - strlen (handle->oidc->redirect_uri), - &tmp); - GNUNET_buffer_write_fstr (&buf, - "&%s=%s", - OIDC_REDIRECT_URI_KEY, - tmp); - GNUNET_free (tmp); - GNUNET_STRINGS_urlencode (handle->oidc->scope, - strlen (handle->oidc->scope), - &tmp); - GNUNET_buffer_write_fstr (&buf, - "&%s=%s", - OIDC_SCOPE_KEY, - tmp); - GNUNET_free (tmp); - if (NULL != handle->oidc->state) - { - GNUNET_STRINGS_urlencode (handle->oidc->state, - strlen (handle->oidc->state), - &tmp); - GNUNET_buffer_write_fstr (&buf, - "&%s=%s", - OIDC_STATE_KEY, - handle->oidc->state); - GNUNET_free (tmp); - } - if (NULL != handle->oidc->code_challenge) - { - GNUNET_buffer_write_fstr (&buf, - "&%s=%s", - OIDC_CODE_CHALLENGE_KEY, - handle->oidc->code_challenge); - } - if (NULL != handle->oidc->nonce) - { - GNUNET_buffer_write_fstr (&buf, - "&%s=%s", - OIDC_NONCE_KEY, - handle->oidc->nonce); - } - if (NULL != handle->oidc->claims) - { - GNUNET_STRINGS_urlencode (handle->oidc->claims, - strlen (handle->oidc->claims), - &tmp); - GNUNET_buffer_write_fstr (&buf, - "&%s=%s", - OIDC_CLAIMS_KEY, - tmp); - GNUNET_free (tmp); - } - new_redirect = GNUNET_buffer_reap_str (&buf); - resp = GNUNET_REST_create_response (""); - MHD_add_response_header (resp, "Location", new_redirect); - GNUNET_free (login_base_url); - } - else - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); - handle->edesc = GNUNET_strdup ("gnunet configuration failed"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); - GNUNET_free (new_redirect); - cleanup_handle (handle); -} - - -/** - * Does internal server error when iteration failed. - */ -static void -oidc_iteration_error (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); -} - - -/** - * Issues ticket and redirects to relying party with the authorization code as - * parameter. Otherwise redirects with error - */ -static void -oidc_ticket_issue_cb (void *cls, - const struct GNUNET_RECLAIM_Ticket *ticket, - const struct - GNUNET_RECLAIM_PresentationList *presentation) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *ticket_str; - char *redirect_uri; - char *code_string; - - handle->idp_op = NULL; - if (NULL == ticket) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); - handle->edesc = GNUNET_strdup ("Server cannot generate ticket."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - handle->ticket = *ticket; - ticket_str = - GNUNET_STRINGS_data_to_string_alloc (&handle->ticket, - sizeof(struct GNUNET_RECLAIM_Ticket)); - code_string = OIDC_build_authz_code (&handle->priv_key, - &handle->ticket, - handle->attr_idtoken_list, - presentation, - handle->oidc->nonce, - handle->oidc->code_challenge); - if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) && - (NULL != handle->tld)) - { - GNUNET_asprintf (&redirect_uri, - "%s.%s/%s%s%s=%s&state=%s", - handle->redirect_prefix, - handle->tld, - handle->redirect_suffix, - (NULL == strchr (handle->redirect_suffix, '?') ? "?" : - "&"), - handle->oidc->response_type, - code_string, - handle->oidc->state); - } - else - { - GNUNET_asprintf (&redirect_uri, - "%s%s%s=%s&state=%s", - handle->oidc->redirect_uri, - (NULL == strchr (handle->oidc->redirect_uri, '?') ? "?" : - "&"), - handle->oidc->response_type, - code_string, - handle->oidc->state); - } - resp = GNUNET_REST_create_response (""); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Location", redirect_uri)); - handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); - cleanup_handle (handle); - GNUNET_free (redirect_uri); - GNUNET_free (ticket_str); - GNUNET_free (code_string); -} - - -static struct GNUNET_RECLAIM_AttributeList* -attribute_list_merge (struct GNUNET_RECLAIM_AttributeList *list_a, - struct GNUNET_RECLAIM_AttributeList *list_b) -{ - struct GNUNET_RECLAIM_AttributeList *merged_list; - struct GNUNET_RECLAIM_AttributeListEntry *le_a; - struct GNUNET_RECLAIM_AttributeListEntry *le_b; - struct GNUNET_RECLAIM_AttributeListEntry *le_m; - - merged_list = GNUNET_new (struct GNUNET_RECLAIM_AttributeList); - for (le_a = list_a->list_head; NULL != le_a; le_a = le_a->next) - { - le_m = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry); - le_m->attribute = GNUNET_RECLAIM_attribute_new (le_a->attribute->name, - &le_a->attribute-> - credential, - le_a->attribute->type, - le_a->attribute->data, - le_a->attribute->data_size); - le_m->attribute->id = le_a->attribute->id; - le_m->attribute->flag = le_a->attribute->flag; - le_m->attribute->credential = le_a->attribute->credential; - GNUNET_CONTAINER_DLL_insert (merged_list->list_head, - merged_list->list_tail, - le_m); - } - le_m = NULL; - for (le_b = list_b->list_head; NULL != le_b; le_b = le_b->next) - { - for (le_m = merged_list->list_head; NULL != le_m; le_m = le_m->next) - { - if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (&le_m->attribute->id, - &le_b->attribute->id)) - break; /** Attribute already in list **/ - } - if (NULL != le_m) - continue; /** Attribute already in list **/ - le_m = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry); - le_m->attribute = GNUNET_RECLAIM_attribute_new (le_b->attribute->name, - &le_b->attribute-> - credential, - le_b->attribute->type, - le_b->attribute->data, - le_b->attribute->data_size); - le_m->attribute->id = le_b->attribute->id; - le_m->attribute->flag = le_b->attribute->flag; - le_m->attribute->credential = le_b->attribute->credential; - GNUNET_CONTAINER_DLL_insert (merged_list->list_head, - merged_list->list_tail, - le_m); - } - return merged_list; -} - - -static void -oidc_cred_collect_finished_cb (void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_RECLAIM_AttributeList *merged_list; - struct GNUNET_RECLAIM_AttributeListEntry *le_m; - - handle->cred_it = NULL; - merged_list = attribute_list_merge (handle->attr_idtoken_list, - handle->attr_userinfo_list); - for (le_m = merged_list->list_head; NULL != le_m; le_m = le_m->next) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "List Attribute in ticket to issue: %s\n", - le_m->attribute->name); - handle->idp_op = GNUNET_RECLAIM_ticket_issue (idp, - &handle->priv_key, - &handle->oidc->client_pkey, - merged_list, - &oidc_ticket_issue_cb, - handle); - GNUNET_RECLAIM_attribute_list_destroy (merged_list); -} - - -/** - * Collects all attributes for an ego if in scope parameter - */ -static void -oidc_cred_collect (void *cls, - const struct GNUNET_CRYPTO_PublicKey *identity, - const struct GNUNET_RECLAIM_Credential *cred) -{ - struct RequestHandle *handle = cls; - struct GNUNET_RECLAIM_AttributeListEntry *le; - struct GNUNET_RECLAIM_CredentialListEntry *ale; - - for (ale = handle->credentials->list_head; NULL != ale; ale = ale->next) - { - if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (&ale->credential->id, - &cred->id)) - continue; - /** Credential already in list **/ - GNUNET_RECLAIM_get_credentials_next (handle->cred_it); - return; - } - - for (le = handle->attr_idtoken_list->list_head; NULL != le; le = le->next) - { - if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (&le->attribute->credential, - &cred->id)) - continue; - /** Credential matches for attribute, add **/ - ale = GNUNET_new (struct GNUNET_RECLAIM_CredentialListEntry); - ale->credential = GNUNET_RECLAIM_credential_new (cred->name, - cred->type, - cred->data, - cred->data_size); - GNUNET_CONTAINER_DLL_insert (handle->credentials->list_head, - handle->credentials->list_tail, - ale); - } - GNUNET_RECLAIM_get_credentials_next (handle->cred_it); -} - - -static void -oidc_attr_collect_finished_cb (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->attr_it = NULL; - handle->ticket_it = NULL; - if (NULL == handle->attr_idtoken_list->list_head) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE); - handle->edesc = GNUNET_strdup ("The requested scope is not available."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - handle->credentials = GNUNET_new (struct GNUNET_RECLAIM_CredentialList); - handle->cred_it = - GNUNET_RECLAIM_get_credentials_start (idp, - &handle->priv_key, - &oidc_iteration_error, - handle, - &oidc_cred_collect, - handle, - &oidc_cred_collect_finished_cb, - handle); - -} - - -static int -attr_in_claims_request (struct RequestHandle *handle, - const char *attr_name, - const char *claims_parameter) -{ - int ret = GNUNET_NO; - json_t *root; - json_error_t error; - json_t *claims_j; - const char *key; - json_t *value; - - /** Check if attribute is requested through a scope **/ - if (GNUNET_YES == OIDC_check_scopes_for_claim_request (handle->oidc->scope, - attr_name)) - return GNUNET_YES; - - /** Try claims parameter if not in scope */ - if (NULL != handle->oidc->claims) - { - root = json_loads (handle->oidc->claims, JSON_DECODE_ANY, &error); - claims_j = json_object_get (root, claims_parameter); - /* obj is a JSON object */ - if (NULL != claims_j) - { - json_object_foreach (claims_j, key, value) { - if (0 != strcmp (attr_name, key)) - continue; - ret = GNUNET_YES; - break; - } - } - json_decref (root); - } - return ret; -} - - -static int -attr_in_idtoken_request (struct RequestHandle *handle, - const char *attr_name) -{ - return attr_in_claims_request (handle, attr_name, "id_token"); -} - - -static int -attr_in_userinfo_request (struct RequestHandle *handle, - const char *attr_name) -{ - return attr_in_claims_request (handle, attr_name, "userinfo"); -} - - -/** - * Collects all attributes for an ego if in scope parameter - */ -static void -oidc_attr_collect (void *cls, - const struct GNUNET_CRYPTO_PublicKey *identity, - const struct GNUNET_RECLAIM_Attribute *attr) -{ - struct RequestHandle *handle = cls; - struct GNUNET_RECLAIM_AttributeListEntry *le; - if (GNUNET_YES == attr_in_idtoken_request (handle, attr->name)) - { - le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry); - le->attribute = GNUNET_RECLAIM_attribute_new (attr->name, - &attr->credential, - attr->type, - attr->data, - attr->data_size); - le->attribute->id = attr->id; - le->attribute->flag = attr->flag; - le->attribute->credential = attr->credential; - GNUNET_CONTAINER_DLL_insert (handle->attr_idtoken_list->list_head, - handle->attr_idtoken_list->list_tail, - le); - } - if (GNUNET_YES == attr_in_userinfo_request (handle, attr->name)) - { - le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry); - le->attribute = GNUNET_RECLAIM_attribute_new (attr->name, - &attr->credential, - attr->type, - attr->data, - attr->data_size); - le->attribute->id = attr->id; - le->attribute->flag = attr->flag; - le->attribute->credential = attr->credential; - GNUNET_CONTAINER_DLL_insert (handle->attr_userinfo_list->list_head, - handle->attr_userinfo_list->list_tail, - le); - } - - GNUNET_RECLAIM_get_attributes_next (handle->attr_it); -} - - -/** - * Checks time and cookie and redirects accordingly - */ -static void -code_redirect (void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_TIME_Absolute current_time; - struct GNUNET_TIME_Absolute *relog_time; - struct GNUNET_CRYPTO_PublicKey pubkey; - struct GNUNET_CRYPTO_PublicKey ego_pkey; - struct GNUNET_HashCode cache_key; - char *identity_cookie; - - GNUNET_asprintf (&identity_cookie, - "Identity=%s", - handle->oidc->login_identity); - GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key); - GNUNET_free (identity_cookie); - // No login time for identity -> redirect to login - if (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key)) - { - relog_time = - GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key); - current_time = GNUNET_TIME_absolute_get (); - // 30 min after old login -> redirect to login - if (current_time.abs_value_us <= relog_time->abs_value_us) - { - if (GNUNET_OK != - GNUNET_CRYPTO_public_key_from_string (handle->oidc - ->login_identity, - &pubkey)) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_COOKIE); - handle->edesc = - GNUNET_strdup ("The cookie of a login identity is not valid"); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - // iterate over egos and compare their public key - for (handle->ego_entry = ego_head; NULL != handle->ego_entry; - handle->ego_entry = handle->ego_entry->next) - { - GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey); - if (0 == GNUNET_memcmp (&ego_pkey, &pubkey)) - { - handle->priv_key = - *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego); - handle->attr_idtoken_list = - GNUNET_new (struct GNUNET_RECLAIM_AttributeList); - handle->attr_userinfo_list = - GNUNET_new (struct GNUNET_RECLAIM_AttributeList); - handle->attr_it = - GNUNET_RECLAIM_get_attributes_start (idp, - &handle->priv_key, - &oidc_iteration_error, - handle, - &oidc_attr_collect, - handle, - &oidc_attr_collect_finished_cb, - handle); - return; - } - } - GNUNET_SCHEDULER_add_now (&login_redirect, handle); - return; - } - } -} - - -static void -build_redirect (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *redirect_uri; - - if (GNUNET_YES == handle->oidc->user_cancelled) - { - if ((NULL != handle->redirect_prefix) && - (NULL != handle->redirect_suffix) && (NULL != handle->tld)) - { - GNUNET_asprintf (&redirect_uri, - "%s.%s/%s?error=%s&error_description=%s&state=%s", - handle->redirect_prefix, - handle->tld, - handle->redirect_suffix, - "access_denied", - "User denied access", - handle->oidc->state); - } - else - { - GNUNET_asprintf (&redirect_uri, - "%s?error=%s&error_description=%s&state=%s", - handle->oidc->redirect_uri, - "access_denied", - "User denied access", - handle->oidc->state); - } - resp = GNUNET_REST_create_response (""); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Location", - redirect_uri)); - handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); - cleanup_handle (handle); - GNUNET_free (redirect_uri); - return; - } - GNUNET_SCHEDULER_add_now (&code_redirect, handle); -} - - -static void -lookup_redirect_uri_result (void *cls, - uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - char *tmp; - char *tmp_key_str; - char *pos; - struct GNUNET_CRYPTO_PublicKey redirect_zone; - - handle->gns_op = NULL; - if (0 == rd_count) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); - handle->edesc = - GNUNET_strdup ("Server cannot generate ticket, redirect uri not found."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - for (int i = 0; i < rd_count; i++) - { - if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type) - continue; - if (0 != strncmp (rd[i].data, handle->oidc->redirect_uri, rd[i].data_size)) - continue; - tmp = GNUNET_strndup (rd[i].data, rd[i].data_size); - if (NULL == strstr (tmp, handle->oidc->client_id)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Redirect uri %s does not contain client_id %s\n", - tmp, - handle->oidc->client_id); - } - else - { - pos = strrchr (tmp, (unsigned char) '.'); - if (NULL == pos) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Redirect uri %s contains client_id but is malformed\n", - tmp); - GNUNET_free (tmp); - continue; - } - *pos = '\0'; - handle->redirect_prefix = GNUNET_strdup (tmp); - tmp_key_str = pos + 1; - pos = strchr (tmp_key_str, (unsigned char) '/'); - if (NULL == pos) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Redirect uri %s contains client_id but is malformed\n", - tmp); - GNUNET_free (tmp); - continue; - } - *pos = '\0'; - handle->redirect_suffix = GNUNET_strdup (pos + 1); - - GNUNET_STRINGS_string_to_data (tmp_key_str, - strlen (tmp_key_str), - &redirect_zone, - sizeof(redirect_zone)); - } - GNUNET_SCHEDULER_add_now (&build_redirect, handle); - GNUNET_free (tmp); - return; - } - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); - handle->edesc = - GNUNET_strdup ("Server cannot generate ticket, redirect uri not found."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); -} - - -/** - * Initiate redirect back to client. - */ -static void -client_redirect (void *cls) -{ - struct RequestHandle *handle = cls; - - /* Lookup client redirect uri to verify request */ - handle->gns_op = - GNUNET_GNS_lookup (gns_handle, - GNUNET_GNS_EMPTY_LABEL_AT, - &handle->oidc->client_pkey, - GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT, - GNUNET_GNS_LO_DEFAULT, - &lookup_redirect_uri_result, - handle); -} - - -static char * -get_url_parameter_copy (const struct RequestHandle *handle, const char *key) -{ - struct GNUNET_HashCode hc; - char *value; - char *res; - - GNUNET_CRYPTO_hash (key, strlen (key), &hc); - if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle - ->url_param_map, - &hc)) - return NULL; - value = - GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, &hc); - if (NULL == value) - return NULL; - GNUNET_STRINGS_urldecode (value, strlen (value), &res); - return res; -} - - -/** - * Iteration over all results finished, build final - * response. - * - * @param cls the `struct RequestHandle` - */ -static void -build_authz_response (void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_HashCode cache_key; - - char *expected_scope; - char delimiter[] = " "; - int number_of_ignored_parameter, iterator; - - - // REQUIRED value: redirect_uri - handle->oidc->redirect_uri = - get_url_parameter_copy (handle, OIDC_REDIRECT_URI_KEY); - if (NULL == handle->oidc->redirect_uri) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); - handle->edesc = GNUNET_strdup ("missing parameter redirect_uri"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - // REQUIRED value: response_type - handle->oidc->response_type = - get_url_parameter_copy (handle, OIDC_RESPONSE_TYPE_KEY); - if (NULL == handle->oidc->response_type) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); - handle->edesc = GNUNET_strdup ("missing parameter response_type"); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - - // REQUIRED value: scope - handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY); - if (NULL == handle->oidc->scope) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE); - handle->edesc = GNUNET_strdup ("missing parameter scope"); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - - // OPTIONAL value: nonce - handle->oidc->nonce = get_url_parameter_copy (handle, OIDC_NONCE_KEY); - - // OPTIONAL value: claims - handle->oidc->claims = get_url_parameter_copy (handle, OIDC_CLAIMS_KEY); - - // TODO check other values if needed - number_of_ignored_parameter = - sizeof(OIDC_ignored_parameter_array) / sizeof(char *); - for (iterator = 0; iterator < number_of_ignored_parameter; iterator++) - { - GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator], - strlen (OIDC_ignored_parameter_array[iterator]), - &cache_key); - if (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle - ->url_param_map, - &cache_key)) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_ACCESS_DENIED); - GNUNET_asprintf (&handle->edesc, - "Server will not handle parameter: %s", - OIDC_ignored_parameter_array[iterator]); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - } - - // We only support authorization code flows. - if (0 != strcmp (handle->oidc->response_type, - OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE)) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE); - handle->edesc = GNUNET_strdup ("The authorization server does not support " - "obtaining this authorization code."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - - // Checks if scope contains 'openid' - expected_scope = GNUNET_strdup (handle->oidc->scope); - char *test; - test = strtok (expected_scope, delimiter); - while (NULL != test) - { - if (0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope)) - break; - test = strtok (NULL, delimiter); - } - if (NULL == test) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE); - handle->edesc = - GNUNET_strdup ("The requested scope is invalid, unknown, or malformed."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - GNUNET_free (expected_scope); - return; - } - - GNUNET_free (expected_scope); - if ((NULL == handle->oidc->login_identity) && - (GNUNET_NO == handle->oidc->user_cancelled)) - GNUNET_SCHEDULER_add_now (&login_redirect, handle); - else - GNUNET_SCHEDULER_add_now (&client_redirect, handle); -} - - -/** - * Iterate over tlds in config - */ -static void -tld_iter (void *cls, const char *section, const char *option, const char *value) -{ - struct RequestHandle *handle = cls; - struct GNUNET_CRYPTO_PublicKey pkey; - - if (GNUNET_OK != - GNUNET_CRYPTO_public_key_from_string (value, &pkey)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping non key %s\n", value); - return; - } - if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey)) - handle->tld = GNUNET_strdup (option + 1); -} - - -/** - * Responds to authorization GET and url-encoded POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct EgoEntry *tmp_ego; - const struct GNUNET_CRYPTO_PrivateKey *priv_key; - struct GNUNET_CRYPTO_PublicKey pkey; - - cookie_identity_interpretation (handle); - - // RECOMMENDED value: state - REQUIRED for answers - handle->oidc->state = get_url_parameter_copy (handle, OIDC_STATE_KEY); - - // REQUIRED value: client_id - handle->oidc->client_id = get_url_parameter_copy (handle, OIDC_CLIENT_ID_KEY); - if (NULL == handle->oidc->client_id) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); - handle->edesc = GNUNET_strdup ("missing parameter client_id"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - // OPTIONAL value: code_challenge - handle->oidc->code_challenge = get_url_parameter_copy (handle, - OIDC_CODE_CHALLENGE_KEY); - if (NULL == handle->oidc->code_challenge) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "OAuth authorization request does not contain PKCE parameters!\n"); - } - - if (GNUNET_OK != - GNUNET_CRYPTO_public_key_from_string (handle->oidc->client_id, - &handle->oidc->client_pkey)) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT); - handle->edesc = GNUNET_strdup ("The client is not authorized to request an " - "authorization code using this method."); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - // If we know this identity, translated the corresponding TLD - // TODO: We might want to have a reverse lookup functionality for TLDs? - for (tmp_ego = ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next) - { - priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego); - GNUNET_CRYPTO_key_get_public (priv_key, &pkey); - if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey)) - { - handle->tld = GNUNET_strdup (tmp_ego->identifier); - handle->ego_entry = ego_tail; - } - } - if (NULL == handle->tld) - GNUNET_CONFIGURATION_iterate_section_values (cfg, "gns", tld_iter, handle); - if (NULL == handle->tld) - handle->tld = GNUNET_strdup (handle->oidc->client_id); - GNUNET_SCHEDULER_add_now (&build_authz_response, handle); -} - - -/** - * Combines an identity with a login time and responds OK to login request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -login_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct MHD_Response *resp = GNUNET_REST_create_response (""); - struct RequestHandle *handle = cls; - struct GNUNET_HashCode cache_key; - struct GNUNET_TIME_Absolute *current_time; - struct GNUNET_TIME_Absolute *last_time; - char *cookie; - char *header_val; - json_t *root; - json_error_t error; - json_t *identity; - char term_data[handle->rest_handle->data_size + 1]; - - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - root = json_loads (term_data, JSON_DECODE_ANY, &error); - identity = json_object_get (root, "identity"); - if (! json_is_string (identity)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error parsing json string from %s\n", - term_data); - handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); - json_decref (root); - cleanup_handle (handle); - return; - } - GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity)); - GNUNET_asprintf (&header_val, - "%s;Max-Age=%d", - cookie, - OIDC_COOKIE_EXPIRATION); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Set-Cookie", header_val)); - GNUNET_assert (MHD_NO != - MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - "POST")); - GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key); - - if (0 != strcmp (json_string_value (identity), "Denied")) - { - current_time = GNUNET_new (struct GNUNET_TIME_Absolute); - *current_time = GNUNET_TIME_relative_to_absolute ( - GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (), - OIDC_COOKIE_EXPIRATION)); - last_time = - GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key); - GNUNET_free (last_time); - GNUNET_CONTAINER_multihashmap_put (OIDC_cookie_jar_map, - &cache_key, - current_time, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); - } - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (cookie); - GNUNET_free (header_val); - json_decref (root); - cleanup_handle (handle); -} - - -static int -parse_credentials_basic_auth (struct RequestHandle *handle, - char **client_id, - char **client_secret) -{ - struct GNUNET_HashCode cache_key; - char *authorization; - char *credentials; - char *basic_authorization; - char *client_id_tmp; - char *pass; - - GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, - strlen (OIDC_AUTHORIZATION_HEADER_KEY), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle - ->header_param_map, - &cache_key)) - return GNUNET_SYSERR; - authorization = - GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map, - &cache_key); - - // split header in "Basic" and [content] - credentials = strtok (authorization, " "); - if ((NULL == credentials) || (0 != strcmp ("Basic", credentials))) - return GNUNET_SYSERR; - credentials = strtok (NULL, " "); - if (NULL == credentials) - return GNUNET_SYSERR; - GNUNET_STRINGS_base64_decode (credentials, - strlen (credentials), - (void **) &basic_authorization); - - if (NULL == basic_authorization) - return GNUNET_SYSERR; - client_id_tmp = strtok (basic_authorization, ":"); - if (NULL == client_id_tmp) - { - GNUNET_free (basic_authorization); - return GNUNET_SYSERR; - } - pass = strtok (NULL, ":"); - if (NULL == pass) - { - GNUNET_free (basic_authorization); - return GNUNET_SYSERR; - } - *client_id = strdup (client_id_tmp); - *client_secret = strdup (pass); - GNUNET_free (basic_authorization); - return GNUNET_OK; -} - - -static int -parse_credentials_post_body (struct RequestHandle *handle, - char **client_id, - char **client_secret) -{ - struct GNUNET_HashCode cache_key; - char *client_id_tmp; - char *pass; - - GNUNET_CRYPTO_hash ("client_id", - strlen ("client_id"), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle - ->url_param_map, - &cache_key)) - return GNUNET_SYSERR; - client_id_tmp = GNUNET_CONTAINER_multihashmap_get ( - handle->rest_handle->url_param_map, - &cache_key); - if (NULL == client_id_tmp) - return GNUNET_SYSERR; - *client_id = strdup (client_id_tmp); - GNUNET_CRYPTO_hash ("client_secret", - strlen ("client_secret"), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle - ->url_param_map, - &cache_key)) - { - GNUNET_free (*client_id); - *client_id = NULL; - return GNUNET_SYSERR; - } - pass = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, - &cache_key); - if (NULL == pass) - { - GNUNET_free (*client_id); - *client_id = NULL; - return GNUNET_SYSERR; - } - *client_secret = strdup (pass); - return GNUNET_OK; -} - - -static int -check_authorization (struct RequestHandle *handle, - struct GNUNET_CRYPTO_PublicKey *cid) -{ - char *expected_pass; - char *received_cid; - char *received_cpw; - char *pkce_cv; - - if (GNUNET_OK == parse_credentials_basic_auth (handle, - &received_cid, - &received_cpw)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received client credentials in HTTP AuthZ header\n"); - } - else if (GNUNET_OK == parse_credentials_post_body (handle, - &received_cid, - &received_cpw)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received client credentials in POST body\n"); - } - else - { - /** Allow public clients with PKCE **/ - pkce_cv = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY); - if (NULL == pkce_cv) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - return GNUNET_SYSERR; - } - handle->public_client = GNUNET_YES; - GNUNET_free (pkce_cv); - received_cid = get_url_parameter_copy (handle, OIDC_CLIENT_ID_KEY); - GNUNET_STRINGS_string_to_data (received_cid, - strlen (received_cid), - cid, - sizeof(struct GNUNET_CRYPTO_PublicKey)); - GNUNET_free (received_cid); - return GNUNET_OK; - - } - - // check client password - if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, - "reclaim-rest-plugin", - "OIDC_CLIENT_HMAC_SECRET", - &expected_pass)) - { - if (0 != strcmp (expected_pass, received_cpw)) - { - GNUNET_free (expected_pass); - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_free (received_cpw); - GNUNET_free (received_cid); - return GNUNET_SYSERR; - } - GNUNET_free (expected_pass); - } - else - { - GNUNET_free (received_cpw); - GNUNET_free (received_cid); - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); - handle->edesc = GNUNET_strdup ("gnunet configuration failed"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - return GNUNET_SYSERR; - } - // check client_id - for (handle->ego_entry = ego_head; NULL != handle->ego_entry; - handle->ego_entry = handle->ego_entry->next) - { - if (0 == strcmp (handle->ego_entry->keystring, received_cid)) - break; - } - if (NULL == handle->ego_entry) - { - GNUNET_free (received_cpw); - GNUNET_free (received_cid); - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - return GNUNET_SYSERR; - } - GNUNET_STRINGS_string_to_data (received_cid, - strlen (received_cid), - cid, - sizeof(struct GNUNET_CRYPTO_PublicKey)); - - GNUNET_free (received_cpw); - GNUNET_free (received_cid); - return GNUNET_OK; -} - - -const struct EgoEntry * -find_ego (struct RequestHandle *handle, - struct GNUNET_CRYPTO_PublicKey *test_key) -{ - struct EgoEntry *ego_entry; - struct GNUNET_CRYPTO_PublicKey pub_key; - - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key); - if (0 == GNUNET_memcmp (&pub_key, test_key)) - return ego_entry; - } - return NULL; -} - - -/** - * Responds to token url-encoded POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - const struct EgoEntry *ego_entry = NULL; - struct GNUNET_TIME_Relative expiration_time; - struct GNUNET_RECLAIM_AttributeList *cl = NULL; - struct GNUNET_RECLAIM_PresentationList *pl = NULL; - struct GNUNET_RECLAIM_Ticket ticket; - struct GNUNET_CRYPTO_PublicKey cid; - struct GNUNET_HashCode cache_key; - struct MHD_Response *resp = NULL; - char *grant_type = NULL; - char *code = NULL; - char *json_response = NULL; - char *id_token = NULL; - char *access_token = NULL; - char *jwa = NULL; - char *jwt_secret = NULL; - char *nonce = NULL; - char *code_verifier = NULL; - json_t *oidc_jwk = NULL; - char *oidc_jwk_path = NULL; - char *oidc_directory = NULL; - char *tmp_at = NULL; - - /* - * Check Authorization - */ - if (GNUNET_SYSERR == check_authorization (handle, &cid)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "OIDC authorization for token endpoint failed\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - /* - * Check parameter - */ - - // TODO Do not allow multiple equal parameter names - // REQUIRED grant_type - GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, - strlen (OIDC_GRANT_TYPE_KEY), - &cache_key); - grant_type = get_url_parameter_copy (handle, OIDC_GRANT_TYPE_KEY); - if (NULL == grant_type) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); - handle->edesc = GNUNET_strdup ("missing parameter grant_type"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - // Check parameter grant_type == "authorization_code" - if (0 != strcmp (OIDC_GRANT_TYPE_VALUE, grant_type)) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_free (grant_type); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - GNUNET_free (grant_type); - // REQUIRED code - code = get_url_parameter_copy (handle, OIDC_CODE_KEY); - if (NULL == code) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); - handle->edesc = GNUNET_strdup ("missing parameter code"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - ego_entry = find_ego (handle, &cid); - if (NULL == ego_entry) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); - handle->edesc = GNUNET_strdup ("Unknown client"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_free (code); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - // REQUIRED code verifier - code_verifier = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY); - if (NULL == code_verifier) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "OAuth authorization request does not contain PKCE parameters!\n"); - - } - - // decode code - if (GNUNET_OK != OIDC_parse_authz_code (&cid, code, code_verifier, &ticket, - &cl, &pl, &nonce, - OIDC_VERIFICATION_DEFAULT)) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); - handle->edesc = GNUNET_strdup ("invalid code"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_free (code); - if (NULL != code_verifier) - GNUNET_free (code_verifier); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (NULL != code_verifier) - GNUNET_free (code_verifier); - - // create jwt - if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, - "reclaim-rest-plugin", - "expiration_time", - &expiration_time)) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); - handle->edesc = GNUNET_strdup ("gnunet configuration failed"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_free (code); - if (NULL != nonce) - GNUNET_free (nonce); - GNUNET_RECLAIM_attribute_list_destroy (cl); - GNUNET_RECLAIM_presentation_list_destroy (pl); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - // Check if HMAC or RSA should be used - if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, - "reclaim-rest-plugin", - "oidc_json_web_algorithm", - &jwa)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Could not read OIDC JSON Web Algorithm config attribute." - "Defaulting to RS256."); - jwa = JWT_ALG_VALUE_RSA; - } - - if ( ! strcmp (jwa, JWT_ALG_VALUE_RSA)) - { - // Replace for now - oidc_jwk_path = get_oidc_jwk_path (cls); - oidc_jwk = read_jwk_from_file (oidc_jwk_path); - - // Check if secret JWK exists - if (! oidc_jwk) - { - // Generate and save a new key - oidc_jwk = generate_jwk (); - oidc_directory = get_oidc_dir_path (cls); - - // Create new oidc directory - if (GNUNET_OK != GNUNET_DISK_directory_create (oidc_directory)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - ("Failed to create directory `%s' for storing oidc data\n"), - oidc_directory); - } - else - { - write_jwk_to_file (oidc_jwk_path, oidc_jwk); - } - } - - // Generate oidc token - id_token = OIDC_generate_id_token_rsa (&ticket.audience, - &ticket.identity, - cl, - pl, - &expiration_time, - (NULL != nonce) ? nonce : NULL, - oidc_jwk); - } - else if ( ! strcmp (jwa, JWT_ALG_VALUE_HMAC)) - { - // TODO OPTIONAL acr,amr,azp - if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, - "reclaim-rest-plugin", - "jwt_secret", - &jwt_secret)) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); - handle->edesc = GNUNET_strdup ("No signing secret configured!"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_free (code); - GNUNET_RECLAIM_attribute_list_destroy (cl); - GNUNET_RECLAIM_presentation_list_destroy (pl); - if (NULL != nonce) - GNUNET_free (nonce); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - id_token = OIDC_generate_id_token_hmac (&ticket.audience, - &ticket.identity, - cl, - pl, - &expiration_time, - (NULL != nonce) ? nonce : NULL, - jwt_secret); - - GNUNET_free (jwt_secret); - } - else - { - // TODO: OPTION NOT FOUND ERROR - } - - if (NULL != nonce) - GNUNET_free (nonce); - access_token = OIDC_access_token_new (&ticket); - /** - * Store mapping from access token to code so we can later - * fall back on the provided attributes in userinfo one time. - */ - GNUNET_CRYPTO_hash (access_token, - strlen (access_token), - &cache_key); - /** - * Note to future self: This cache has the following purpose: - * Some OIDC plugins call the userendpoint right after receiving an - * ID token and access token. There are reasons why this would make sense. - * Others not so much. - * In any case, in order to smoothen out the user experience upon login - * (authorization), we speculatively cache the next - * userinfo response in case the actual resolution through reclaim/GNS - * takes too long. - */ - tmp_at = GNUNET_CONTAINER_multihashmap_get (oidc_code_cache, - &cache_key); - GNUNET_CONTAINER_multihashmap_put (oidc_code_cache, - &cache_key, - code, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); - /* If there was a previous code in there, free the old value */ - if (NULL != tmp_at) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "OIDC access token already issued. Cleanup.\n"); - GNUNET_free (tmp_at); - } - - OIDC_build_token_response (access_token, - id_token, - &expiration_time, - &json_response); - - resp = GNUNET_REST_create_response (json_response); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Cache-Control", - "no-store")); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Pragma", "no-cache")); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Content-Type", - "application/json")); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_RECLAIM_attribute_list_destroy (cl); - GNUNET_RECLAIM_presentation_list_destroy (pl); - GNUNET_free (access_token); - GNUNET_free (json_response); - GNUNET_free (id_token); - cleanup_handle (handle); -} - - -/** - * Collects claims and stores them in handle - */ -static void -consume_ticket (void *cls, - const struct GNUNET_CRYPTO_PublicKey *identity, - const struct GNUNET_RECLAIM_Attribute *attr, - const struct GNUNET_RECLAIM_Presentation *presentation) -{ - struct RequestHandle *handle = cls; - struct GNUNET_RECLAIM_AttributeListEntry *ale; - struct GNUNET_RECLAIM_PresentationListEntry *atle; - struct MHD_Response *resp; - struct GNUNET_HashCode cache_key; - char *result_str; - char *cached_code; - - if (NULL != handle->consume_timeout_op) - GNUNET_SCHEDULER_cancel (handle->consume_timeout_op); - handle->consume_timeout_op = NULL; - handle->idp_op = NULL; - - /** - * We received a reply. In any case clear the cache. - */ - GNUNET_CRYPTO_hash (handle->access_token, - strlen (handle->access_token), - &cache_key); - cached_code = GNUNET_CONTAINER_multihashmap_get (oidc_code_cache, - &cache_key); - if (NULL != cached_code) - { - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (oidc_code_cache, - &cache_key, - cached_code)); - GNUNET_free (cached_code); - } - - - if (NULL == identity) - { - result_str = OIDC_generate_userinfo (&handle->ticket.identity, - handle->attr_userinfo_list, - handle->presentations); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Userinfo: %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (result_str); - cleanup_handle (handle); - return; - } - ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry); - ale->attribute = GNUNET_RECLAIM_attribute_new (attr->name, - &attr->credential, - attr->type, - attr->data, - attr->data_size); - ale->attribute->id = attr->id; - ale->attribute->flag = attr->flag; - ale->attribute->credential = attr->credential; - GNUNET_CONTAINER_DLL_insert (handle->attr_userinfo_list->list_head, - handle->attr_userinfo_list->list_tail, - ale); - if (NULL == presentation) - return; - for (atle = handle->presentations->list_head; - NULL != atle; atle = atle->next) - { - if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal ( - &atle->presentation->credential_id, - &presentation->credential_id)) - continue; - break; /** already in list **/ - } - if (NULL == atle) - { - /** Credential matches for attribute, add **/ - atle = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry); - atle->presentation = GNUNET_RECLAIM_presentation_new (presentation->type, - presentation->data, - presentation-> - data_size); - atle->presentation->credential_id = presentation->credential_id; - GNUNET_CONTAINER_DLL_insert (handle->presentations->list_head, - handle->presentations->list_tail, - atle); - } -} - - -static void -consume_fail (void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_HashCode cache_key; - struct GNUNET_RECLAIM_AttributeList *cl = NULL; - struct GNUNET_RECLAIM_PresentationList *pl = NULL; - struct GNUNET_RECLAIM_Ticket ticket; - struct MHD_Response *resp; - char *nonce; - char *cached_code; - char *result_str; - - - handle->consume_timeout_op = NULL; - if (NULL != handle->idp_op) - GNUNET_RECLAIM_cancel (handle->idp_op); - handle->idp_op = NULL; - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Ticket consumptioned timed out. Using cache...\n"); - GNUNET_CRYPTO_hash (handle->access_token, - strlen (handle->access_token), - &cache_key); - cached_code = GNUNET_CONTAINER_multihashmap_get (oidc_code_cache, - &cache_key); - if (NULL == cached_code) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); - handle->edesc = GNUNET_strdup ("No Access Token in cache!"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - return; - } - /** - * Remove the cached item - */ - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (oidc_code_cache, - &cache_key, - cached_code)); - - // decode code - if (GNUNET_OK != OIDC_parse_authz_code (&handle->ticket.audience, - cached_code, NULL, &ticket, - &cl, &pl, &nonce, - OIDC_VERIFICATION_NO_CODE_VERIFIER)) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); - handle->edesc = GNUNET_strdup ("invalid code"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_free (cached_code); - if (NULL != nonce) - GNUNET_free (nonce); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - GNUNET_free (cached_code); - - result_str = OIDC_generate_userinfo (&handle->ticket.identity, - cl, - pl); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Userinfo: %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (result_str); - GNUNET_free (nonce); - GNUNET_RECLAIM_attribute_list_destroy (cl); - GNUNET_RECLAIM_presentation_list_destroy (pl); - cleanup_handle (handle); -} - - -/** - * Responds to userinfo GET and url-encoded POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - // TODO expiration time - struct RequestHandle *handle = cls; - struct GNUNET_RECLAIM_Ticket *ticket; - char delimiter[] = " "; - struct GNUNET_HashCode cache_key; - char *authorization; - char *authorization_type; - char *authorization_access_token; - const struct EgoEntry *aud_ego; - const struct GNUNET_CRYPTO_PrivateKey *privkey; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting userinfo\n"); - GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, - strlen (OIDC_AUTHORIZATION_HEADER_KEY), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle - ->header_param_map, - &cache_key)) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); - handle->edesc = GNUNET_strdup ("No Access Token"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - return; - } - authorization = - GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map, - &cache_key); - - // split header in "Bearer" and access_token - authorization = GNUNET_strdup (authorization); - authorization_type = strtok (authorization, delimiter); - if ((NULL == authorization_type) || - (0 != strcmp ("Bearer", authorization_type))) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); - handle->edesc = GNUNET_strdup ("No Access Token"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free (authorization); - return; - } - authorization_access_token = strtok (NULL, delimiter); - if (NULL == authorization_access_token) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); - handle->edesc = GNUNET_strdup ("Access token missing"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free (authorization); - return; - } - - if (GNUNET_OK != OIDC_access_token_parse (authorization_access_token, - &ticket)) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); - handle->edesc = GNUNET_strdup ("The access token is invalid"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free (authorization); - return; - - } - GNUNET_assert (NULL != ticket); - handle->ticket = *ticket; - GNUNET_free (ticket); - aud_ego = find_ego (handle, &handle->ticket.audience); - if (NULL == aud_ego) - { - handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); - handle->edesc = GNUNET_strdup ("The access token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free (authorization); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Consuming ticket\n"); - privkey = GNUNET_IDENTITY_ego_get_private_key (aud_ego->ego); - handle->attr_userinfo_list = - GNUNET_new (struct GNUNET_RECLAIM_AttributeList); - handle->presentations = - GNUNET_new (struct GNUNET_RECLAIM_PresentationList); - - /* If the consume takes too long, we use values from the cache */ - handle->access_token = GNUNET_strdup (authorization_access_token); - handle->consume_timeout_op = GNUNET_SCHEDULER_add_delayed (consume_timeout, - &consume_fail, - handle); - handle->idp_op = GNUNET_RECLAIM_ticket_consume (idp, - privkey, - &handle->ticket, - &consume_ticket, - handle); - GNUNET_free (authorization); -} - -/** - * Responds to /jwks.json - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -jwks_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - char *oidc_directory; - char *oidc_jwk_path; - char *oidc_jwk_pub_str; - json_t *oidc_jwk; - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - oidc_jwk_path = get_oidc_jwk_path (cls); - oidc_jwk = read_jwk_from_file (oidc_jwk_path); - - // Check if secret JWK exists - if (! oidc_jwk) - { - // Generate and save a new key - oidc_jwk = generate_jwk (); - oidc_directory = get_oidc_dir_path (cls); - - // Create new oidc directory - if (GNUNET_OK != GNUNET_DISK_directory_create (oidc_directory)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - ("Failed to create directory `%s' for storing oidc data\n"), - oidc_directory); - } - else - { - write_jwk_to_file (oidc_jwk_path, oidc_jwk); - } - } - - // Convert secret JWK to public JWK - jose_jwk_pub (NULL, oidc_jwk); - - // Encode JWK as string and return to API endpoint - oidc_jwk_pub_str = json_dumps (oidc_jwk, JSON_INDENT (1)); - resp = GNUNET_REST_create_response (oidc_jwk_pub_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - json_decref (oidc_jwk); - GNUNET_free (oidc_jwk_pub_str); - GNUNET_free (oidc_jwk_pub_str); - cleanup_handle (handle); -} - -/** - * If listing is enabled, prints information about the egos. - * - * This function is initially called for all egos and then again - * whenever a ego's identifier changes or if it is deleted. At the - * end of the initial pass over all egos, the function is once called - * with 'NULL' for 'ego'. That does NOT mean that the callback won't - * be invoked in the future or that there was an error. - * - * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', this - * function is only called ONCE, and 'NULL' being passed in 'ego' does - * indicate an error (for example because name is taken or no default value is - * known). If 'ego' is non-NULL and if '*ctx' is set in those callbacks, the - * value WILL be passed to a subsequent call to the identity callback of - * 'GNUNET_IDENTITY_connect' (if that one was not NULL). - * - * When an identity is renamed, this function is called with the - * (known) ego but the NEW identifier. - * - * When an identity is deleted, this function is called with the - * (known) ego and "NULL" for the 'identifier'. In this case, - * the 'ego' is henceforth invalid (and the 'ctx' should also be - * cleaned up). - * - * @param cls closure - * @param ego ego handle - * @param ctx context for application to store data for this ego - * (during the lifetime of this process, initially NULL) - * @param identifier identifier assigned by the user for this ego, - * NULL if the user just deleted the ego and it - * must thus no longer be used - */ -static void -list_ego (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *identifier) -{ - struct EgoEntry *ego_entry; - struct GNUNET_CRYPTO_PublicKey pk; - - if (NULL == ego) - { - state = ID_REST_STATE_POST_INIT; - return; - } - if (ID_REST_STATE_INIT == state) - - { - ego_entry = GNUNET_new (struct EgoEntry); - GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = GNUNET_CRYPTO_public_key_to_string (&pk); - ego_entry->ego = ego; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail (ego_head, - ego_tail, - ego_entry); - return; - } - /* Ego renamed or added */ - if (identifier != NULL) - { - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (ego_entry->ego == ego) - { - /* Rename */ - GNUNET_free (ego_entry->identifier); - ego_entry->identifier = GNUNET_strdup (identifier); - break; - } - } - if (NULL == ego_entry) - { - /* Add */ - ego_entry = GNUNET_new (struct EgoEntry); - GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = GNUNET_CRYPTO_public_key_to_string (&pk); - ego_entry->ego = ego; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail (ego_head, - ego_tail, - ego_entry); - } - } - else - { - /* Delete */ - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (ego_entry->ego == ego) - break; - } - if (NULL == ego_entry) - return; /* Not found */ - - GNUNET_CONTAINER_DLL_remove (ego_head, - ego_tail, - ego_entry); - GNUNET_free (ego_entry->identifier); - GNUNET_free (ego_entry->keystring); - GNUNET_free (ego_entry); - return; - } -} - - -static void -oidc_config_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - json_t *oidc_config; - json_t *auth_methods; - json_t *sig_algs; - json_t *scopes; - json_t *response_types; - json_t *sub_types; - json_t *claim_types; - char *oidc_config_str; - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - oidc_config = json_object (); - // FIXME get from config? - json_object_set_new (oidc_config, - "issuer", json_string ("http://localhost:7776")); - json_object_set_new (oidc_config, - "authorization_endpoint", - json_string ("https://api.reclaim/openid/authorize")); - json_object_set_new (oidc_config, - "token_endpoint", - json_string ("http://localhost:7776/openid/token")); - auth_methods = json_array (); - json_array_append_new (auth_methods, - json_string ("client_secret_basic")); - json_array_append_new (auth_methods, - json_string ("client_secret_post")); - json_object_set_new (oidc_config, - "token_endpoint_auth_methods_supported", - auth_methods); - sig_algs = json_array (); - json_array_append_new (sig_algs, - json_string ("HS512")); - json_array_append_new (sig_algs, - json_string ("RS256")); - json_object_set_new (oidc_config, - "id_token_signing_alg_values_supported", - sig_algs); - json_object_set_new (oidc_config, - "jwks_uri", - json_string ("http://localhost:7776/jwks.json")); - json_object_set_new (oidc_config, - "userinfo_endpoint", - json_string ("http://localhost:7776/openid/userinfo")); - scopes = json_array (); - json_array_append_new (scopes, - json_string ("openid")); - json_array_append_new (scopes, - json_string ("profile")); - json_array_append_new (scopes, - json_string ("email")); - json_array_append_new (scopes, - json_string ("address")); - json_array_append_new (scopes, - json_string ("phone")); - json_object_set_new (oidc_config, - "scopes_supported", - scopes); - response_types = json_array (); - json_array_append_new (response_types, - json_string ("code")); - json_object_set_new (oidc_config, - "response_types_supported", - response_types); - sub_types = json_array (); - json_array_append_new (sub_types, - json_string ("public")); /* no pairwise support */ - json_object_set_new (oidc_config, - "subject_types_supported", - sub_types); - claim_types = json_array (); - json_array_append_new (claim_types, - json_string ("normal")); - json_array_append_new (claim_types, - json_string ("aggregated")); - json_object_set_new (oidc_config, - "claim_types_supported", - claim_types); - json_object_set_new (oidc_config, - "claims_parameter_supported", - json_boolean (1)); - oidc_config_str = json_dumps (oidc_config, JSON_INDENT (1)); - resp = GNUNET_REST_create_response (oidc_config_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - json_decref (oidc_config); - GNUNET_free (oidc_config_str); - cleanup_handle (handle); -} - - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -oidc_config_cors (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - // For now, independent of path return all options - resp = GNUNET_REST_create_response (NULL); - GNUNET_assert (MHD_NO != - MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - allow_methods)); - GNUNET_assert (MHD_NO != - MHD_add_response_header (resp, - "Access-Control-Allow-Origin", - "*")); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - cleanup_handle (handle); - return; -} - - -static enum GNUNET_GenericReturnValue -rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = - { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint }, - { MHD_HTTP_METHOD_POST, - GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint }, // url-encoded - { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont }, - { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint }, - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, - { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_JWKS, &jwks_endpoint }, - { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_OIDC_CONFIG, - &oidc_config_endpoint }, - { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC_CONFIG, - &oidc_config_cors }, - { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, &options_cont }, - GNUNET_REST_HANDLER_END }; - - handle->oidc = GNUNET_new (struct OIDC_Variables); - if (NULL == OIDC_cookie_jar_map) - OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10, - GNUNET_NO); - if (NULL == oidc_code_cache) - oidc_code_cache = GNUNET_CONTAINER_multihashmap_create (10, - GNUNET_NO); - - handle->response_code = 0; - handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->rest_handle = rest_handle; - handle->url = GNUNET_strdup (rest_handle->url); - handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle); - GNUNET_CONTAINER_DLL_insert (requests_head, - requests_tail, - handle); - if (handle->url[strlen (handle->url) - 1] == '/') - handle->url[strlen (handle->url) - 1] = '\0'; - if (GNUNET_NO == - GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle)) - return GNUNET_NO; - - return GNUNET_YES; -} - - -/** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_openid_connect_init (void *cls) -{ - static struct Plugin plugin; - struct GNUNET_REST_Plugin *api; - - cfg = cls; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof(struct Plugin)); - plugin.cfg = cfg; - api = GNUNET_new (struct GNUNET_REST_Plugin); - api->cls = &plugin; - api->name = GNUNET_REST_API_NS_OIDC; - api->process_request = &rest_identity_process_request; - identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL); - gns_handle = GNUNET_GNS_connect (cfg); - idp = GNUNET_RECLAIM_connect (cfg); - if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, - "reclaim-rest-plugin", - "OIDC_USERINFO_CONSUME_TIMEOUT", - &consume_timeout)) - { - consume_timeout = CONSUME_TIMEOUT; - } - - - state = ID_REST_STATE_INIT; - GNUNET_asprintf (&allow_methods, - "%s, %s, %s, %s, %s", - MHD_HTTP_METHOD_GET, - MHD_HTTP_METHOD_POST, - MHD_HTTP_METHOD_PUT, - MHD_HTTP_METHOD_DELETE, - MHD_HTTP_METHOD_OPTIONS); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _ ("OpenID Connect REST API initialized\n")); - return api; -} - - -static int -cleanup_hashmap (void *cls, const struct GNUNET_HashCode *key, void *value) -{ - GNUNET_free (value); - return GNUNET_YES; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_rest_openid_connect_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - struct EgoEntry *ego_entry; - - plugin->cfg = NULL; - while (NULL != requests_head) - cleanup_handle (requests_head); - if (NULL != OIDC_cookie_jar_map) - { - GNUNET_CONTAINER_multihashmap_iterate (OIDC_cookie_jar_map, - &cleanup_hashmap, - NULL); - GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map); - } - if (NULL != oidc_code_cache) - { - GNUNET_CONTAINER_multihashmap_iterate (oidc_code_cache, - &cleanup_hashmap, - NULL); - GNUNET_CONTAINER_multihashmap_destroy (oidc_code_cache); - } - - GNUNET_free (allow_methods); - if (NULL != gns_handle) - GNUNET_GNS_disconnect (gns_handle); - if (NULL != identity_handle) - GNUNET_IDENTITY_disconnect (identity_handle); - if (NULL != idp) - GNUNET_RECLAIM_disconnect (idp); - while (NULL != (ego_entry = ego_head)) - { - GNUNET_CONTAINER_DLL_remove (ego_head, - ego_tail, - ego_entry); - GNUNET_free (ego_entry->identifier); - GNUNET_free (ego_entry->keystring); - GNUNET_free (ego_entry); - } - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "OpenID Connect REST plugin is finished\n"); - return NULL; -} - - -/* end of plugin_rest_openid_connect.c */ diff --git a/src/rest-plugin/reclaim/plugin_rest_pabc.c b/src/rest-plugin/reclaim/plugin_rest_pabc.c deleted file mode 100644 index 4b7d21df3..000000000 --- a/src/rest-plugin/reclaim/plugin_rest_pabc.c +++ /dev/null @@ -1,667 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ -/** - * @author Martin Schanzenbach - * @file reclaim/plugin_rest_pabc.c - * @brief GNUnet pabc REST plugin - * - */ -#include "platform.h" -#include "microhttpd.h" -#include -#include -#include -#include "gnunet_reclaim_lib.h" -#include "gnunet_reclaim_service.h" -#include "gnunet_rest_lib.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_signatures.h" -#include "pabc_helper.h" - -/** - * REST root namespace - */ -#define GNUNET_REST_API_NS_PABC "/pabc" - -/** - * Credential request endpoint - */ -#define GNUNET_REST_API_NS_PABC_CR "/pabc/cr" - -/** - * The configuration handle - */ -const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * HTTP methods allows for this plugin - */ -static char *allow_methods; - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - - -struct RequestHandle -{ - /** - * DLL - */ - struct RequestHandle *next; - - /** - * DLL - */ - struct RequestHandle *prev; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * Desired timeout for the lookup (default is no timeout). - */ - struct GNUNET_TIME_Relative timeout; - - /** - * ID of a task associated with the resolution process. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * Error response message - */ - char *emsg; - - /** - * Response code - */ - int response_code; - - /** - * Response object - */ - json_t *resp_object; -}; - -/** - * DLL - */ -static struct RequestHandle *requests_head; - -/** - * DLL - */ -static struct RequestHandle *requests_tail; - - -/** - * Cleanup lookup handle - * @param handle Handle to clean up - */ -static void -cleanup_handle (void *cls) -{ - struct RequestHandle *handle = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); - if (NULL != handle->resp_object) - json_decref (handle->resp_object); - if (NULL != handle->timeout_task) - GNUNET_SCHEDULER_cancel (handle->timeout_task); - if (NULL != handle->url) - GNUNET_free (handle->url); - if (NULL != handle->emsg) - GNUNET_free (handle->emsg); - GNUNET_CONTAINER_DLL_remove (requests_head, - requests_tail, - handle); - GNUNET_free (handle); -} - - -/** - * Task run on error, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *json_error; - - GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg); - if (0 == handle->response_code) - { - handle->response_code = MHD_HTTP_BAD_REQUEST; - } - resp = GNUNET_REST_create_response (json_error); - MHD_add_response_header (resp, "Content-Type", "application/json"); - handle->proc (handle->proc_cls, resp, handle->response_code); - cleanup_handle (handle); - GNUNET_free (json_error); -} - - -/** - * Task run on timeout, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_timeout (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->timeout_task = NULL; - do_error (handle); -} - - -static void -return_response (void *cls) -{ - char *result_str; - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - result_str = json_dumps (handle->resp_object, 0); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (result_str); - cleanup_handle (handle); -} - - -static enum pabc_status -set_attributes_from_idtoken (const struct pabc_context *ctx, - const struct pabc_public_parameters *pp, - struct pabc_user_context *usr_ctx, - const char *id_token) -{ - json_t *payload_json; - json_t *value; - json_error_t json_err; - const char *key; - const char *jwt_body; - char *decoded_jwt; - char delim[] = "."; - char *jwt_string; - const char *pabc_key; - enum pabc_status status; - - // FIXME parse JWT - jwt_string = GNUNET_strndup (id_token, strlen (id_token)); - jwt_body = strtok (jwt_string, delim); - jwt_body = strtok (NULL, delim); - GNUNET_STRINGS_base64url_decode (jwt_body, strlen (jwt_body), - (void **) &decoded_jwt); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decoded ID Token: %s\n", decoded_jwt); - payload_json = json_loads (decoded_jwt, JSON_DECODE_ANY, &json_err); - GNUNET_free (decoded_jwt); - - json_object_foreach (payload_json, key, value) - { - pabc_key = key; - if (0 == strcmp ("iss", key)) - pabc_key = "issuer"; // rename - if (0 == strcmp ("sub", key)) - pabc_key = "subject"; // rename - if (0 == strcmp ("jti", key)) - continue; - if (0 == strcmp ("exp", key)) - pabc_key = "expiration"; // rename - if (0 == strcmp ("iat", key)) - continue; - if (0 == strcmp ("nbf", key)) - continue; - if (0 == strcmp ("aud", key)) - continue; - char *tmp_val; - if (json_is_string (value)) - tmp_val = GNUNET_strdup (json_string_value (value)); - else - tmp_val = json_dumps (value, JSON_ENCODE_ANY); - if (NULL == tmp_val) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to encode JSON value for `%s'\n", key); - continue; - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Setting `%s' to `%s'\n", key, tmp_val); - status = pabc_set_attribute_value_by_name (ctx, pp, usr_ctx, - pabc_key, - tmp_val); - GNUNET_free (tmp_val); - if (PABC_OK != status) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to set attribute `%s'.\n", key); - } - } - GNUNET_free (jwt_string); - return PABC_OK; -} - - -static enum GNUNET_GenericReturnValue -setup_new_user_context (struct pabc_context *ctx, - struct pabc_public_parameters *pp, - struct pabc_user_context **usr_ctx) -{ - if (PABC_OK != pabc_new_user_context (ctx, pp, usr_ctx)) - return GNUNET_SYSERR; - - if (PABC_OK != pabc_populate_user_context (ctx, *usr_ctx)) - { - pabc_free_user_context (ctx, pp, usr_ctx); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -static void -cr_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - char term_data[handle->rest_handle->data_size + 1]; - char *response_str; - json_t *data_json; - json_t *nonce_json; - json_t *pp_json; - json_t *idtoken_json; - json_t *iss_json; - json_t *identity_json; - json_error_t err; - struct pabc_public_parameters *pp = NULL; - struct pabc_context *ctx = NULL; - struct pabc_user_context *usr_ctx = NULL; - struct pabc_credential_request *cr = NULL; - struct pabc_nonce *nonce = NULL; - enum pabc_status status; - - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Credential request...\n"); - - if (0 >= handle->rest_handle->data_size) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_json = json_loads (term_data, JSON_DECODE_ANY, &err); - if (NULL == data_json) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse %s\n", term_data); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (! json_is_object (data_json)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse %s\n", term_data); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - nonce_json = json_object_get (data_json, "nonce"); - if (NULL == nonce_json) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse nonce\n"); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - iss_json = json_object_get (data_json, "issuer"); - if (NULL == iss_json) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse issuer\n"); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity_json = json_object_get (data_json, "identity"); - if (NULL == identity_json) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse identity\n"); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - idtoken_json = json_object_get (data_json, "id_token"); - if (NULL == idtoken_json) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse id_token\n"); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - pp_json = json_object_get (data_json, "public_params"); - if (NULL == pp_json) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse public parameters\n"); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - PABC_ASSERT (pabc_new_ctx (&ctx)); - char *pp_str = json_dumps (pp_json, JSON_ENCODE_ANY); - status = pabc_decode_and_new_public_parameters (ctx, - &pp, - pp_str); - char *ppid; - GNUNET_assert (PABC_OK == pabc_cred_get_ppid_from_pp (pp_str, &ppid)); - GNUNET_free (pp_str); - if (status != PABC_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to read public parameters: %s\n", - pp_str); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - // (Over)write parameters - status = PABC_write_public_parameters (json_string_value (iss_json), - pp); - if (status != PABC_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to write public parameters.\n"); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - status = PABC_read_usr_ctx (json_string_value (identity_json), - json_string_value (iss_json), - ctx, pp, &usr_ctx); - if (PABC_OK != status) - { - if (GNUNET_OK != setup_new_user_context (ctx, pp, &usr_ctx)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to setup user context.\n"); - pabc_free_public_parameters (ctx, &pp); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - PABC_write_usr_ctx (json_string_value (identity_json), - json_string_value (iss_json), - ctx, pp, usr_ctx); - } - - // Set attributes from JWT to context - status = set_attributes_from_idtoken (ctx, - pp, - usr_ctx, - json_string_value (idtoken_json)); - if (status != PABC_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to set attributes.\n"); - pabc_free_user_context (ctx, pp, &usr_ctx); - pabc_free_public_parameters (ctx, &pp); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - - // nonce - status = pabc_new_nonce (ctx, &nonce); - if (status != PABC_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to allocate nonce.\n"); - pabc_free_user_context (ctx, pp, &usr_ctx); - pabc_free_public_parameters (ctx, &pp); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - char *nonce_str = json_dumps (nonce_json, JSON_ENCODE_ANY); - status = pabc_decode_nonce (ctx, nonce, nonce_str); - if (status != PABC_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to decode nonce.\n"); - pabc_free_nonce (ctx, &nonce); - pabc_free_user_context (ctx, pp, &usr_ctx); - pabc_free_public_parameters (ctx, &pp); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - // cr - status = pabc_new_credential_request (ctx, pp, &cr); - if (PABC_OK != status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to allocate cr.\n"); - pabc_free_nonce (ctx, &nonce); - pabc_free_user_context (ctx, pp, &usr_ctx); - pabc_free_public_parameters (ctx, &pp); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - status = pabc_gen_credential_request (ctx, pp, usr_ctx, nonce, cr); - if (PABC_OK != status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to generate cr.\n"); - pabc_free_nonce (ctx, &nonce); - pabc_free_credential_request (ctx, pp, &cr); - pabc_free_user_context (ctx, pp, &usr_ctx); - pabc_free_public_parameters (ctx, &pp); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->resp_object = json_object (); - GNUNET_assert (PABC_OK == pabc_cred_encode_cr (ctx, pp, cr, - json_string_value ( - identity_json), - ppid, &response_str)); - if (PABC_OK != status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to serialize cr.\n"); - pabc_free_nonce (ctx, &nonce); - pabc_free_credential_request (ctx, pp, &cr); - pabc_free_user_context (ctx, pp, &usr_ctx); - pabc_free_public_parameters (ctx, &pp); - json_decref (data_json); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - json_decref (handle->resp_object); - handle->resp_object = json_loads (response_str, JSON_DECODE_ANY, &err); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s\n", response_str); - GNUNET_free (response_str); - - // clean up - pabc_free_nonce (ctx, &nonce); - pabc_free_credential_request (ctx, pp, &cr); - pabc_free_user_context (ctx, pp, &usr_ctx); - pabc_free_public_parameters (ctx, &pp); - GNUNET_SCHEDULER_add_now (&return_response, handle); - json_decref (data_json); -} - - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - // For now, independent of path return all options - resp = GNUNET_REST_create_response (NULL); - MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - cleanup_handle (handle); - return; -} - - -static enum GNUNET_GenericReturnValue -rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = { - {MHD_HTTP_METHOD_POST, - GNUNET_REST_API_NS_PABC_CR, &cr_cont }, - { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_PABC, &options_cont }, - GNUNET_REST_HANDLER_END - }; - - handle->response_code = 0; - handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->rest_handle = rest_handle; - - handle->url = GNUNET_strdup (rest_handle->url); - if (handle->url[strlen (handle->url) - 1] == '/') - handle->url[strlen (handle->url) - 1] = '\0'; - handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle); - GNUNET_CONTAINER_DLL_insert (requests_head, - requests_tail, - handle); - if (GNUNET_NO == - GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle)) - { - cleanup_handle (handle); - return GNUNET_NO; - } - - return GNUNET_YES; -} - - -/** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_pabc_init (void *cls) -{ - static struct Plugin plugin; - struct GNUNET_REST_Plugin *api; - - cfg = cls; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof(struct Plugin)); - plugin.cfg = cfg; - api = GNUNET_new (struct GNUNET_REST_Plugin); - api->cls = &plugin; - api->name = GNUNET_REST_API_NS_PABC; - api->process_request = &rest_identity_process_request; - GNUNET_asprintf (&allow_methods, - "%s, %s", - MHD_HTTP_METHOD_POST, - MHD_HTTP_METHOD_OPTIONS); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _ ("Identity Provider REST API initialized\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_rest_reclaim_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - struct RequestHandle *request; - - plugin->cfg = NULL; - while (NULL != (request = requests_head)) - do_error (request); - - GNUNET_free (allow_methods); - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "PABC REST plugin is finished\n"); - return NULL; -} - - -/* end of plugin_rest_reclaim.c */ diff --git a/src/rest-plugin/reclaim/plugin_rest_reclaim.c b/src/rest-plugin/reclaim/plugin_rest_reclaim.c deleted file mode 100644 index b2586109a..000000000 --- a/src/rest-plugin/reclaim/plugin_rest_reclaim.c +++ /dev/null @@ -1,1564 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ -/** - * @author Martin Schanzenbach - * @author Philippe Buschmann - * @file reclaim/plugin_rest_reclaim.c - * @brief GNUnet reclaim REST plugin - * - */ -#include "platform.h" -#include "microhttpd.h" -#include -#include -#include "gnunet_gns_service.h" -#include "gnunet_gnsrecord_lib.h" -#include "gnunet_identity_service.h" -#include "gnunet_reclaim_lib.h" -#include "gnunet_reclaim_service.h" -#include "gnunet_rest_lib.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_signatures.h" -#include "json_reclaim.h" -/** - * REST root namespace - */ -#define GNUNET_REST_API_NS_RECLAIM "/reclaim" - -/** - * Attribute namespace - */ -#define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes" - -/** - * Credential namespace - */ -#define GNUNET_REST_API_NS_RECLAIM_CREDENTIAL "/reclaim/credential" - -/** - * Ticket namespace - */ -#define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets" - -/** - * Revoke namespace - */ -#define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke" - -/** - * Revoke namespace - */ -#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume" - -/** - * State while collecting all egos - */ -#define ID_REST_STATE_INIT 0 - -/** - * Done collecting egos - */ -#define ID_REST_STATE_POST_INIT 1 - -/** - * The configuration handle - */ -const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * HTTP methods allows for this plugin - */ -static char *allow_methods; - -/** - * Ego list - */ -static struct EgoEntry *ego_head; - -/** - * Ego list - */ -static struct EgoEntry *ego_tail; - -/** - * The processing state - */ -static int state; - -/** - * Handle to Identity service. - */ -static struct GNUNET_IDENTITY_Handle *identity_handle; - -/** - * Identity Provider - */ -static struct GNUNET_RECLAIM_Handle *idp; - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - -/** - * The ego list - */ -struct EgoEntry -{ - /** - * DLL - */ - struct EgoEntry *next; - - /** - * DLL - */ - struct EgoEntry *prev; - - /** - * Ego Identifier - */ - char *identifier; - - /** - * Public key string - */ - char *keystring; - - /** - * The Ego - */ - struct GNUNET_IDENTITY_Ego *ego; -}; - - -struct RequestHandle -{ - /** - * DLL - */ - struct RequestHandle *next; - - /** - * DLL - */ - struct RequestHandle *prev; - - /** - * Selected ego - */ - struct EgoEntry *ego_entry; - - /** - * Pointer to ego private key - */ - struct GNUNET_CRYPTO_PrivateKey priv_key; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * Attribute claim list - */ - struct GNUNET_RECLAIM_AttributeList *attr_list; - - /** - * IDENTITY Operation - */ - struct GNUNET_IDENTITY_Operation *op; - - /** - * Idp Operation - */ - struct GNUNET_RECLAIM_Operation *idp_op; - - /** - * Attribute iterator - */ - struct GNUNET_RECLAIM_AttributeIterator *attr_it; - - /** - * Attribute iterator - */ - struct GNUNET_RECLAIM_CredentialIterator *cred_it; - - /** - * Ticket iterator - */ - struct GNUNET_RECLAIM_TicketIterator *ticket_it; - - /** - * A ticket - */ - struct GNUNET_RECLAIM_Ticket ticket; - - /** - * Desired timeout for the lookup (default is no timeout). - */ - struct GNUNET_TIME_Relative timeout; - - /** - * ID of a task associated with the resolution process. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * Error response message - */ - char *emsg; - - /** - * Response code - */ - int response_code; - - /** - * Response object - */ - json_t *resp_object; -}; - -/** - * DLL - */ -static struct RequestHandle *requests_head; - -/** - * DLL - */ -static struct RequestHandle *requests_tail; - - -/** - * Cleanup lookup handle - * @param handle Handle to clean up - */ -static void -cleanup_handle (void *cls) -{ - struct RequestHandle *handle = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); - if (NULL != handle->resp_object) - json_decref (handle->resp_object); - if (NULL != handle->timeout_task) - GNUNET_SCHEDULER_cancel (handle->timeout_task); - if (NULL != handle->attr_it) - GNUNET_RECLAIM_get_attributes_stop (handle->attr_it); - if (NULL != handle->cred_it) - GNUNET_RECLAIM_get_credentials_stop (handle->cred_it); - if (NULL != handle->ticket_it) - GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it); - if (NULL != handle->url) - GNUNET_free (handle->url); - if (NULL != handle->emsg) - GNUNET_free (handle->emsg); - if (NULL != handle->attr_list) - GNUNET_RECLAIM_attribute_list_destroy (handle->attr_list); - GNUNET_CONTAINER_DLL_remove (requests_head, - requests_tail, - handle); - GNUNET_free (handle); -} - - -/** - * Task run on error, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *json_error; - - GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg); - if (0 == handle->response_code) - { - handle->response_code = MHD_HTTP_BAD_REQUEST; - } - resp = GNUNET_REST_create_response (json_error); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, "Content-Type", "application/json")); - handle->proc (handle->proc_cls, resp, handle->response_code); - cleanup_handle (handle); - GNUNET_free (json_error); -} - - -/** - * Task run on timeout, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_timeout (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->timeout_task = NULL; - do_error (handle); -} - - -static void -collect_error_cb (void *cls) -{ - GNUNET_SCHEDULER_add_now (&do_error, cls); -} - - -static void -finished_cont (void *cls, int32_t success, const char *emsg) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - handle->idp_op = NULL; - if (GNUNET_OK != success) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - resp = GNUNET_REST_create_response (emsg); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Content-Type", - "application/json")); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - allow_methods)); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -static void -delete_finished_cb (void *cls, int32_t success, const char *emsg) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - if (GNUNET_OK != success) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - resp = GNUNET_REST_create_response (emsg); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - allow_methods)); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); -} - - -/** - * Return attributes for identity - * - * @param cls the request handle - */ -static void -return_response (void *cls) -{ - char *result_str; - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - result_str = json_dumps (handle->resp_object, 0); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - GNUNET_assert (MHD_NO != - MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - allow_methods)); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (result_str); - cleanup_handle (handle); -} - - -static void -collect_finished_cb (void *cls) -{ - struct RequestHandle *handle = cls; - - // Done - handle->attr_it = NULL; - handle->cred_it = NULL; - handle->ticket_it = NULL; - GNUNET_SCHEDULER_add_now (&return_response, handle); -} - - -/** - * Collect all attributes for an ego - * - */ -static void -ticket_collect (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket) -{ - json_t *json_resource; - struct RequestHandle *handle = cls; - json_t *value; - char *tmp; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n"); - tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd)); - json_resource = json_object (); - GNUNET_free (tmp); - json_array_append (handle->resp_object, json_resource); - - tmp = - GNUNET_STRINGS_data_to_string_alloc (&ticket->identity, - sizeof(struct - GNUNET_CRYPTO_PublicKey)); - value = json_string (tmp); - json_object_set_new (json_resource, "issuer", value); - GNUNET_free (tmp); - tmp = - GNUNET_STRINGS_data_to_string_alloc (&ticket->audience, - sizeof(struct - GNUNET_CRYPTO_PublicKey)); - value = json_string (tmp); - json_object_set_new (json_resource, "audience", value); - GNUNET_free (tmp); - tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd)); - value = json_string (tmp); - json_object_set_new (json_resource, "rnd", value); - GNUNET_free (tmp); - GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it); -} - - -static void -add_credential_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - const struct GNUNET_CRYPTO_PrivateKey *identity_priv; - const char *identity; - struct EgoEntry *ego_entry; - struct GNUNET_RECLAIM_Credential *attribute; - struct GNUNET_TIME_Relative exp; - char term_data[handle->rest_handle->data_size + 1]; - json_t *data_json; - json_error_t err; - struct GNUNET_JSON_Specification attrspec[] = - { GNUNET_RECLAIM_JSON_spec_credential (&attribute), - GNUNET_JSON_spec_end () }; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Adding an credential for %s.\n", - handle->url); - if (strlen (GNUNET_REST_API_NS_RECLAIM_CREDENTIAL) >= strlen ( - handle->url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity = handle->url + strlen ( - GNUNET_REST_API_NS_RECLAIM_CREDENTIAL) + 1; - - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - if (0 == strcmp (identity, ego_entry->identifier)) - break; - - if (NULL == ego_entry) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity); - return; - } - identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - - if (0 >= handle->rest_handle->data_size) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_json = json_loads (term_data, JSON_DECODE_ANY, &err); - if (GNUNET_OK != GNUNET_JSON_parse (data_json, attrspec, NULL, NULL)) - { - json_decref (data_json); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse JSON from %s\n", - term_data); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - json_decref (data_json); - if (NULL == attribute) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse credential from %s\n", - term_data); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - /** - * New ID for attribute - */ - if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id)) - GNUNET_RECLAIM_id_generate (&attribute->id); - exp = GNUNET_TIME_UNIT_HOURS; - handle->idp_op = GNUNET_RECLAIM_credential_store (idp, - identity_priv, - attribute, - &exp, - &finished_cont, - handle); - GNUNET_JSON_parse_free (attrspec); -} - - -/** - * Collect all credentials for an ego - * - */ -static void -cred_collect (void *cls, - const struct GNUNET_CRYPTO_PublicKey *identity, - const struct GNUNET_RECLAIM_Credential *cred) -{ - struct RequestHandle *handle = cls; - struct GNUNET_RECLAIM_AttributeList *attrs; - struct GNUNET_RECLAIM_AttributeListEntry *ale; - struct GNUNET_TIME_Absolute exp; - json_t *attr_obj; - json_t *cred_obj; - const char *type; - char *tmp_value; - char *id_str; - char *issuer; - - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding credential: %s\n", - cred->name); - attrs = GNUNET_RECLAIM_credential_get_attributes (cred); - issuer = GNUNET_RECLAIM_credential_get_issuer (cred); - tmp_value = GNUNET_RECLAIM_credential_value_to_string (cred->type, - cred->data, - cred->data_size); - cred_obj = json_object (); - json_object_set_new (cred_obj, "value", json_string (tmp_value)); - json_object_set_new (cred_obj, "name", json_string (cred->name)); - type = GNUNET_RECLAIM_credential_number_to_typename (cred->type); - json_object_set_new (cred_obj, "type", json_string (type)); - if (NULL != issuer) - { - json_object_set_new (cred_obj, "issuer", json_string (issuer)); - GNUNET_free (issuer); - } - if (GNUNET_OK == GNUNET_RECLAIM_credential_get_expiration (cred, - &exp)) - { - json_object_set_new (cred_obj, "expiration", json_integer ( - exp.abs_value_us)); - } - id_str = GNUNET_STRINGS_data_to_string_alloc (&cred->id, - sizeof(cred->id)); - json_object_set_new (cred_obj, "id", json_string (id_str)); - GNUNET_free (tmp_value); - GNUNET_free (id_str); - if (NULL != attrs) - { - json_t *attr_arr = json_array (); - for (ale = attrs->list_head; NULL != ale; ale = ale->next) - { - tmp_value = - GNUNET_RECLAIM_attribute_value_to_string (ale->attribute->type, - ale->attribute->data, - ale->attribute->data_size); - attr_obj = json_object (); - json_object_set_new (attr_obj, "value", json_string (tmp_value)); - json_object_set_new (attr_obj, "name", json_string ( - ale->attribute->name)); - - json_object_set_new (attr_obj, "flag", json_string ("1")); // FIXME - type = GNUNET_RECLAIM_attribute_number_to_typename (ale->attribute->type); - json_object_set_new (attr_obj, "type", json_string (type)); - json_object_set_new (attr_obj, "id", json_string ("")); - json_object_set_new (attr_obj, "credential", json_string ("")); - json_array_append_new (attr_arr, attr_obj); - GNUNET_free (tmp_value); - } - json_object_set_new (cred_obj, "attributes", attr_arr); - } - json_array_append_new (handle->resp_object, cred_obj); - if (NULL != attrs) - GNUNET_RECLAIM_attribute_list_destroy (attrs); - GNUNET_RECLAIM_get_credentials_next (handle->cred_it); -} - - -/** - * Lists credential for identity request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -list_credential_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - const struct GNUNET_CRYPTO_PrivateKey *priv_key; - struct EgoEntry *ego_entry; - char *identity; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Getting credentials for %s.\n", - handle->url); - if (strlen (GNUNET_REST_API_NS_RECLAIM_CREDENTIAL) >= strlen ( - handle->url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity = handle->url + strlen ( - GNUNET_REST_API_NS_RECLAIM_CREDENTIAL) + 1; - - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - if (0 == strcmp (identity, ego_entry->identifier)) - break; - handle->resp_object = json_array (); - - - if (NULL == ego_entry) - { - // Done - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity); - GNUNET_SCHEDULER_add_now (&return_response, handle); - return; - } - priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - handle->cred_it = GNUNET_RECLAIM_get_credentials_start (idp, - priv_key, - &collect_error_cb, - handle, - &cred_collect, - handle, - & - collect_finished_cb, - handle); -} - - -/** - * Deletes credential from an identity - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -delete_credential_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - const struct GNUNET_CRYPTO_PrivateKey *priv_key; - struct GNUNET_RECLAIM_Credential attr; - struct EgoEntry *ego_entry; - char *identity_id_str; - char *identity; - char *id; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting credential.\n"); - if (strlen (GNUNET_REST_API_NS_RECLAIM_CREDENTIAL) >= strlen ( - handle->url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity_id_str = - strdup (handle->url + strlen ( - GNUNET_REST_API_NS_RECLAIM_CREDENTIAL) + 1); - identity = strtok (identity_id_str, "/"); - id = strtok (NULL, "/"); - if ((NULL == identity) || (NULL == id)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n"); - GNUNET_free (identity_id_str); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - if (0 == strcmp (identity, ego_entry->identifier)) - break; - handle->resp_object = json_array (); - if (NULL == ego_entry) - { - // Done - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity); - GNUNET_free (identity_id_str); - GNUNET_SCHEDULER_add_now (&return_response, handle); - return; - } - priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Credential)); - GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id)); - attr.name = ""; - handle->idp_op = GNUNET_RECLAIM_credential_delete (idp, - priv_key, - &attr, - &delete_finished_cb, - handle); - GNUNET_free (identity_id_str); -} - - -/** - * List tickets for identity request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - const struct GNUNET_CRYPTO_PrivateKey *priv_key; - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *identity; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Getting tickets for %s.\n", - handle->url); - if (strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen (handle->url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1; - - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - if (0 == strcmp (identity, ego_entry->identifier)) - break; - handle->resp_object = json_array (); - - if (NULL == ego_entry) - { - // Done - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity); - GNUNET_SCHEDULER_add_now (&return_response, handle); - return; - } - priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - handle->ticket_it = - GNUNET_RECLAIM_ticket_iteration_start (idp, - priv_key, - &collect_error_cb, - handle, - &ticket_collect, - handle, - &collect_finished_cb, - handle); -} - - -static void -add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - const struct GNUNET_CRYPTO_PrivateKey *identity_priv; - const char *identity; - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct GNUNET_RECLAIM_Attribute *attribute; - struct GNUNET_TIME_Relative exp; - char term_data[handle->rest_handle->data_size + 1]; - json_t *data_json; - json_error_t err; - struct GNUNET_JSON_Specification attrspec[] = - { GNUNET_RECLAIM_JSON_spec_attribute (&attribute), GNUNET_JSON_spec_end () }; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Adding an attribute for %s.\n", - handle->url); - if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1; - - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - if (0 == strcmp (identity, ego_entry->identifier)) - break; - - if (NULL == ego_entry) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity); - return; - } - identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - - if (0 >= handle->rest_handle->data_size) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_json = json_loads (term_data, JSON_DECODE_ANY, &err); - GNUNET_assert (GNUNET_OK == - GNUNET_JSON_parse (data_json, attrspec, NULL, NULL)); - json_decref (data_json); - if (NULL == attribute) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse attribute from %s\n", - term_data); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - /** - * New ID for attribute - */ - if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id)) - GNUNET_RECLAIM_id_generate (&attribute->id); - exp = GNUNET_TIME_UNIT_HOURS; - handle->idp_op = GNUNET_RECLAIM_attribute_store (idp, - identity_priv, - attribute, - &exp, - &finished_cont, - handle); - GNUNET_JSON_parse_free (attrspec); -} - - -/** - * Parse a JWT and return the respective claim value as Attribute - * - * @param cred the jwt credential - * @param claim the name of the claim in the JWT - * - * @return a GNUNET_RECLAIM_Attribute, containing the new value - */ -struct GNUNET_RECLAIM_Attribute * -parse_jwt (const struct GNUNET_RECLAIM_Credential *cred, - const char *claim) -{ - char *jwt_string; - struct GNUNET_RECLAIM_Attribute *attr; - char delim[] = "."; - const char *type_str = NULL; - const char *val_str = NULL; - char *data; - size_t data_size; - uint32_t type; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing JWT attributes.\n"); - char *decoded_jwt; - json_t *json_val; - json_error_t *json_err = NULL; - - jwt_string = GNUNET_RECLAIM_credential_value_to_string (cred->type, - cred->data, - cred->data_size); - char *jwt_body = strtok (jwt_string, delim); - jwt_body = strtok (NULL, delim); - GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body), - (void **) &decoded_jwt); - json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, json_err); - const char *key; - json_t *value; - json_object_foreach (json_val, key, value) { - if (0 == strcasecmp (key,claim)) - { - val_str = json_dumps (value, JSON_ENCODE_ANY); - } - } - type_str = "String"; - type = GNUNET_RECLAIM_attribute_typename_to_number (type_str); - if (GNUNET_SYSERR == GNUNET_RECLAIM_attribute_string_to_value (type,val_str, - (void **) &data, - &data_size)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Attribute value from JWT Parser invalid!\n"); - GNUNET_RECLAIM_attribute_string_to_value (type, - "Error: Referenced Claim Name not Found", - (void **) &data, - &data_size); - attr = GNUNET_RECLAIM_attribute_new (claim, &cred->id, - type, data, data_size); - attr->id = cred->id; - attr->flag = 1; - } - else - { - attr = GNUNET_RECLAIM_attribute_new (claim, &cred->id, - type, data, data_size); - attr->id = cred->id; - attr->flag = 1; - } - return attr; -} - - -/** - * Collect all attributes for an ego - * - */ -static void -attr_collect (void *cls, - const struct GNUNET_CRYPTO_PublicKey *identity, - const struct GNUNET_RECLAIM_Attribute *attr) -{ - struct RequestHandle *handle = cls; - json_t *attr_obj; - const char *type; - char *id_str; - - char *tmp_value; - tmp_value = GNUNET_RECLAIM_attribute_value_to_string (attr->type, - attr->data, - attr->data_size); - attr_obj = json_object (); - json_object_set_new (attr_obj, "value", json_string (tmp_value)); - json_object_set_new (attr_obj, "name", json_string (attr->name)); - - if (GNUNET_RECLAIM_id_is_zero (&attr->credential)) - json_object_set_new (attr_obj, "flag", json_string ("0")); - else - json_object_set_new (attr_obj, "flag", json_string ("1")); - type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type); - json_object_set_new (attr_obj, "type", json_string (type)); - id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id, - sizeof(attr->id)); - json_object_set_new (attr_obj, "id", json_string (id_str)); - GNUNET_free (id_str); - id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->credential, - sizeof(attr->credential)); - json_object_set_new (attr_obj, "credential", json_string (id_str)); - GNUNET_free (id_str); - json_array_append (handle->resp_object, attr_obj); - json_decref (attr_obj); - GNUNET_free (tmp_value); - GNUNET_RECLAIM_get_attributes_next (handle->attr_it); -} - - -/** - * List attributes for identity request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - const struct GNUNET_CRYPTO_PrivateKey *priv_key; - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *identity; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Getting attributes for %s.\n", - handle->url); - if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1; - - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - if (0 == strcmp (identity, ego_entry->identifier)) - break; - handle->resp_object = json_array (); - - - if (NULL == ego_entry) - { - // Done - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity); - GNUNET_SCHEDULER_add_now (&return_response, handle); - return; - } - priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - handle->attr_it = GNUNET_RECLAIM_get_attributes_start (idp, - priv_key, - &collect_error_cb, - handle, - &attr_collect, - handle, - &collect_finished_cb, - handle); -} - - -/** - * List attributes for identity request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - const struct GNUNET_CRYPTO_PrivateKey *priv_key; - struct RequestHandle *handle = cls; - struct GNUNET_RECLAIM_Attribute attr; - struct EgoEntry *ego_entry; - char *identity_id_str; - char *identity; - char *id; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n"); - if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity_id_str = - strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1); - identity = strtok (identity_id_str, "/"); - id = strtok (NULL, "/"); - if ((NULL == identity) || (NULL == id)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n"); - GNUNET_free (identity_id_str); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - if (0 == strcmp (identity, ego_entry->identifier)) - break; - handle->resp_object = json_array (); - if (NULL == ego_entry) - { - // Done - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity); - GNUNET_free (identity_id_str); - GNUNET_SCHEDULER_add_now (&return_response, handle); - return; - } - priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attribute)); - GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id)); - attr.name = ""; - handle->idp_op = GNUNET_RECLAIM_attribute_delete (idp, - priv_key, - &attr, - &delete_finished_cb, - handle); - GNUNET_free (identity_id_str); -} - - -static void -revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - const struct GNUNET_CRYPTO_PrivateKey *identity_priv; - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct GNUNET_RECLAIM_Ticket *ticket = NULL; - struct GNUNET_CRYPTO_PublicKey tmp_pk; - char term_data[handle->rest_handle->data_size + 1]; - json_t *data_json; - json_error_t err; - struct GNUNET_JSON_Specification tktspec[] = - { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () }; - - if (0 >= handle->rest_handle->data_size) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_json = json_loads (term_data, JSON_DECODE_ANY, &err); - if ((NULL == data_json) || - (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL))) - { - handle->emsg = GNUNET_strdup ("Not a ticket!\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_JSON_parse_free (tktspec); - if (NULL != data_json) - json_decref (data_json); - return; - } - json_decref (data_json); - if (NULL == ticket) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse ticket from %s\n", - term_data); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk); - if (0 == memcmp (&ticket->identity, - &tmp_pk, - sizeof(struct GNUNET_CRYPTO_PublicKey))) - break; - } - if (NULL == ego_entry) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n"); - GNUNET_JSON_parse_free (tktspec); - return; - } - identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - - handle->idp_op = GNUNET_RECLAIM_ticket_revoke (idp, - identity_priv, - ticket, - &finished_cont, - handle); - GNUNET_JSON_parse_free (tktspec); -} - - -static void -consume_cont (void *cls, - const struct GNUNET_CRYPTO_PublicKey *identity, - const struct GNUNET_RECLAIM_Attribute *attr, - const struct GNUNET_RECLAIM_Presentation *presentation) -{ - struct RequestHandle *handle = cls; - char *val_str; - json_t *value; - - if (NULL == identity) - { - GNUNET_SCHEDULER_add_now (&return_response, handle); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name); - val_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type, - attr->data, - attr->data_size); - if (NULL == val_str) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse value for: %s\n", - attr->name); - return; - } - value = json_string (val_str); - json_object_set_new (handle->resp_object, attr->name, value); - json_decref (value); - GNUNET_free (val_str); -} - - -static void -consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - const struct GNUNET_CRYPTO_PrivateKey *identity_priv; - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct GNUNET_RECLAIM_Ticket *ticket; - struct GNUNET_CRYPTO_PublicKey tmp_pk; - char term_data[handle->rest_handle->data_size + 1]; - json_t *data_json; - json_error_t err; - struct GNUNET_JSON_Specification tktspec[] = - { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () }; - - if (0 >= handle->rest_handle->data_size) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_json = json_loads (term_data, JSON_DECODE_ANY, &err); - if (NULL == data_json) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse JSON Object from %s\n", - term_data); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)) - { - handle->emsg = GNUNET_strdup ("Not a ticket!\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_JSON_parse_free (tktspec); - json_decref (data_json); - return; - } - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk); - if (0 == memcmp (&ticket->audience, - &tmp_pk, - sizeof(struct GNUNET_CRYPTO_PublicKey))) - break; - } - if (NULL == ego_entry) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n"); - GNUNET_JSON_parse_free (tktspec); - return; - } - identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - handle->resp_object = json_object (); - handle->idp_op = GNUNET_RECLAIM_ticket_consume (idp, - identity_priv, - ticket, - &consume_cont, - handle); - GNUNET_JSON_parse_free (tktspec); -} - - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - // For now, independent of path return all options - resp = GNUNET_REST_create_response (NULL); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods)); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - cleanup_handle (handle); - return; -} - - -/** - * If listing is enabled, prints information about the egos. - * - * This function is initially called for all egos and then again - * whenever a ego's identifier changes or if it is deleted. At the - * end of the initial pass over all egos, the function is once called - * with 'NULL' for 'ego'. That does NOT mean that the callback won't - * be invoked in the future or that there was an error. - * - * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', this - * function is only called ONCE, and 'NULL' being passed in 'ego' does - * indicate an error (for example because name is taken or no default value is - * known). If 'ego' is non-NULL and if '*ctx' is set in those callbacks, the - * value WILL be passed to a subsequent call to the identity callback of - * 'GNUNET_IDENTITY_connect' (if that one was not NULL). - * - * When an identity is renamed, this function is called with the - * (known) ego but the NEW identifier. - * - * When an identity is deleted, this function is called with the - * (known) ego and "NULL" for the 'identifier'. In this case, - * the 'ego' is henceforth invalid (and the 'ctx' should also be - * cleaned up). - * - * @param cls closure - * @param ego ego handle - * @param ctx context for application to store data for this ego - * (during the lifetime of this process, initially NULL) - * @param identifier identifier assigned by the user for this ego, - * NULL if the user just deleted the ego and it - * must thus no longer be used - */ -static void -list_ego (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *identifier) -{ - struct EgoEntry *ego_entry; - struct GNUNET_CRYPTO_PublicKey pk; - - if (NULL == ego) - { - state = ID_REST_STATE_POST_INIT; - return; - } - if (ID_REST_STATE_INIT == state) - { - ego_entry = GNUNET_new (struct EgoEntry); - GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = GNUNET_CRYPTO_public_key_to_string (&pk); - ego_entry->ego = ego; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail (ego_head, - ego_tail, - ego_entry); - } - /* Ego renamed or added */ - if (identifier != NULL) - { - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (ego_entry->ego == ego) - { - /* Rename */ - GNUNET_free (ego_entry->identifier); - ego_entry->identifier = GNUNET_strdup (identifier); - break; - } - } - if (NULL == ego_entry) - { - /* Add */ - ego_entry = GNUNET_new (struct EgoEntry); - GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = GNUNET_CRYPTO_public_key_to_string (&pk); - ego_entry->ego = ego; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail (ego_head, - ego_tail, - ego_entry); - } - } - else - { - /* Delete */ - for (ego_entry = ego_head; NULL != ego_entry; - ego_entry = ego_entry->next) - { - if (ego_entry->ego == ego) - break; - } - if (NULL == ego_entry) - return; /* Not found */ - - GNUNET_CONTAINER_DLL_remove (ego_head, - ego_tail, - ego_entry); - GNUNET_free (ego_entry->identifier); - GNUNET_free (ego_entry->keystring); - GNUNET_free (ego_entry); - return; - } - -} - - -static enum GNUNET_GenericReturnValue -rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = - { { MHD_HTTP_METHOD_GET, - GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &list_attribute_cont }, - { MHD_HTTP_METHOD_POST, - GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &add_attribute_cont }, - { MHD_HTTP_METHOD_DELETE, - GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &delete_attribute_cont }, - { MHD_HTTP_METHOD_GET, - GNUNET_REST_API_NS_RECLAIM_CREDENTIAL, &list_credential_cont }, - { MHD_HTTP_METHOD_POST, - GNUNET_REST_API_NS_RECLAIM_CREDENTIAL, &add_credential_cont }, - { MHD_HTTP_METHOD_DELETE, - GNUNET_REST_API_NS_RECLAIM_CREDENTIAL, &delete_credential_cont }, - { MHD_HTTP_METHOD_GET, - GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont }, - { MHD_HTTP_METHOD_POST, - GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont }, - { MHD_HTTP_METHOD_POST, - GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont }, - { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont }, - GNUNET_REST_HANDLER_END}; - - handle->response_code = 0; - handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->rest_handle = rest_handle; - - handle->url = GNUNET_strdup (rest_handle->url); - if (handle->url[strlen (handle->url) - 1] == '/') - handle->url[strlen (handle->url) - 1] = '\0'; - handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle); - GNUNET_CONTAINER_DLL_insert (requests_head, - requests_tail, - handle); - if (GNUNET_NO == - GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle)) - { - cleanup_handle (handle); - return GNUNET_NO; - } - - return GNUNET_YES; -} - - -/** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_rest_reclaim_init (void *cls) -{ - static struct Plugin plugin; - struct GNUNET_REST_Plugin *api; - - cfg = cls; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof(struct Plugin)); - plugin.cfg = cfg; - api = GNUNET_new (struct GNUNET_REST_Plugin); - api->cls = &plugin; - api->name = GNUNET_REST_API_NS_RECLAIM; - api->process_request = &rest_identity_process_request; - GNUNET_asprintf (&allow_methods, - "%s, %s, %s, %s, %s", - MHD_HTTP_METHOD_GET, - MHD_HTTP_METHOD_POST, - MHD_HTTP_METHOD_PUT, - MHD_HTTP_METHOD_DELETE, - MHD_HTTP_METHOD_OPTIONS); - identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL); - state = ID_REST_STATE_INIT; - idp = GNUNET_RECLAIM_connect (cfg); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _ ("Identity Provider REST API initialized\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_rest_reclaim_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - struct RequestHandle *request; - struct EgoEntry *ego_entry; - struct EgoEntry *ego_tmp; - - plugin->cfg = NULL; - while (NULL != (request = requests_head)) - do_error (request); - if (NULL != idp) - GNUNET_RECLAIM_disconnect (idp); - if (NULL != identity_handle) - GNUNET_IDENTITY_disconnect (identity_handle); - for (ego_entry = ego_head; NULL != ego_entry;) - { - ego_tmp = ego_entry; - ego_entry = ego_entry->next; - GNUNET_free (ego_tmp->identifier); - GNUNET_free (ego_tmp->keystring); - GNUNET_free (ego_tmp); - } - - GNUNET_free (allow_methods); - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Identity Provider REST plugin is finished\n"); - return NULL; -} - - -/* end of plugin_rest_reclaim.c */ diff --git a/src/rest-plugin/rest/Makefile.am b/src/rest-plugin/rest/Makefile.am deleted file mode 100644 index 4f7f834fb..000000000 --- a/src/rest-plugin/rest/Makefile.am +++ /dev/null @@ -1,37 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include - -plugindir = $(libdir)/gnunet - -pkgcfgdir= $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 - XLIBS = -lgcov -endif - -plugin_LTLIBRARIES = \ - libgnunet_plugin_rest_copying.la \ - libgnunet_plugin_rest_config.la - -libgnunet_plugin_rest_copying_la_SOURCES = \ - plugin_rest_copying.c -libgnunet_plugin_rest_copying_la_LIBADD = \ - $(top_builddir)/src/service/rest/libgnunetrest.la \ - $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) $(MHD_LIBS) -libgnunet_plugin_rest_copying_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) -libgnunet_plugin_rest_copying_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS) - -libgnunet_plugin_rest_config_la_SOURCES = \ - plugin_rest_config.c -libgnunet_plugin_rest_config_la_LIBADD = \ - $(top_builddir)/src/service/rest/libgnunetrest.la \ - $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) $(MHD_LIBS) -ljansson -libgnunet_plugin_rest_config_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) -libgnunet_plugin_rest_config_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS) diff --git a/src/rest-plugin/rest/meson.build b/src/rest-plugin/rest/meson.build deleted file mode 100644 index 0c7219327..000000000 --- a/src/rest-plugin/rest/meson.build +++ /dev/null @@ -1,18 +0,0 @@ -shared_module('gnunet_plugin_rest_config', - ['plugin_rest_config.c'], - dependencies: [libgnunetrest_dep, - libgnunetutil_dep, - json_dep, - mhd_dep], - include_directories: [incdir, configuration_inc], - install: true, - install_dir: get_option('libdir') / 'gnunet') -shared_module('gnunet_plugin_rest_copying', - ['plugin_rest_copying.c'], - dependencies: [libgnunetrest_dep, - libgnunetutil_dep, - json_dep, - mhd_dep], - include_directories: [incdir, configuration_inc], - install: true, - install_dir: get_option('libdir') / 'gnunet') diff --git a/src/rest-plugin/rest/plugin_rest_config.c b/src/rest-plugin/rest/plugin_rest_config.c deleted file mode 100644 index 826188702..000000000 --- a/src/rest-plugin/rest/plugin_rest_config.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2018 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ -/** - * @author Martin Schanzenbach - * @file gns/plugin_rest_config.c - * @brief REST plugin for configuration - * - */ - -#include "platform.h" -#include "gnunet_rest_plugin.h" -#include -#include -#include - -#define GNUNET_REST_API_NS_CONFIG "/config" - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct Plugin -{ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - -const struct GNUNET_CONFIGURATION_Handle *cfg; - -struct RequestHandle -{ - /** - * DLL - */ - struct RequestHandle *next; - - /** - * DLL - */ - struct RequestHandle *prev; - - /** - * Handle to rest request - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * HTTP response code - */ - int response_code; - - /** - * The URL - */ - char *url; -}; - -/** - * DLL - */ -static struct RequestHandle *requests_head; - -/** - * DLL - */ -static struct RequestHandle *requests_tail; - - -/** - * Cleanup request handle. - * - * @param handle Handle to clean up - */ -static void -cleanup_handle (struct RequestHandle *handle) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); - if (NULL != handle->url) - GNUNET_free (handle->url); - GNUNET_CONTAINER_DLL_remove (requests_head, - requests_tail, - handle); - GNUNET_free (handle); -} - - -/** - * Task run on shutdown. Cleans up everything. - * - * @param cls unused - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, handle->response_code); - cleanup_handle (handle); -} - - -static void -add_sections (void *cls, - const char *section, - const char *option, - const char *value) -{ - json_t *sections_obj = cls; - json_t *sec_obj; - - sec_obj = json_object_get (sections_obj, section); - if (NULL != sec_obj) - { - json_object_set_new (sec_obj, option, json_string (value)); - return; - } - sec_obj = json_object (); - json_object_set_new (sec_obj, option, json_string (value)); - json_object_set_new (sections_obj, section, sec_obj); -} - - -static void -add_section_contents (void *cls, - const char *section, - const char *option, - const char *value) -{ - json_t *section_obj = cls; - - json_object_set_new (section_obj, option, json_string (value)); -} - - -/** - * Handle rest request - * - * @param handle the lookup handle - */ -static void -get_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - const char *section; - char *response; - json_t *result; - - if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url)) - { - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (strlen (GNUNET_REST_API_NS_CONFIG) == strlen (handle->url)) - { - result = json_object (); - GNUNET_CONFIGURATION_iterate (cfg, &add_sections, result); - } - else - { - result = json_object (); - section = &handle->url[strlen (GNUNET_REST_API_NS_CONFIG) + 1]; - GNUNET_CONFIGURATION_iterate_section_values (cfg, - section, - &add_section_contents, - result); - } - response = json_dumps (result, 0); - resp = GNUNET_REST_create_response (response); - GNUNET_assert (MHD_NO != MHD_add_response_header (resp, - "Content-Type", - "application/json")); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - cleanup_handle (handle); - GNUNET_free (response); - json_decref (result); -} - - -struct GNUNET_CONFIGURATION_Handle * -set_value (struct GNUNET_CONFIGURATION_Handle *config, - const char *section, - const char *option, - json_t *value) -{ - if (json_is_string (value)) - GNUNET_CONFIGURATION_set_value_string (config, section, option, - json_string_value (value)); - else if (json_is_number (value)) - GNUNET_CONFIGURATION_set_value_number (config, section, option, - json_integer_value (value)); - else if (json_is_null (value)) - GNUNET_CONFIGURATION_set_value_string (config, section, option, NULL); - else if (json_is_true (value)) - GNUNET_CONFIGURATION_set_value_string (config, section, option, "yes"); - else if (json_is_false (value)) - GNUNET_CONFIGURATION_set_value_string (config, section, option, "no"); - else - return NULL; - return config; // for error handling (0 -> success, 1 -> error) -} - - -/** - * Handle REST POST request - * - * @param handle the lookup handle - */ -static void -set_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char *url, - void *cls) -{ - struct RequestHandle *handle = cls; - char term_data[handle->rest_handle->data_size + 1]; - struct GNUNET_CONFIGURATION_Handle *out = GNUNET_CONFIGURATION_dup (cfg); - - json_error_t err; - json_t *data_json; - const char *section; - const char *option; - json_t *sec_obj; - json_t *value; - char *cfg_fn; - - // invalid url - if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url)) - { - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - // extract data from handle - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_json = json_loads (term_data, JSON_DECODE_ANY, &err); - - if (NULL == data_json) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse JSON Object from %s\n", - term_data); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - // POST /config => {
: {