From 78b7c56bd1502ec87054521970a8e5b9cf225b66 Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Mon, 12 Dec 2016 18:38:35 +0100 Subject: [PATCH] - Add rest plugin for credential --- src/credential/Makefile.am | 43 +-- src/credential/plugin_rest_credential.c | 418 ++++++++++++++++++++++++ 2 files changed, 434 insertions(+), 27 deletions(-) create mode 100644 src/credential/plugin_rest_credential.c diff --git a/src/credential/Makefile.am b/src/credential/Makefile.am index 47204ae26..13da9dc0f 100644 --- a/src/credential/Makefile.am +++ b/src/credential/Makefile.am @@ -4,16 +4,6 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/include EXTRA_DIST = \ test_credential_defaults.conf \ test_credential_lookup.conf -# test_gns_nick_shorten.conf \ -#### test_gns_proxy.conf \ -# test_gns_simple_lookup.conf \ -# gns-helper-service-w32.conf \ -# w32nsp.def \ -# gnunet-gns-proxy-setup-ca \ -# zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkey \ -# zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey \ -# zonefiles/test_zonekey \ -# $(check_SCRIPTS) if USE_COVERAGE @@ -45,11 +35,11 @@ plugin_LTLIBRARIES = \ libgnunet_plugin_gnsrecord_credential.la -#if HAVE_MHD -#if HAVE_JSON -#plugin_LTLIBRARIES += libgnunet_plugin_rest_gns.la -#endif -#endif +if HAVE_MHD +if HAVE_JSON +plugin_LTLIBRARIES += libgnunet_plugin_rest_credential.la +endif +endif gnunet_credential_SOURCES = \ @@ -89,18 +79,17 @@ libgnunetcredential_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) -#libgnunet_plugin_rest_gns_la_SOURCES = \ -# plugin_rest_gns.c -#libgnunet_plugin_rest_gns_la_LIBADD = \ -# libgnunetgns.la \ -# $(top_builddir)/src/rest/libgnunetrest.la \ -# $(top_builddir)/src/identity/libgnunetidentity.la \ -# $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \ -# $(top_builddir)/src/jsonapi/libgnunetjsonapiutils.la \ -# $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ -# $(LTLIBINTL) -ljansson -lmicrohttpd -#libgnunet_plugin_rest_gns_la_LDFLAGS = \ -# $(GN_PLUGIN_LDFLAGS) +libgnunet_plugin_rest_credential_la_SOURCES = \ + plugin_rest_credential.c +libgnunet_plugin_rest_credential_la_LIBADD = \ + libgnunetcredential.la \ + $(top_builddir)/src/rest/libgnunetrest.la \ + $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \ + $(top_builddir)/src/jsonapi/libgnunetjsonapiutils.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ + $(LTLIBINTL) -ljansson -lmicrohttpd +libgnunet_plugin_rest_credential_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) check_SCRIPTS = \ diff --git a/src/credential/plugin_rest_credential.c b/src/credential/plugin_rest_credential.c new file mode 100644 index 000000000..51d91079a --- /dev/null +++ b/src/credential/plugin_rest_credential.c @@ -0,0 +1,418 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2016 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ +/** + * @author Martin Schanzenbach + * @file gns/plugin_rest_credential.c + * @brief GNUnet CREDENTIAL REST plugin + * + */ + +#include "platform.h" +#include "gnunet_rest_plugin.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define GNUNET_REST_API_NS_CREDENTIAL "/credential" + +#define GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR "attribute" + +#define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR "credential" + +/** + * @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 VerifyHandle +{ + /** + * Handle to Credential service. + */ + struct GNUNET_CREDENTIAL_Handle *credential; + + /** + * Handle to lookup request + */ + struct GNUNET_CREDENTIAL_Request *verify_request; + + /** + * Handle to rest request + */ + struct GNUNET_REST_RequestHandle *rest_handle; + + /** + * ID of a task associated with the resolution process. + */ + struct GNUNET_SCHEDULER_Task * timeout_task; + + /** + * The root of the received JSON or NULL + */ + json_t *json_root; + + /** + * The plugin result processor + */ + GNUNET_REST_ResultProcessor proc; + + /** + * The closure of the result processor + */ + void *proc_cls; + + /** + * The issuer attribute to verify + */ + char *issuer_attr; + + /** + * The subject attribute + */ + char *subject_attr; + + /** + * The public key of the issuer + */ + struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key; + + /** + * The public key of the subject + */ + struct GNUNET_CRYPTO_EcdsaPublicKey subject_key; + + /** + * HTTP response code + */ + int response_code; + + /** + * Timeout + */ + struct GNUNET_TIME_Relative timeout; + +}; + + +/** + * Cleanup lookup handle. + * + * @param handle Handle to clean up + */ +static void +cleanup_handle (struct VerifyHandle *handle) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + if (NULL != handle->json_root) + json_decref (handle->json_root); + + if (NULL != handle->issuer_attr) + GNUNET_free (handle->issuer_attr); + if (NULL != handle->subject_attr) + GNUNET_free (handle->subject_attr); + if (NULL != handle->verify_request) + { + GNUNET_CREDENTIAL_verify_cancel (handle->verify_request); + handle->verify_request = NULL; + } + if (NULL != handle->credential) + { + GNUNET_CREDENTIAL_disconnect (handle->credential); + handle->credential = NULL; + } + + if (NULL != handle->timeout_task) + { + GNUNET_SCHEDULER_cancel (handle->timeout_task); + } + GNUNET_free (handle); +} + + +/** + * Task run on shutdown. Cleans up everything. + * + * @param cls unused + * @param tc scheduler context + */ +static void +do_error (void *cls) +{ + struct VerifyHandle *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 +verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle, + const char* url, + void *cls) +{ + struct VerifyHandle *handle = cls; + struct GNUNET_HashCode key; + char *tmp; + char *entity_attr; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connecting...\n"); + handle->credential = GNUNET_CREDENTIAL_connect (cfg); + handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_error, handle); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connected\n"); + if (NULL == handle->credential) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Connecting to CREDENTIAL failed\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR, + strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR), + &key); + if ( GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, + &key) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Missing issuer attribute\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, + &key); + entity_attr = GNUNET_strdup (tmp); + tmp = strtok(entity_attr, "."); + if (NULL == tmp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed issuer or attribute\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp, + strlen (tmp), + &handle->issuer_key)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed issuer key\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + tmp = strtok (NULL, "."); //Issuer attribute + if (NULL == tmp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed attribute\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->issuer_attr = GNUNET_strdup (tmp); + GNUNET_free (entity_attr); + + GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR, + strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR), + &key); + if ( GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, + &key) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Missing subject or attribute\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, + &key); + entity_attr = GNUNET_strdup (tmp); + tmp = strtok(entity_attr, "."); + if (NULL == tmp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed subject\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp, + strlen (tmp), + &handle->subject_key)) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed subject key\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + tmp = strtok (NULL, "."); + if (NULL == tmp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed subject attribute\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->subject_attr = GNUNET_strdup (tmp); + GNUNET_free (entity_attr); + + handle->verify_request = GNUNET_CREDENTIAL_verify (handle->credential, + &handle->issuer_key, + handle->issuer_attr, + &handle->subject_key, + handle->subject_attr, + NULL, + NULL); + +} + +/** + * Handle rest request + * + * @param handle the lookup handle + */ +static void +options_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct MHD_Response *resp; + struct VerifyHandle *handle = cls; + + //For GNS, independent of path return all options + resp = GNUNET_REST_create_response (NULL); + MHD_add_response_header (resp, + "Access-Control-Allow-Methods", + MHD_HTTP_METHOD_GET); + handle->proc (handle->proc_cls, + resp, + MHD_HTTP_OK); + cleanup_handle (handle); +} + + +/** + * 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 void +rest_credential_process_request(struct GNUNET_REST_RequestHandle *conndata_handle, + GNUNET_REST_ResultProcessor proc, + void *proc_cls) +{ + struct VerifyHandle *handle = GNUNET_new (struct VerifyHandle); + struct GNUNET_REST_RequestHandlerError err; + + handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; + handle->proc_cls = proc_cls; + handle->proc = proc; + handle->rest_handle = conndata_handle; + + static const struct GNUNET_REST_RequestHandler handlers[] = { + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL, &verify_cred_cont}, + {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CREDENTIAL, &options_cont}, + GNUNET_REST_HANDLER_END + }; + + if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle, + handlers, + &err, + handle)) + { + handle->response_code = err.error_code; + GNUNET_SCHEDULER_add_now (&do_error, handle); + } +} + + +/** + * Entry point for the plugin. + * + * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*" + * @return NULL on error, otherwise the plugin context + */ +void * +libgnunet_plugin_rest_credential_init (void *cls) +{ + static struct Plugin plugin; + cfg = cls; + struct GNUNET_REST_Plugin *api; + + 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_CREDENTIAL; + api->process_request = &rest_credential_process_request; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("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_credential_done (void *cls) +{ + struct GNUNET_REST_Plugin *api = cls; + struct Plugin *plugin = api->cls; + + plugin->cfg = NULL; + GNUNET_free (api); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "GNS REST plugin is finished\n"); + return NULL; +} + +/* end of plugin_rest_gns.c */ -- 2.25.1