commit 365e4e6f7b32712891ed79f08401fcc2558f5bbb
parent 7bec20c7d509e16c1061731198b0bf92f84e2631
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date: Tue, 7 May 2024 22:07:05 +0200
RECLAIM: Start fixing OIDC plugin; add new CLI test
Diffstat:
5 files changed, 87 insertions(+), 18 deletions(-)
diff --git a/src/cli/reclaim/test_reclaim.conf b/src/cli/reclaim/test_reclaim.conf
@@ -8,7 +8,8 @@ START_ON_DEMAND = YES
[rest]
START_ON_DEMAND = YES
-PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=$GNUNET_TMP/restlog
+# PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=$GNUNET_TMP/restlog
+BASIC_AUTH_ENABLED = NO
[transport]
PLUGINS =
@@ -34,6 +35,10 @@ ZONE_PUBLISH_TIME_WINDOW = 1 h
DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
[reclaim-rest-plugin]
-address = http://localhost:8000/#/login
-psw = mysupersecretpassword
expiration_time = 3600
+JWT_SECRET = secret
+OIDC_USERINFO_CONSUME_TIMEOUT = 5s
+OIDC_DIR = $GNUNET_DATA_HOME/oidc
+OIDC_CLIENT_HMAC_SECRET = secret
+OIDC_JSON_WEB_ALGORITHM = RS256
+ADDRESS = https://ui.reclaim/#/login
diff --git a/src/cli/reclaim/test_reclaim_oidc.sh b/src/cli/reclaim/test_reclaim_oidc.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+trap "gnunet-arm -e -c test_reclaim.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_reclaim.conf -s PATHS -o GNUNET_HOME -f`
+
+which timeout >/dev/null 2>&1 && DO_TIMEOUT="timeout 30"
+
+RES=0
+TEST_ATTR="test"
+REDIRECT_URI="https://example.gns.alt/my_cb"
+SCOPE="\"openid email name\""
+gnunet-arm -s -c test_reclaim.conf
+gnunet-arm -i rest -c test_reclaim.conf
+gnunet-arm -I
+gnunet-identity -C testego -c test_reclaim.conf
+gnunet-identity -C rpego -c test_reclaim.conf
+TEST_KEY=$(gnunet-identity -d -e rpego -q -c test_reclaim.conf)
+SUBJECT_KEY=$(gnunet-identity -d -e testego -q -c test_reclaim.conf)
+gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf
+gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf
+
+# Register client
+gnunet-namestore -z rpego -a -n @ -t RECLAIM_OIDC_CLIENT -V "My RP" -e 1d -p -c test_reclaim.conf
+gnunet-namestore -z rpego -a -n @ -t RECLAIM_OIDC_REDIRECT -V $REDIRECT_URI -e 1d -p -c test_reclaim.conf
+
+gnunet-gns -u @.$TEST_KEY -t RECLAIM_OIDC_REDIRECT -c test_reclaim.conf
+curl -v -X POST -H -v "http://localhost:7776/openid/login" --data "{\"identity\": \"$SUBJECT_KEY\"}"
+
+PKCE_CHALLENGE=$(echo -n secret | openssl dgst -binary -sha256 | openssl base64 | sed 's/\=//g' | sed 's/+/-/g' | sed 's/\//_/g')
+
+CODE=$(curl -H "Cookie: Identity=$SUBJECT_KEY" "http://localhost:7776/openid/authorize?client_id=$TEST_KEY&response_type=code&redirect_uri=$REDIRECT_URI&scope=openid&claims=%7B%22userinfo%22%3A%20%7B%22email%22%3A%20%7B%22essential%22%20%20%20%20%3A%20true%7D%7D%2C%22id_token%22%3A%20%7B%22email%22%3A%20%7B%22essential%22%3A%20true%7D%7D%7D&state=xyz&code_challenge=$PKCE_CHALLENGE&code_challenge_method=S256" \
+ -sS -D - -o /dev/null | grep "Location: " | cut -d" " -f2 | cut -d"?" -f2 | cut -d"&" -f1 | cut -d"=" -f2)
+
+echo "Code: $CODE"
+
+curl -v -X POST -u$TEST_KEY:"secret" "http://localhost:7776/openid/token?client_id=$TEST_KEY&response_type=code&redirect_uri=$REDIRECT_URI&scope=openid&claims=%7B%22userinfo%22%3A%20%7B%22email%22%3A%20%7B%22essential%22%20%20%20%20%3A%20true%7D%7D%2C%22id_token%22%3A%20%7B%22email%22%3A%20%7B%22essential%22%3A%20true%7D%7D%7D&state=xyz&grant_type=authorization_code&code=$CODE&code_verifier=secret"
+
+gnunet-identity -D testego -c test_reclaim.conf
+gnunet-identity -D rpego -c test_reclaim.conf
+gnunet-arm -e -c test_reclaim.conf
+if test $RES != 0
+then
+ echo "Failed."
+fi
+
diff --git a/src/service/rest/oidc_helper.c b/src/service/rest/oidc_helper.c
@@ -27,6 +27,8 @@
#include <inttypes.h>
#include <jansson.h>
#include <jose/jose.h>
+#include "gnunet_gns_service.h"
+#include "gnunet_gnsrecord_lib.h"
#include "gnunet_util_lib.h"
#include "gnunet_reclaim_lib.h"
#include "gnunet_reclaim_service.h"
@@ -587,7 +589,8 @@ OIDC_build_authz_code (const struct GNUNET_CRYPTO_PrivateKey *issuer,
/** PLAINTEXT **/
// Assign ticket
memset (¶ms, 0, sizeof(params));
- params.ticket = *ticket;
+ memcpy (params.ticket.gns_name, ticket->gns_name, strlen (ticket->gns_name)
+ + 1);
// Assign nonce
payload_len = sizeof(struct OIDC_Parameters);
if ((NULL != nonce_str) && (strcmp ("", nonce_str) != 0))
@@ -756,7 +759,7 @@ OIDC_parse_authz_code (const char *rp_uri,
struct GNUNET_RECLAIM_AttributeList **attrs,
struct GNUNET_RECLAIM_PresentationList **presentations,
char **nonce_str,
- enum OIDC_VerificationOptions opts)
+ enum OIDC_VerificationOptions opts, char **emsg)
{
char *code_payload;
char *ptr;
@@ -766,6 +769,7 @@ OIDC_parse_authz_code (const char *rp_uri,
char *code_challenge;
struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
struct GNUNET_CRYPTO_Signature *signature;
+ struct GNUNET_CRYPTO_PublicKey iss;
uint32_t code_challenge_len;
uint32_t attrs_ser_len;
uint32_t pres_ser_len;
@@ -774,6 +778,8 @@ OIDC_parse_authz_code (const char *rp_uri,
uint32_t nonce_len = 0;
struct OIDC_Parameters *params;
+
+ GNUNET_GNS_parse_ztld (ticket->gns_name, &iss);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to decode `%s'\n", code);
code_payload = NULL;
code_payload_len =
@@ -807,6 +813,8 @@ OIDC_parse_authz_code (const char *rp_uri,
code_challenge_len,
code_verifier))
{
+ GNUNET_asprintf (emsg, "Code verifier `%s' invalid for challenge `%s'",
+ code_verifier, code_challenge);
GNUNET_free (code_payload);
return GNUNET_SYSERR;
}
@@ -828,12 +836,13 @@ OIDC_parse_authz_code (const char *rp_uri,
GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN,
purpose,
signature,
- cid))
+ &iss))
{
GNUNET_free (code_payload);
if (NULL != *nonce_str)
GNUNET_free (*nonce_str);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signature of AuthZ code invalid!\n");
+ *emsg = GNUNET_strdup ("Signature verification failed");
return GNUNET_SYSERR;
}
// Attributes
@@ -899,6 +908,7 @@ OIDC_access_token_new (const struct GNUNET_RECLAIM_Ticket *ticket,
sizeof(*ticket),
&tkt_b64);
GNUNET_asprintf (&access_token, "%s-%s", tkt_b64, rp_uri);
+ GNUNET_free (tkt_b64);
return access_token;
}
diff --git a/src/service/rest/oidc_helper.h b/src/service/rest/oidc_helper.h
@@ -138,7 +138,7 @@ OIDC_parse_authz_code (const char *rp_uri,
struct GNUNET_RECLAIM_AttributeList **attrs,
struct GNUNET_RECLAIM_PresentationList **presentations,
char **nonce,
- enum OIDC_VerificationOptions opts);
+ enum OIDC_VerificationOptions opts, char **emsg);
/**
* Build a token response for a token request
diff --git a/src/service/rest/openid_plugin.c b/src/service/rest/openid_plugin.c
@@ -2265,14 +2265,16 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
}
// decode code
+ char *emsg = NULL;
if (GNUNET_OK != OIDC_parse_authz_code (received_cid, &cid, code,
code_verifier,
&ticket,
&cl, &pl, &nonce,
- OIDC_VERIFICATION_DEFAULT))
+ OIDC_VERIFICATION_DEFAULT,
+ &emsg))
{
handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
- handle->edesc = GNUNET_strdup ("invalid code");
+ handle->edesc = emsg;
handle->response_code = MHD_HTTP_BAD_REQUEST;
GNUNET_free (code);
if (NULL != code_verifier)
@@ -2313,14 +2315,8 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
jwa = JWT_ALG_VALUE_RSA;
}
- char *tmp = GNUNET_strdup (ticket.gns_name);
- GNUNET_assert (NULL != strtok (tmp, "."));
- char *key = strtok (NULL, ".");
struct GNUNET_CRYPTO_PublicKey issuer;
- GNUNET_assert (NULL != key);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_public_key_from_string (key, &issuer));
- GNUNET_free (tmp);
+ GNUNET_GNS_parse_ztld (ticket.gns_name, &issuer);
if (! strcmp (jwa, JWT_ALG_VALUE_RSA))
{
@@ -2598,13 +2594,14 @@ consume_fail (void *cls)
sizeof(struct GNUNET_CRYPTO_PublicKey));
// decode code
+ char *emsg;
if (GNUNET_OK != OIDC_parse_authz_code (received_cid, &cid,
cached_code, NULL, &ticket,
&cl, &pl, &nonce,
- OIDC_VERIFICATION_NO_CODE_VERIFIER))
+ OIDC_VERIFICATION_NO_CODE_VERIFIER, &emsg))
{
handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
- handle->edesc = GNUNET_strdup ("invalid code");
+ handle->edesc = emsg;
handle->response_code = MHD_HTTP_BAD_REQUEST;
GNUNET_free (cached_code);
if (NULL != nonce)