From 897dd85d9feb5cd962db3bf2156a2a2b4d2841d4 Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Thu, 29 Dec 2016 11:28:10 +0100 Subject: [PATCH] -add collect rest; fixes --- src/credential/plugin_rest_credential.c | 255 ++++++++++++++++-- .../test_credential_collect_rest.sh | 90 +++++++ src/credential/test_credential_issue_rest.sh | 53 ++++ src/credential/test_credential_lookup.conf | 2 +- src/credential/test_credential_verify_rest.sh | 9 +- src/jsonapi/jsonapi_document.c | 2 +- 6 files changed, 391 insertions(+), 20 deletions(-) create mode 100755 src/credential/test_credential_collect_rest.sh create mode 100755 src/credential/test_credential_issue_rest.sh diff --git a/src/credential/plugin_rest_credential.c b/src/credential/plugin_rest_credential.c index 0d469f5de..59022e794 100644 --- a/src/credential/plugin_rest_credential.c +++ b/src/credential/plugin_rest_credential.c @@ -41,10 +41,14 @@ #define GNUNET_REST_API_NS_CREDENTIAL_VERIFY "/credential/verify" +#define GNUNET_REST_API_NS_CREDENTIAL_COLLECT "/credential/collect" + #define GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION "expiration" #define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY "subject_key" +#define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO "subject" + #define GNUNET_REST_JSONAPI_CREDENTIAL "credential" #define GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO "credential" @@ -92,6 +96,11 @@ struct RequestHandle */ struct GNUNET_IDENTITY_Operation *id_op; + /** + * Handle to ego lookup + */ + struct GNUNET_IDENTITY_EgoLookup *ego_lookup; + /** * Handle to rest request */ @@ -173,6 +182,8 @@ cleanup_handle (struct RequestHandle *handle) GNUNET_CREDENTIAL_disconnect (handle->credential); if (NULL != handle->id_op) GNUNET_IDENTITY_cancel (handle->id_op); + if (NULL != handle->ego_lookup) + GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup); if (NULL != handle->identity) GNUNET_IDENTITY_disconnect (handle->identity); if (NULL != handle->timeout_task) @@ -362,6 +373,103 @@ credential_to_json (struct GNUNET_CREDENTIAL_Credential *cred) return cred_obj; } +/** + * Function called with the result of a Credential lookup. + * + * @param cls the 'const char *' name that was resolved + * @param cd_count number of records returned + * @param cd array of @a cd_count records with the results + */ +static void +handle_collect_response (void *cls, + unsigned int d_count, + struct GNUNET_CREDENTIAL_Delegation *delegation_chain, + unsigned int c_count, + struct GNUNET_CREDENTIAL_Credential *cred) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + struct GNUNET_JSONAPI_Document *json_document; + struct GNUNET_JSONAPI_Resource *json_resource; + json_t *cred_obj; + json_t *cred_array; + char *result; + char *issuer; + char *id; + uint32_t i; + + handle->verify_request = NULL; + if (NULL == cred) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Verify failed.\n"); + handle->response_code = MHD_HTTP_NOT_FOUND; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&handle->issuer_key); + if (NULL == issuer) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Issuer in delegation malformed\n"); + return; + } + GNUNET_asprintf (&id, + "%s.%s", + issuer, + handle->issuer_attr); + GNUNET_free (issuer); + json_document = GNUNET_JSONAPI_document_new (); + json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO, + id); + GNUNET_free (id); + cred_array = json_array (); + for (i=0;iproc (handle->proc_cls, resp, MHD_HTTP_OK); + cleanup_handle (handle); +} + +static void +subject_ego_lookup (void *cls, + const struct GNUNET_IDENTITY_Ego *ego) +{ + struct RequestHandle *handle = cls; + const struct GNUNET_CRYPTO_EcdsaPrivateKey *sub_key; + handle->ego_lookup = NULL; + + if (NULL == ego) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Subject not found\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + sub_key = GNUNET_IDENTITY_ego_get_private_key (ego); + handle->verify_request = GNUNET_CREDENTIAL_collect (handle->credential, + &handle->issuer_key, + handle->issuer_attr, + sub_key, + &handle_collect_response, + handle); +} + + + /** * Function called with the result of a Credential lookup. * @@ -446,6 +554,107 @@ handle_verify_response (void *cls, cleanup_handle (handle); } +static void +collect_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle, + const char* url, + void *cls) +{ + struct RequestHandle *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_EGO, + strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO), + &key); + if ( GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, + &key) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Missing subject\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, + &key); + if (NULL == tmp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed subject\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg, + tmp, + &subject_ego_lookup, + handle); +} + + static void verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle, @@ -527,15 +736,15 @@ verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle, 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), + GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY, + strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY), &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"); + "Missing subject key\n"); GNUNET_free (entity_attr); GNUNET_SCHEDULER_add_now (&do_error, handle); return; @@ -560,7 +769,6 @@ verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle, GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - GNUNET_free (entity_attr); if (0 >= handle->rest_handle->data_size) { @@ -596,28 +804,44 @@ verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle, } resource_count = GNUNET_JSONAPI_document_resource_count(json_obj); + GNUNET_assert (1 == resource_count); + res = (GNUNET_JSONAPI_document_get_resource(json_obj, 0)); + if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type(res, + GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Resource not a credential!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse JSONAPI Object from %s\n", + term_data); + GNUNET_JSONAPI_document_delete (json_obj); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + cred_json = GNUNET_JSONAPI_resource_read_attr (res, + GNUNET_REST_JSONAPI_CREDENTIAL); + + GNUNET_assert (json_is_array (cred_json)); + + credential_count = json_array_size(cred_json); + struct GNUNET_CREDENTIAL_Credential credentials[credential_count]; - for (i=0;iissuer_attribute); GNUNET_free (cred); } - + GNUNET_JSONAPI_document_delete(json_obj); handle->verify_request = GNUNET_CREDENTIAL_verify (handle->credential, &handle->issuer_key, handle->issuer_attr, @@ -888,7 +1112,8 @@ rest_credential_process_request(struct GNUNET_REST_RequestHandle *conndata_handl handle->rest_handle = conndata_handle; static const struct GNUNET_REST_RequestHandler handlers[] = { - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_VERIFY, &verify_cred_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_CREDENTIAL_VERIFY, &verify_cred_cont}, + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_COLLECT, &collect_cred_cont}, {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_ISSUE, &issue_cred_cont}, {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CREDENTIAL, &options_cont}, GNUNET_REST_HANDLER_END diff --git a/src/credential/test_credential_collect_rest.sh b/src/credential/test_credential_collect_rest.sh new file mode 100755 index 000000000..0b31f85bc --- /dev/null +++ b/src/credential/test_credential_collect_rest.sh @@ -0,0 +1,90 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_credential_lookup.conf" SIGINT + +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_credential_lookup.conf -s PATHS -o GNUNET_HOME -f` + +# (1) Service.user -> GNU.project.member +# (2) GNU.project -> GNUnet +# (3) GNUnet.member -> GNUnet.developer +# (4) GNUnet.member -> GNUnet.user +# (5) GNUnet.developer -> Alice + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" +gnunet-arm -s -c test_credential_lookup.conf +gnunet-identity -C service -c test_credential_lookup.conf +gnunet-identity -C alice -c test_credential_lookup.conf +gnunet-identity -C gnu -c test_credential_lookup.conf +gnunet-identity -C gnunet -c test_credential_lookup.conf + +GNU_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnu | grep -v gnunet | awk '{print $3}') +ALICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep alice | awk '{print $3}') +GNUNET_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnunet | awk '{print $3}') +SERVICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep service | awk '{print $3}') + +USER_ATTR="user" +GNU_PROJECT_ATTR="project" +MEMBER_ATTR="member" +DEVELOPER_ATTR="developer" +DEV_ATTR="developer" +TEST_CREDENTIAL="mygnunetcreds" + +# (1) A service assigns the attribute "user" to all entities that have been assigned "member" by entities that werde assigned "project" from GNU +gnunet-namestore -p -z service -a -n $USER_ATTR -t ATTR -V "$GNU_KEY $GNU_PROJECT_ATTR.$MEMBER_ATTR" -e 5m -c test_credential_lookup.conf + +# (2) GNU recognized GNUnet as a GNU project and delegates the "project" attribute +gnunet-namestore -p -z gnu -a -n $GNU_PROJECT_ATTR -t ATTR -V "$GNUNET_KEY" -e 5m -c test_credential_lookup.conf + +# (3+4) GNUnet assigns the attribute "member" to all entities gnunet has also assigned "developer" or "user" +gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $DEVELOPER_ATTR" -e 5m -c test_credential_lookup.conf +gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $USER_ATTR" -e 5m -c test_credential_lookup.conf + +# (5) GNUnet issues Alice the credential "developer" +CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$DEV_ATTR --ttl=5m -c test_credential_lookup.conf` + +# Alice stores the credential under "mygnunetcreds" +gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf + +# (5) GNUnet issues Alice the credential "developer" +CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$USER_ATTR --ttl=5m -c test_credential_lookup.conf` + +# Alice stores the credential under "mygnunetcreds" +gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf + +#TODO2 Add -z swich like in gnunet-gns +#RES_CRED=`gnunet-credential --collect --issuer=$SERVICE_KEY --attribute=$USER_ATTR --subject=$ALICE_KEY -c test_credential_lookup.conf` + +gnunet-arm -i rest -c test_credential_lookup.conf + +sleep 5 + +curl -v "localhost:7776/credential/collect?attribute=$SERVICE_KEY.$USER_ATTR&subject=alice" + +#TODO cleanup properly +gnunet-namestore -z alice -d -n $TEST_CREDENTIAL -t CRED -e never -c test_credential_lookup.conf +gnunet-namestore -z gnu -d -n $GNU_PROJECT_ATTR -t ATTR -c test_credential_lookup.conf +gnunet-namestore -z gnunet -d -n $MEMBER_ATTR -t ATTR -c test_credential_lookup.conf +gnunet-namestore -z service -d -n $USER_ATTR -t ATTR -c test_credential_lookup.conf +echo "Stopping arm..." +gnunet-arm -e -c test_credential_lookup.conf +echo "Done" +if [ "$RES_CRED" != "Failed." ] +then + echo -e "${RES_CRED}" + exit 0 +else + echo "FAIL: Failed to verify credential $RES_CRED." + exit 1 +fi diff --git a/src/credential/test_credential_issue_rest.sh b/src/credential/test_credential_issue_rest.sh new file mode 100755 index 000000000..15cd55083 --- /dev/null +++ b/src/credential/test_credential_issue_rest.sh @@ -0,0 +1,53 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_credential_lookup.conf" SIGINT + +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_credential_lookup.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +gnunet-arm -s -c test_credential_lookup.conf +gnunet-arm -i gns +gnunet-arm -i credential +gnunet-arm -i identity +gnunet-arm -i rest -c test_credential_lookup.conf + +gnunet-arm -I -c test_credential_lookup.conf +gnunet-identity -C testissuer -c test_credential_lookup.conf +gnunet-identity -C testsubject -c test_credential_lookup.conf +gnunet-identity -s credential-issuer -e testissuer +SUBJECT_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testsubject | awk '{print $3}') +ISSUER_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testissuer | awk '{print $3}') +#TODO1 Get credential and store it with subject (3) +sleep 5 +curl "localhost:7776/credential/issue?subject_key=$SUBJECT_KEY&attribute=$TEST_ATTR&expiration=1d" +#CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=testissuer --subject=$SUBJECT_KEY --attribute=$TEST_ATTR --ttl=5m -c test_credential_lookup.conf` +STATUS=$? + +if test $? != 0 +then + echo "Error issuing..." + exit 1 +fi +#Try import +#$DO_TIMEOUT gnunet-namestore -a -z testsubject -n c1 -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf +RES=$? +gnunet-arm -e -c test_credential_lookup.conf +exit $RES diff --git a/src/credential/test_credential_lookup.conf b/src/credential/test_credential_lookup.conf index 93b4864d9..3684063b1 100644 --- a/src/credential/test_credential_lookup.conf +++ b/src/credential/test_credential_lookup.conf @@ -14,7 +14,7 @@ AUTOSTART = YES PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/credlog [rest] -#PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/restlog +PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/restlog [gns] #PREFIX = valgrind --leak-check=full --track-origins=yes diff --git a/src/credential/test_credential_verify_rest.sh b/src/credential/test_credential_verify_rest.sh index 092737df7..6133ea25e 100755 --- a/src/credential/test_credential_verify_rest.sh +++ b/src/credential/test_credential_verify_rest.sh @@ -58,14 +58,17 @@ CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY -- gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf #TODO2 Add -z swich like in gnunet-gns -RES_CRED=`gnunet-credential --verify --issuer=$SERVICE_KEY --attribute=$USER_ATTR --subject=$ALICE_KEY --credential=$TEST_CREDENTIAL -c test_credential_lookup.conf` +#RES_CRED=`gnunet-credential --verify --issuer=$SERVICE_KEY --attribute=$USER_ATTR --subject=$ALICE_KEY --credential=$TEST_CREDENTIAL -c test_credential_lookup.conf` gnunet-arm -i rest -c test_credential_lookup.conf sleep 5 -echo "localhost:7776/credential?attribute=$SERVICE_KEY.$USER_ATTR&credential=$ALICE_KEY.$TEST_CREDENTIAL" -curl -v "localhost:7776/credential?attribute=$SERVICE_KEY.$USER_ATTR&credential=$ALICE_KEY.$TEST_CREDENTIAL" +CREDS=`curl "localhost:7776/credential/collect?attribute=$SERVICE_KEY.$USER_ATTR&subject=alice"` + +echo $CREDS + +curl -v "localhost:7776/credential/verify?attribute=$SERVICE_KEY.$USER_ATTR&subject_key=$ALICE_KEY" --data "$CREDS" #TODO cleanup properly gnunet-namestore -z alice -d -n $TEST_CREDENTIAL -t CRED -e never -c test_credential_lookup.conf diff --git a/src/jsonapi/jsonapi_document.c b/src/jsonapi/jsonapi_document.c index 8022a9f6e..3a60940f6 100644 --- a/src/jsonapi/jsonapi_document.c +++ b/src/jsonapi/jsonapi_document.c @@ -344,7 +344,7 @@ GNUNET_JSONAPI_document_to_json (const struct GNUNET_JSONAPI_Document *doc, GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_resource_to_json (res, &res_json_tmp)); - json_array_append (res_json, res_json_tmp); + json_array_append_new (res_json, res_json_tmp); } } json_object_set_new (*root_json, -- 2.25.1