From 1c8219b0c7310d18bca215b51a2ea48401cea4d4 Mon Sep 17 00:00:00 2001 From: kexkey Date: Wed, 17 Nov 2021 01:07:28 -0500 Subject: [PATCH] Fixed JWT and added tests for the gatekeeper --- api_auth_docker/Dockerfile | 5 +- api_auth_docker/README.md | 24 +- api_auth_docker/auth.sh | 98 ++- api_auth_docker/tests.sh | 299 --------- api_auth_docker/tests/colors.sh | 73 +++ api_auth_docker/tests/test-gatekeeper.sh | 612 ++++++++++++++++++ clients/javascript/cyphernode-client.js | 16 +- clients/shell/cyphernode-client.sh | 2 +- .../templates/gatekeeper/api.properties | 3 +- .../templates/installer/testfeatures.sh | 15 +- doc/INSTALL-MANUAL-STEPS.md | 8 +- doc/INSTALL-MANUALLY.md | 8 +- doc/INSTALL.md | 8 +- doc/README.md | 6 +- 14 files changed, 822 insertions(+), 355 deletions(-) delete mode 100644 api_auth_docker/tests.sh create mode 100644 api_auth_docker/tests/colors.sh create mode 100755 api_auth_docker/tests/test-gatekeeper.sh diff --git a/api_auth_docker/Dockerfile b/api_auth_docker/Dockerfile index e109638..4d15896 100644 --- a/api_auth_docker/Dockerfile +++ b/api_auth_docker/Dockerfile @@ -1,13 +1,14 @@ FROM nginx:1.18.0-alpine RUN apk add --update --no-cache \ - bash \ + bash \ git \ openssl \ fcgiwrap \ spawn-fcgi \ curl \ - jq + jq \ + coreutils COPY auth.sh /etc/nginx/conf.d/ COPY default.conf /etc/nginx/conf.d/default.conf diff --git a/api_auth_docker/README.md b/api_auth_docker/README.md index 399f83f..cf22831 100644 --- a/api_auth_docker/README.md +++ b/api_auth_docker/README.md @@ -88,7 +88,7 @@ If you don't want to use HTTPS, just copy default.conf instead of default-ssl.co docker build -t authapi . ``` -If you are using it independantly from the Docker stack (docker-compose.yml), you can run it like that: +If you are using it independently from the Docker stack (docker-compose.yml), you can run it like this: ```shell docker run -d --rm --name authapi -p 80:80 -p 443:443 --network cyphernodenet -v "~/cyphernode-ssl/certs:/etc/ssl/certs" -v "~/cyphernode-ssl/private:/etc/ssl/private" authapi @@ -108,16 +108,16 @@ Authorization: Bearer token = hhh.ppp.sss ``` -...where hhh is the header in base64, ppp is the payload in base64 and sss is the signature. Here are the expected formats and contents: +...where hhh is the header in unpadded base64url, ppp is the payload in unpadded base64url and sss is the signature in unpadded base64url. Here are the expected formats and contents: ```shell header = {"alg":"HS256","typ":"JWT"} -header64 = base64(header) = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9Cg== +header64 = unpad(base64url(header)) = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 ``` ```shell payload = {"id":"001","exp":1538528077} -payload64 = base64(payload) = eyJpZCI6IjAwMSIsImV4cCI6MTUzODUyODA3N30K +payload64 = unpad(base64url(payload)) = eyJpZCI6IjAwMSIsImV4cCI6MTUzODUyODA3N30 ``` The "id" property is the client id and the "exp" property should be current epoch time + 10 seconds, like: @@ -129,7 +129,7 @@ $((`date +"%s"`+10)) ...so that the request will be expired in 10 seconds. That should take care of most Replay attacks if any. You should run nginx with TLS so that the replay attack can't be possible. ```shell -signature = hmacsha256(header64.payload64, key) +signature = unpad(base64url(hmacsha256(header64.payload64, key))) ``` ```shell @@ -147,21 +147,21 @@ curl -v -H "Authorization: Bearer hhh.ppp.sss" localhost 10 seconds request expiration: ```shell -id="001";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="2df1eeea370eacdc5cf7e96c2d82140d1568079a5d4d87006ec8718a98883b36";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Authorization: Bearer $token" -k https://localhost/getbestblockhash +id="003";key="926c4cced4efd969ea9e40e1666b985319af842a4b0b641c157713959ebd49cb";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/getbestblockhash ``` 60 seconds request expiration: ```shell -id="001";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+60))}" | base64);k="2df1eeea370eacdc5cf7e96c2d82140d1568079a5d4d87006ec8718a98883b36";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Authorization: Bearer $token" -k https://localhost/getbestblockhash +id="003";key="926c4cced4efd969ea9e40e1666b985319af842a4b0b641c157713959ebd49cb";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+60))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/getbestblockhash ``` ## Technicalities ```shell -h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64) -p64=$(echo -n "{\"id\":\"001\",\"exp\":$((`date +"%s"`+10))}" | base64) -k="2df1eeea370eacdc5cf7e96c2d82140d1568079a5d4d87006ec8718a98883b36" -s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1) -token="$h64.$p64.$s" +h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=') +p64=$(echo -n '{"id":"001","exp":1637032766}' | basenc --base64url | tr -d '=') +key="2df1eeea370eacdc5cf7e96c2d82140d1568079a5d4d87006ec8718a98883b36" +sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=') +token="${h64}.${p64}.${sig}" ``` diff --git a/api_auth_docker/auth.sh b/api_auth_docker/auth.sh index 7a543b9..b5f80a0 100755 --- a/api_auth_docker/auth.sh +++ b/api_auth_docker/auth.sh @@ -3,15 +3,29 @@ # # This is not designed to serve thousands of API key! # +# 401 = authentication error +# 403 = authorization error +# # header = {"alg":"HS256","typ":"JWT"} -# header64 = base64(header) = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9Cg== +# header64 = unpad(base64url(header)) = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 # # payload = {"id":"001","exp":1538528077} -# payload64 = base64(payload) = eyJpZCI6IjAwMSIsImV4cCI6MTUzODUyODA3N30K +# payload64 = unpad(base64url(payload)) = eyJpZCI6IjAwMSIsImV4cCI6MTUzODUyODA3N30K # -# signature = hmacsha256(header64.payload64, key) +# signature = unpad(base64url(hmacsha256(header64.payload64, key))) # -# token = header64.payload64.signature = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9Cg==.eyJpZCI6IjAwMSIsImV4cCI6MTUzODUyODA3N30K.signature +# token = header64.payload64.signature = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjAwMSIsImV4cCI6MTUzODUyODA3N30K.signature +# +# +# Previous implementation of gatekeeper had a bug in the generation/validation of the JWT token: +# - The header and payload were in base64 instead of unpadded base64url +# - the signature was in HEX instead of unpadded base64url. +# +# Ref.: Appendix C of RFC 7515, "JSON Web Signature (JWS)" +# https://www.rfc-editor.org/rfc/rfc7515.txt +# +# To stay backward-compatible, we'll validate the right way first and if the +# signature is not valid, we'll validate the old-broken way. # . ./trace.sh @@ -27,11 +41,47 @@ verify_sign() { trace "[verify_sign] payload64=${payload64}" trace "[verify_sign] signature=${signature}" - local payload=$(echo -n "${payload64}" | base64 -d) - local exp=$(echo "${payload}" | jq ".exp") + local padding + case $((${#payload64}%4)) in + 2) padding='==' + ;; + 3) padding='=' + ;; + esac + # When broken-legacy used, padding is always empty because we were using base64 + # which is padded + trace "[verify_sign] padding=${padding}" + local payload + local legacy + # When broken-legacy used, this will fail if + and / found in payload because + # it's base64 instead of base64url. + payload=$(echo -n "${payload64}${padding}" | basenc --base64url -d) + if [ "$?" -ne "0" ]; then + # We got a legacy broken JWT with + and / in it + trace "[verify_sign] We got a legacy broken JWT" + legacy=1 + fi + + # Let's get the base64 broken legacy payload in case we have to validate it below... + # If base64 -d fails, it means we got a correct JWT-formed payload. + local legacypayload + legacypayload=$(echo -n "${payload64}" | base64 -d) + if [ "$?" -ne "0" ]; then + # We got a fixed unpadded base64url, no need to try old-broken validation + trace "[verify_sign] We got a fixed unpadded base64url, no need to try old-broken validation" + legacy=0 + fi + + local exp + if [ "${legacy}" -eq "1" ]; then + exp=$(echo "${legacypayload}" | jq ".exp") + else + exp=$(echo "${payload}" | jq ".exp") + fi local current=$(date +"%s") trace "[verify_sign] payload=${payload}" + trace "[verify_sign] legacypayload=${legacypayload}" trace "[verify_sign] exp=${exp}" trace "[verify_sign] current=${current}" @@ -57,9 +107,23 @@ verify_sign() { local msg="${header64}.${payload64}" trace "[verify_sign] msg=${msg}" - local comp_sign=$(echo -n "${msg}" | openssl dgst -hmac "${key}" -sha256 -r | cut -sd ' ' -f1) + local comp_sign + if [ "${legacy}" -eq "1" ]; then + comp_sign=$(echo -n "${msg}" | openssl dgst -hmac "${key}" -sha256 -r | cut -sd ' ' -f1) + else + comp_sign=$(echo -n "${msg}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=') + fi trace "[verify_sign] comp_sign=${comp_sign}" + if [ "${comp_sign}" != "${signature}" ] && [ -z "${legacy}" ]; then + # Invalid sig and legacy empty, we don't know if legacy or not... + # So we'll try legacy validation... + trace "[verify_sign] Invalid signature, let's try legacy..." + + comp_sign=$(echo -n "${msg}" | openssl dgst -hmac "${key}" -sha256 -r | cut -sd ' ' -f1) + trace "[verify_sign] comp_sign=${comp_sign}" + fi + if [ "${comp_sign}" = "${signature}" ]; then trace "[verify_sign] Valid signature!" @@ -71,14 +135,14 @@ verify_sign() { return fi trace "[verify_sign] Invalid group!" - return 1 + return 3 fi trace "[verify_sign] Invalid signature!" return 1 fi trace "[verify_sign] Expired!" - return 1 + return 3 } verify_group() { @@ -95,7 +159,7 @@ verify_group() { local actiontoinspect=$(echo "$action" | tr -d '_-') case $actiontoinspect in (*[![:alnum:]]*|"") trace "[verify_group] Potential code injection, exiting" - return 1 + return 3 esac local needed_group @@ -124,9 +188,10 @@ verify_group() { fi trace "[verify_group] Access NOT granted" - return 1 + return 3 } +returncode=0 # $HTTP_AUTHORIZATION = Bearer # Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjAwMyIsImV4cCI6MTU0MjE0OTMyNH0=.b811067cf79c7009a0a38f110a6e3bf82cc4310aa6afae75b9d915b9febf13f7 @@ -139,8 +204,15 @@ if [ "-${HTTP_AUTHORIZATION%% *}" = "-Bearer" ]; then if [ -n "$token" ]; then trace "[auth.sh] Valid format for authorization header" verify_sign "${token}" - [ "$?" -eq "0" ] && return + returncode=$? + trace "[auth.sh] returncode=${returncode}" + [ "$returncode" -eq "0" ] && return fi fi -echo -en "Status: 403 Forbidden\r\n\r\n" +if [ "${returncode}" -eq "1" ]; then + echo -en "Status: 401 Unauthorized\r\n\r\n" +else + echo -en "Status: 403 Forbidden\r\n\r\n" +fi + diff --git a/api_auth_docker/tests.sh b/api_auth_docker/tests.sh deleted file mode 100644 index e95fd26..0000000 --- a/api_auth_docker/tests.sh +++ /dev/null @@ -1,299 +0,0 @@ -#!/bin/sh - -# We just want to test the authentication/authorization, not the actual called function -# Replace -# proxy_pass http://cyphernode:8888; -# by -# proxy_pass http://cyphernode:1111; -# in /etc/nginx/conf.d/default.conf to run the tests - -test_expiration() -{ - # Let's test expiration: 1 second in payload, request 2 seconds later - - local id=${1} -# echo "id=${id}" - local k - eval k='$ukey_'$id - - local p64=$(echo "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+1))}" | base64) - local s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1) - local token="$h64.$p64.$s" - - echo " Sleeping 2 seconds... " - sleep 2 - - local rc - echo -n " Testing expired request... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/getblockinfo) - [ "${rc}" -ne "403" ] && return 10 - - return 0 -} - -test_authentication() -{ - # Let's test authentication/signature - - local id=${1} -# echo "id=${id}" - local k - eval k='$ukey_'$id - - local p64=$(echo "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64) - local s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1) - local token="$h64.$p64.$s" - - local rc - - echo -n " Testing good signature... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/getblockinfo) - [ "${rc}" -eq "403" ] && return 20 - - token="$h64.$p64.a$s" - echo -n " Testing bad signature... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/getblockinfo) - [ "${rc}" -ne "403" ] && return 30 - - return 0 -} - -test_authorization_watcher() -{ - # Let's test autorization - - local id=${1} -# echo "id=${id}" - local k - eval k='$ukey_'$id - - local p64=$(echo "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+20))}" | base64) - local s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1) - local token="$h64.$p64.$s" - - local rc - - # Watcher can: - # watch - echo -n " Testing watch... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/watch) - [ "${rc}" -eq "403" ] && return 40 - - # unwatch - echo -n " Testing unwatch... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/unwatch) - [ "${rc}" -eq "403" ] && return 50 - - # getactivewatches - echo -n " Testing getactivewatches... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/getactivewatches) - [ "${rc}" -eq "403" ] && return 60 - - # getbestblockhash - echo -n " Testing getbestblockhash... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/getbestblockhash) - [ "${rc}" -eq "403" ] && return 70 - - # getbestblockinfo - echo -n " Testing getbestblockinfo... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/getbestblockinfo) - [ "${rc}" -eq "403" ] && return 80 - - # getblockinfo - echo -n " Testing getblockinfo... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/getblockinfo) - [ "${rc}" -eq "403" ] && return 90 - - # gettransaction - echo -n " Testing gettransaction... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/gettransaction) - [ "${rc}" -eq "403" ] && return 100 - - # ln_getinfo - echo -n " Testing ln_getinfo... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/ln_getinfo) - [ "${rc}" -eq "403" ] && return 110 - - # ln_create_invoice - echo -n " Testing ln_create_invoice... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/ln_create_invoice) - [ "${rc}" -eq "403" ] && return 120 - - return 0 -} - -test_authorization_spender() -{ - # Let's test autorization - - local id=${1} -# echo "id=${id}" - local is_spender=${2} -# echo "is_spender=${is_spender}" - local k - eval k='$ukey_'$id - - local p64=$(echo "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+20))}" | base64) - local s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1) - local token="$h64.$p64.$s" - - local rc - - # Spender can do what the watcher can do, plus: - # getbalance - echo -n " Testing getbalance... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/getbalance) - [ ${is_spender} = true ] && [ "${rc}" -eq "403" ] && return 430 - [ ${is_spender} = false ] && [ "${rc}" -ne "403" ] && return 435 - - # getnewaddress - echo -n " Testing getnewaddress... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/getnewaddress) - [ ${is_spender} = true ] && [ "${rc}" -eq "403" ] && return 440 - [ ${is_spender} = false ] && [ "${rc}" -ne "403" ] && return 445 - - # spend - echo -n " Testing spend... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/spend) - [ ${is_spender} = true ] && [ "${rc}" -eq "403" ] && return 450 - [ ${is_spender} = false ] && [ "${rc}" -ne "403" ] && return 455 - - # addtobatch - echo -n " Testing addtobatch... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/addtobatch) - [ ${is_spender} = true ] && [ "${rc}" -eq "403" ] && return 460 - [ ${is_spender} = false ] && [ "${rc}" -ne "403" ] && return 465 - - # batchspend - echo -n " Testing batchspend... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/batchspend) - [ ${is_spender} = true ] && [ "${rc}" -eq "403" ] && return 470 - [ ${is_spender} = false ] && [ "${rc}" -ne "403" ] && return 475 - - # deriveindex - echo -n " Testing deriveindex... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/deriveindex) - [ ${is_spender} = true ] && [ "${rc}" -eq "403" ] && return 480 - [ ${is_spender} = false ] && [ "${rc}" -ne "403" ] && return 485 - - # derivepubpath - echo -n " Testing derivepubpath... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/derivepubpath) - [ ${is_spender} = true ] && [ "${rc}" -eq "403" ] && return 490 - [ ${is_spender} = false ] && [ "${rc}" -ne "403" ] && return 495 - - # ln_pay - echo -n " Testing ln_pay... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/ln_pay) - [ ${is_spender} = true ] && [ "${rc}" -eq "403" ] && return 500 - [ ${is_spender} = false ] && [ "${rc}" -ne "403" ] && return 505 - - # ln_newaddr - echo -n " Testing ln_newaddr... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/ln_newaddr) - [ ${is_spender} = true ] && [ "${rc}" -eq "403" ] && return 510 - [ ${is_spender} = false ] && [ "${rc}" -ne "403" ] && return 515 - - # ots_stamp - echo -n " Testing ots_stamp... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/ots_stamp) - [ ${is_spender} = true ] && [ "${rc}" -eq "403" ] && return 520 - [ ${is_spender} = false ] && [ "${rc}" -ne "403" ] && return 525 - - # ots_getfile - echo -n " Testing ots_getfile... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/ots_getfile) - [ ${is_spender} = true ] && [ "${rc}" -eq "403" ] && return 530 - [ ${is_spender} = false ] && [ "${rc}" -ne "403" ] && return 535 - - return 0 -} - -test_authorization_internal() -{ - # Let's test autorization - - local id=${1} -# echo "id=${id}" - local k - eval k='$ukey_'$id - - local p64=$(echo "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64) - local s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1) - local token="$h64.$p64.$s" - - local rc - - # Should be called from inside the Swarm: - # conf - echo -n " Testing conf... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/conf) - [ "${rc}" -ne "403" ] && return 920 - - # executecallbacks - echo -n " Testing executecallbacks... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/executecallbacks) - [ "${rc}" -ne "403" ] && return 930 - - # ots_backoffice - echo -n " Testing ots_backoffice... " - rc=$(time -f "%E" curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" -k https://localhost/ots_backoffice) - [ "${rc}" -ne "403" ] && return 940 - - return 0 -} - -kapi_id="001";kapi_key="2df1eeea370eacdc5cf7e96c2d82140d1568079a5d4d87006ec8718a98883b36";kapi_groups="watcher";eval ugroups_${kapi_id}=${kapi_groups};eval ukey_${kapi_id}=${kapi_key} -kapi_id="003";kapi_key="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";kapi_groups="watcher,spender";eval ugroups_${kapi_id}=${kapi_groups};eval ukey_${kapi_id}=${kapi_key} -kapi_id="005";kapi_key="6c009201b123e8c24c6b74590de28c0c96f3287e88cac9460a2173a53d73fb87";kapi_groups="watcher,spender,admin";eval ugroups_${kapi_id}=${kapi_groups};eval ukey_${kapi_id}=${kapi_key} -h64=$(echo "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64) - -# Let's test expiration: 1 second in payload, request 2 seconds later - -echo 'test_expiration "001"' -test_expiration "001" ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc -echo 'test_expiration "003"' -test_expiration "003" ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc -echo 'test_expiration "005"' -test_expiration "005" ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc - -# Let's test authentication/signature - -echo 'test_authentication "001"' -test_authentication "001" ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc -echo 'test_authentication "003"' -test_authentication "003" ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc -echo 'test_authentication "005"' -test_authentication "005" ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc - -# Let's test autorization for watcher actions - -echo 'test_authorization_watcher "001"' -test_authorization_watcher "001" ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc -echo 'test_authorization_watcher "003"' -test_authorization_watcher "003" ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc -echo 'test_authorization_watcher "005"' -test_authorization_watcher "005" ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc - -# Let's test autorization for spender actions - -echo 'test_authorization_spender "001" false' -test_authorization_spender "001" false ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc -echo 'test_authorization_spender "003" true' -test_authorization_spender "003" true ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc -echo 'test_authorization_spender "005" true' -test_authorization_spender "005" true ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc - -# Let's test autorization for admin actions - -#test_authorization_admin "001" -#test_authorization_admin "003" -#test_authorization_admin "005" - -# Let's test autorization for internal actions -echo 'test_authorization_internal "001"' -test_authorization_internal "001" ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc -echo 'test_authorization_internal "003"' -test_authorization_internal "003" ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc -echo 'test_authorization_internal "005"' -test_authorization_internal "005" ; rc=$? ; [ $rc -ne 0 ] && echo $rc && return $rc diff --git a/api_auth_docker/tests/colors.sh b/api_auth_docker/tests/colors.sh new file mode 100644 index 0000000..9978103 --- /dev/null +++ b/api_auth_docker/tests/colors.sh @@ -0,0 +1,73 @@ + +# Reset +Color_Off='\033[0m' # Text Reset + +# Regular Colors +Black='\033[0;30m' # Black +Red='\033[0;31m' # Red +Green='\033[0;32m' # Green +Yellow='\033[0;33m' # Yellow +Blue='\033[0;34m' # Blue +Purple='\033[0;35m' # Purple +Cyan='\033[0;36m' # Cyan +White='\033[0;37m' # White + +# Bold +BBlack='\033[1;30m' # Black +BRed='\033[1;31m' # Red +BGreen='\033[1;32m' # Green +BYellow='\033[1;33m' # Yellow +BBlue='\033[1;34m' # Blue +BPurple='\033[1;35m' # Purple +BCyan='\033[1;36m' # Cyan +BWhite='\033[1;37m' # White + +# Underline +UBlack='\033[4;30m' # Black +URed='\033[4;31m' # Red +UGreen='\033[4;32m' # Green +UYellow='\033[4;33m' # Yellow +UBlue='\033[4;34m' # Blue +UPurple='\033[4;35m' # Purple +UCyan='\033[4;36m' # Cyan +UWhite='\033[4;37m' # White + +# Background +On_Black='\033[40m' # Black +On_Red='\033[41m' # Red +On_Green='\033[42m' # Green +On_Yellow='\033[43m' # Yellow +On_Blue='\033[44m' # Blue +On_Purple='\033[45m' # Purple +On_Cyan='\033[46m' # Cyan +On_White='\033[47m' # White + +# High Intensity +IBlack='\033[0;90m' # Black +IRed='\033[0;91m' # Red +IGreen='\033[0;92m' # Green +IYellow='\033[0;93m' # Yellow +IBlue='\033[0;94m' # Blue +IPurple='\033[0;95m' # Purple +ICyan='\033[0;96m' # Cyan +IWhite='\033[0;97m' # White + +# Bold High Intensity +BIBlack='\033[1;90m' # Black +BIRed='\033[1;91m' # Red +BIGreen='\033[1;92m' # Green +BIYellow='\033[1;93m' # Yellow +BIBlue='\033[1;94m' # Blue +BIPurple='\033[1;95m' # Purple +BICyan='\033[1;96m' # Cyan +BIWhite='\033[1;97m' # White + +# High Intensity backgrounds +On_IBlack='\033[0;100m' # Black +On_IRed='\033[0;101m' # Red +On_IGreen='\033[0;102m' # Green +On_IYellow='\033[0;103m' # Yellow +On_IBlue='\033[0;104m' # Blue +On_IPurple='\033[0;105m' # Purple +On_ICyan='\033[0;106m' # Cyan +On_IWhite='\033[0;107m' # White diff --git a/api_auth_docker/tests/test-gatekeeper.sh b/api_auth_docker/tests/test-gatekeeper.sh new file mode 100755 index 0000000..744b08d --- /dev/null +++ b/api_auth_docker/tests/test-gatekeeper.sh @@ -0,0 +1,612 @@ +#!/bin/bash + +. ./colors.sh + +# We just want to test the authentication/authorization, not the actual called function +# You need jq installed for these tests to run correctly + +# This will test this structure of access (api.properties): + +# # Watcher can do stuff +# # Spender can do what the watcher can do plus more stuff +# # Admin can do what the spender can do plus even more stuff + +# # Stats can: +# action_helloworld=stats +# action_getblockchaininfo=stats +# action_installation_info=stats +# action_getmempoolinfo=stats +# action_getblockhash=stats +# +# # Watcher can do what the stats can do, plus: +# action_watch=watcher +# action_unwatch=watcher +# action_watchxpub=watcher +# action_unwatchxpubbyxpub=watcher +# action_unwatchxpubbylabel=watcher +# action_getactivewatchesbyxpub=watcher +# action_getactivewatchesbylabel=watcher +# action_getactivexpubwatches=watcher +# action_get_txns_by_watchlabel=watcher +# action_get_unused_addresses_by_watchlabel=watcher +# action_watchtxid=watcher +# action_unwatchtxid=watcher +# action_getactivewatches=watcher +# action_getbestblockhash=watcher +# action_getbestblockinfo=watcher +# action_getblockinfo=watcher +# action_gettransaction=watcher +# action_ots_verify=watcher +# action_ots_info=watcher +# action_ln_getinfo=watcher +# action_ln_create_invoice=watcher +# action_ln_getconnectionstring=watcher +# action_ln_decodebolt11=watcher +# action_ln_listpeers=watcher +# action_ln_getroute=watcher +# action_ln_listpays=watcher +# action_ln_paystatus=watcher +# action_bitcoin_estimatesmartfee=watcher +# +# # Spender can do what the watcher can do, plus: +# action_get_txns_spending=spender +# action_getbalance=spender +# action_getbalances=spender +# action_getbalancebyxpub=spender +# action_getbalancebyxpublabel=spender +# action_getnewaddress=spender +# action_spend=spender +# action_bumpfee=spender +# action_addtobatch=spender +# action_batchspend=spender +# action_deriveindex=spender +# action_derivepubpath=spender +# action_deriveindex_bitcoind=spender +# action_derivepubpath_bitcoind=spender +# action_ln_pay=spender +# action_ln_newaddr=spender +# action_ots_stamp=spender +# action_ots_getfile=spender +# action_ln_getinvoice=spender +# action_ln_delinvoice=spender +# action_ln_connectfund=spender +# action_ln_listfunds=spender +# action_ln_withdraw=spender +# action_createbatcher=spender +# action_updatebatcher=spender +# action_removefrombatch=spender +# action_listbatchers=spender +# action_getbatcher=spender +# action_getbatchdetails=spender +# +# # Admin can do what the spender can do, plus: +# +# +# # Should be called from inside the Docker network only: +# action_conf=internal +# action_newblock=internal +# action_executecallbacks=internal +# action_ots_backoffice=internal +# +# + +trace() { + if [ "${1}" -le "${TRACING}" ]; then + echo -en "$(date -u +%FT%TZ) ${2}" 1>&2 + fi +} + +trace_following() { + if [ "${1}" -le "${TRACING}" ]; then + echo -en "${2}" 1>&2 + fi +} + +start_test_container() { + trace 1 "[stop_test_container] ${BCyan}Starting test container...${Color_Off}\n" + + docker run -d --rm -t --name tests-gatekeeper --network=cyphernodenet alpine + + sleep 2 +} + +stop_test_container() { + trace 1 "[stop_test_container] ${BCyan}Stopping existing containers if they are running...${Color_Off}\n" + + local containers=$(docker ps -q -f "name=tests-gatekeeper") + if [ -n "${containers}" ]; then + docker stop ${containers} + fi +} + +exec_in_test_container() { + local response + local returncode + response=$(docker exec -it tests-gatekeeper "$@") + returncode=${?} + echo -n "${response}" | tr -d '\r\n' + return ${returncode} +} + +exec_in_test_container_leave_lf() { + local response + local returncode + response=$(docker exec -it tests-gatekeeper "$@") + returncode=${?} + echo -n "${response}" + return ${returncode} +} + +test_auth() { + local fn=${1} + local token=${2} + local has_access=${3} + local httperrorcode=${4} + local returncode + local httpcode + + trace 2 "[test_auth] ${BCyan}action=${fn}...${Color_Off}" + httpcode=$(exec_in_test_container curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" --cacert /cert.pem https://gatekeeper:2009/v0/${fn}) + returncode=${?} + + if ${has_access}; then + trace_following 2 " has access... " + else + trace_following 2 " has NOT access... " + fi + + if [ "${returncode}" -ne "0" ] || ${has_access} && [ "${httpcode}" -eq "${httperrorcode}" ] || ! ${has_access} && [ "${httpcode}" -ne "${httperrorcode}" ]; then + trace_following 1 "${On_Red}${BBlack} curl code=${returncode}, HTTP code=${httpcode}!${Color_Off}\n" + return 10 + else + trace_following 2 "${On_IGreen}${BBlack} OK ${Color_Off}\n" + fi +} + +test_authorization() { + test_auth ${1} ${2} ${3} 403 + return $? +} + +test_authentication() { + test_auth ${1} ${2} ${3} 401 + return $? +} + +generate_token() { + local id=${1} + local expired=${2:-false} + local key + local groups + + key=$(exec_in_test_container sh -c 'source /keys.properties ; echo $ukey_'${id}) + groups=$(exec_in_test_container sh -c 'source /keys.properties ; echo $ugroups_'${id}) + trace 3 "[generate_token] id=${id}\n" + trace 3 "[generate_token] key=${key}\n" + trace 3 "[generate_token] groups=${groups}\n" + + local h64broken=$(exec_in_test_container sh -c "echo -n '{\"alg\":\"HS256\",\"typ\":\"JWT\"}' | base64") + trace 3 "[generate_token] h64broken=${h64broken}\n" + local h64=$(exec_in_test_container sh -c "echo -n '{\"alg\":\"HS256\",\"typ\":\"JWT\"}' | basenc --base64url | tr -d '='") + trace 3 "[generate_token] h64=${h64}\n" + local d=$(exec_in_test_container date +"%s") + if ! ${expired}; then + d=$((d+100000)) + fi + trace 3 "[generate_token] d=${d}\n" + local p64=$(exec_in_test_container sh -c "echo -n '{\"id\":\"${id}\",\"exp\":${d}}' | basenc --base64url | tr -d '='") + trace 3 "[generate_token] p64=${p64}\n" + # local s=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r | cut -sd ' ' -f1) + local sig=$(exec_in_test_container sh -c "echo -n \"${h64}.${p64}\" | openssl dgst -hmac \"${key}\" -sha256 -r -binary | basenc --base64url | tr -d '='") + trace 3 "[generate_token] sig=${sig}\n" + local token="${h64}.${p64}.${sig}" + trace 3 "[generate_token] token=${token}\n\n" + + trace 1 "[test_gatekeeper] ${BCyan}Current user ${id} with groups ${groups}${Color_Off}\n" + + echo -n "${token}" +} + +generate_broken_token() { + local id=${1} + local key + local groups + + key=$(exec_in_test_container sh -c 'source /keys.properties ; echo $ukey_'${id}) + groups=$(exec_in_test_container sh -c 'source /keys.properties ; echo $ugroups_'${id}) + trace 3 "[generate_token] id=${id}\n" + trace 3 "[generate_token] key=${key}\n" + trace 3 "[generate_token] groups=${groups}\n" + + local h64broken=$(exec_in_test_container sh -c "echo -n '{\"alg\":\"HS256\",\"typ\":\"JWT\"}' | base64") + trace 3 "[generate_token] h64broken=${h64broken}\n" + local d=$(exec_in_test_container date +"%s") + trace 3 "[generate_token] d=${d}\n" + local p64broken=$(exec_in_test_container sh -c "echo -n '{\"id\":\"${id}\",\"exp\":$((d+100000))}' | base64") + trace 3 "[generate_token] p64broken=${p64broken}\n" + local sigbroken=$(exec_in_test_container sh -c "echo -n \"${h64}.${p64}\" | openssl dgst -hmac \"${key}\" -sha256 -r | cut -sd ' ' -f1") + trace 3 "[generate_token] sigbroken=${sigbroken}\n" + local token="${h64broken}.${p64broken}.${sigbroken}" + trace 3 "[generate_token] token=${token}\n\n" + + trace 1 "[test_gatekeeper] ${BCyan}Current user ${id} with groups ${groups}${Color_Off}\n" + + echo -n "${token}" +} + +test_functions_with_broken_token() { + trace 1 "\n\n[test_functions_with_broken_token] ${BCyan}Let's test functions with broken token...${Color_Off}\n\n" + + local id=${1} + local token=$(generate_broken_token ${id}) + local has_access=${2} + + # Stats can: + # action_helloworld=stats + test_authorization "helloworld" "${token}" ${has_access} || return 10 + + # action_getblockchaininfo=stats + test_authorization "getblockchaininfo" "${token}" ${has_access} || return 20 + + # action_installation_info=stats + test_authorization "installation_info" "${token}" ${has_access} || return 30 + + # action_getmempoolinfo=stats + test_authorization "getmempoolinfo" "${token}" ${has_access} || return 40 + + # action_getblockhash=stats + test_authorization "getblockhash" "${token}" ${has_access} || return 50 + + trace 1 "\n\n[test_functions_with_broken_token] ${On_IGreen}${BBlack} SUCCESS with user ${id}! ${Color_Off}\n" +} + +test_functions_with_wrong_token() { + trace 1 "\n\n[test_functions_with_wrong_token] ${BCyan}Let's test functions with wrong token (we will receive HTTP 401 Unauthorized here)...${Color_Off}\n\n" + + local id=${1} + local token=aaa$(generate_token ${id})aaa + local has_access=false + + # Stats can: + # action_helloworld=stats + test_authentication "helloworld" "${token}" ${has_access} || return 10 + + # action_getblockchaininfo=stats + test_authentication "getblockchaininfo" "${token}" ${has_access} || return 20 + + # action_installation_info=stats + test_authentication "installation_info" "${token}" ${has_access} || return 30 + + # action_getmempoolinfo=stats + test_authentication "getmempoolinfo" "${token}" ${has_access} || return 40 + + # action_getblockhash=stats + test_authentication "getblockhash" "${token}" ${has_access} || return 50 + + trace 1 "\n\n[test_functions_with_wrong_token] ${On_IGreen}${BBlack} SUCCESS with user ${id}! ${Color_Off}\n" +} + +test_stats_functions() { + trace 1 "\n\n[test_gatekeeper] ${BCyan}Let's test stats functions...${Color_Off}\n\n" + + local id=${1} + local token=$(generate_token ${id}) + local has_access=${2} + + # Stats can: + # action_helloworld=stats + test_authorization "helloworld" "${token}" ${has_access} || return 10 + + # action_getblockchaininfo=stats + test_authorization "getblockchaininfo" "${token}" ${has_access} || return 20 + + # action_installation_info=stats + test_authorization "installation_info" "${token}" ${has_access} || return 30 + + # action_getmempoolinfo=stats + test_authorization "getmempoolinfo" "${token}" ${has_access} || return 40 + + # action_getblockhash=stats + test_authorization "getblockhash" "${token}" ${has_access} || return 50 + + trace 1 "\n\n[test_stats_functions] ${On_IGreen}${BBlack} SUCCESS with user ${id}! ${Color_Off}\n" +} + +test_watcher_functions() { + trace 1 "\n\n[test_watcher_functions] ${BCyan}Let's test watcher functions...${Color_Off}\n\n" + + local id=${1} + local token=$(generate_token ${id}) + local has_access=${2} + + # Watcher can: + # action_watch=watcher + test_authorization "watch" "${token}" ${has_access} || return 10 + + # action_unwatch=watcher + test_authorization "unwatch" "${token}" ${has_access} || return 20 + + # action_watchxpub=watcher + test_authorization "watchxpub" "${token}" ${has_access} || return 30 + + # action_unwatchxpubbyxpub=watcher + test_authorization "unwatchxpubbyxpub" "${token}" ${has_access} || return 40 + + # action_unwatchxpubbylabel=watcher + test_authorization "unwatchxpubbylabel" "${token}" ${has_access} || return 50 + + # action_getactivewatchesbyxpub=watcher + test_authorization "getactivewatchesbyxpub" "${token}" ${has_access} || return 60 + + # action_getactivewatchesbylabel=watcher + test_authorization "getactivewatchesbylabel" "${token}" ${has_access} || return 70 + + # action_getactivexpubwatches=watcher + test_authorization "getactivexpubwatches" "${token}" ${has_access} || return 80 + + # action_get_txns_by_watchlabel=watcher + test_authorization "get_txns_by_watchlabel" "${token}" ${has_access} || return 90 + + # action_get_unused_addresses_by_watchlabel=watcher + test_authorization "get_unused_addresses_by_watchlabel" "${token}" ${has_access} || return 100 + + # action_watchtxid=watcher + test_authorization "watchtxid" "${token}" ${has_access} || return 110 + + # action_unwatchtxid=watcher + test_authorization "unwatchtxid" "${token}" ${has_access} || return 120 + + # action_getactivewatches=watcher + test_authorization "getactivewatches" "${token}" ${has_access} || return 130 + + # action_getbestblockhash=watcher + test_authorization "getbestblockhash" "${token}" ${has_access} || return 140 + + # action_getbestblockinfo=watcher + test_authorization "getbestblockinfo" "${token}" ${has_access} || return 150 + + # action_getblockinfo=watcher + test_authorization "getblockinfo" "${token}" ${has_access} || return 160 + + # action_gettransaction=watcher + test_authorization "gettransaction" "${token}" ${has_access} || return 170 + + # action_ots_verify=watcher + test_authorization "ots_verify" "${token}" ${has_access} || return 180 + + # action_ots_info=watcher + test_authorization "ots_info" "${token}" ${has_access} || return 190 + + # action_ln_getinfo=watcher + test_authorization "ln_getinfo" "${token}" ${has_access} || return 200 + + # action_ln_create_invoice=watcher + test_authorization "ln_create_invoice" "${token}" ${has_access} || return 210 + + # action_ln_getconnectionstring=watcher + test_authorization "ln_getconnectionstring" "${token}" ${has_access} || return 220 + + # action_ln_decodebolt11=watcher + test_authorization "ln_decodebolt11" "${token}" ${has_access} || return 230 + + # action_ln_listpeers=watcher + test_authorization "ln_listpeers" "${token}" ${has_access} || return 240 + + # action_ln_getroute=watcher + test_authorization "ln_getroute" "${token}" ${has_access} || return 250 + + # action_ln_listpays=watcher + test_authorization "ln_listpays" "${token}" ${has_access} || return 260 + + # action_ln_paystatus=watcher + test_authorization "ln_paystatus" "${token}" ${has_access} || return 270 + + # action_bitcoin_estimatesmartfee=watcher + test_authorization "bitcoin_estimatesmartfee" "${token}" ${has_access} || return 280 + + trace 1 "\n\n[test_watcher_functions] ${On_IGreen}${BBlack} SUCCESS with user ${id}! ${Color_Off}\n" +} + +test_spender_functions() { + trace 1 "\n\n[test_spender_functions] ${BCyan}Let's test spender functions...${Color_Off}\n" + + local id=${1} + local token=$(generate_token ${id}) + local has_access=${2} + + # Spender can do what the watcher can do, plus: + # action_get_txns_spending=spender + test_authorization "get_txns_spending" "${token}" ${has_access} || return 10 + + # action_getbalance=spender + test_authorization "getbalance" "${token}" ${has_access} || return 10 + + # action_getbalances=spender + test_authorization "getbalances" "${token}" ${has_access} || return 10 + + # action_getbalancebyxpub=spender + test_authorization "getbalancebyxpub" "${token}" ${has_access} || return 10 + + # action_getbalancebyxpublabel=spender + test_authorization "getbalancebyxpublabel" "${token}" ${has_access} || return 10 + + # action_getnewaddress=spender + test_authorization "getnewaddress" "${token}" ${has_access} || return 10 + + # action_spend=spender + test_authorization "spend" "${token}" ${has_access} || return 10 + + # action_bumpfee=spender + test_authorization "bumpfee" "${token}" ${has_access} || return 10 + + # action_addtobatch=spender + test_authorization "addtobatch" "${token}" ${has_access} || return 10 + + # action_batchspend=spender + test_authorization "batchspend" "${token}" ${has_access} || return 10 + + # action_deriveindex=spender + test_authorization "deriveindex" "${token}" ${has_access} || return 10 + + # action_derivepubpath=spender + test_authorization "derivepubpath" "${token}" ${has_access} || return 10 + + # action_deriveindex_bitcoind=spender + test_authorization "deriveindex_bitcoind" "${token}" ${has_access} || return 10 + + # action_derivepubpath_bitcoind=spender + test_authorization "derivepubpath_bitcoind" "${token}" ${has_access} || return 10 + + # action_ln_pay=spender + test_authorization "ln_pay" "${token}" ${has_access} || return 10 + + # action_ln_newaddr=spender + test_authorization "ln_newaddr" "${token}" ${has_access} || return 10 + + # action_ots_stamp=spender + test_authorization "ots_stamp" "${token}" ${has_access} || return 10 + + # action_ots_getfile=spender + test_authorization "ots_getfile" "${token}" ${has_access} || return 10 + + # action_ln_getinvoice=spender + test_authorization "ln_getinvoice" "${token}" ${has_access} || return 10 + + # action_ln_delinvoice=spender + test_authorization "ln_delinvoice" "${token}" ${has_access} || return 10 + + # action_ln_connectfund=spender + test_authorization "ln_connectfund" "${token}" ${has_access} || return 10 + + # action_ln_listfunds=spender + test_authorization "ln_listfunds" "${token}" ${has_access} || return 10 + + # action_ln_withdraw=spender + test_authorization "ln_withdraw" "${token}" ${has_access} || return 10 + + # action_createbatcher=spender + test_authorization "createbatcher" "${token}" ${has_access} || return 10 + + # action_updatebatcher=spender + test_authorization "updatebatcher" "${token}" ${has_access} || return 10 + + # action_removefrombatch=spender + test_authorization "removefrombatch" "${token}" ${has_access} || return 10 + + # action_listbatchers=spender + test_authorization "listbatchers" "${token}" ${has_access} || return 10 + + # action_getbatcher=spender + test_authorization "getbatcher" "${token}" ${has_access} || return 10 + + # action_getbatchdetails=spender + test_authorization "getbatchdetails" "${token}" ${has_access} || return 10 + + trace 1 "\n\n[test_spender_functions] ${On_IGreen}${BBlack} SUCCESS with user ${id}! ${Color_Off}\n" +} + +test_admin_functions() { + trace 1 "\n\n[test_admin_functions] ${BCyan}Let's test admin functions...${Color_Off}\n" + + # Admin can do what the spender can do, plus: + trace 1 "\n\n[test_admin_functions] ${On_IGreen}${BBlack} SUCCESS with user ${id}! ${Color_Off}\n" +} + +test_internal_functions() { + trace 1 "\n\n[test_internal_functions] ${BCyan}Let's test internal functions...${Color_Off}\n" + + local id=${1} + local token=$(generate_token ${id}) + local has_access=${2} + + # Should be called from inside the Docker network only: + # action_conf=internal + test_authorization "conf" "${token}" ${has_access} || return 10 + + # action_newblock=internal + test_authorization "newblock" "${token}" ${has_access} || return 10 + + # action_executecallbacks=internal + test_authorization "executecallbacks" "${token}" ${has_access} || return 10 + + # action_ots_backoffice=internal + test_authorization "ots_backoffice" "${token}" ${has_access} || return 10 + + trace 1 "\n\n[test_internal_functions] ${On_IGreen}${BBlack} SUCCESS with user ${id}! ${Color_Off}\n" +} + +test_expired() { + trace 1 "\n\n[test_expired] ${BCyan}Let's test calling a function with an expired token (we will receive HTTP 403 Forbidden here)...${Color_Off}\n\n" + + local id=${1} + local token=$(generate_token ${id} true) + local has_access=false + + # Stats can: + # action_helloworld=stats + test_authorization "helloworld" "${token}" ${has_access} || return 10 + + trace 1 "\n\n[test_expired] ${On_IGreen}${BBlack} SUCCESS with user ${id}! ${Color_Off}\n" +} + +TRACING=3 + +stop_test_container +start_test_container + +trace 1 "\n\n[test_gatekeeper] ${BCyan}Installing needed packages...${Color_Off}\n" +exec_in_test_container_leave_lf apk add --update curl coreutils openssl + +# Copy keys to test container +trace 1 "\n\n[test_gatekeeper] ${BCyan}Copying keys and certs to test container...${Color_Off}\n" +gatekeeperid=$(docker ps -q -f "name=cyphernode_gatekeeper") +testid=$(docker ps -q -f "name=tests-gatekeeper") +docker cp ${gatekeeperid}:/etc/nginx/conf.d/keys.properties - | docker cp - ${testid}:/ +docker cp ${gatekeeperid}:/etc/ssl/certs/cert.pem - | docker cp - ${testid}:/ + +# Test with an expired token +# Test functions with broken legacy token +# Test functions with wrong token +# Stats functions with a stats +# Stats functions with a watcher +# Stats functions with a spender +# Stats functions with a admin +# Watcher functions with a stats +# Watcher functions with a watcher +# Watcher functions with a spender +# Watcher functions with a admin +# Spending functions with a stats +# Spending functions with a watcher +# Spending functions with a spender +# Spending functions with a admin +# Internal functions with a stats +# Internal functions with a watcher +# Internal functions with a spender +# Internal functions with a admin +test_expired 003 \ +&& test_functions_with_broken_token 003 true \ +&& test_functions_with_wrong_token 003 true \ +&& test_stats_functions 000 true \ +&& test_stats_functions 001 true \ +&& test_stats_functions 002 true \ +&& test_stats_functions 003 true \ +&& test_watcher_functions 000 false \ +&& test_watcher_functions 001 true \ +&& test_watcher_functions 002 true \ +&& test_watcher_functions 003 true \ +&& test_spender_functions 000 false \ +&& test_spender_functions 001 false \ +&& test_spender_functions 002 true \ +&& test_spender_functions 003 true \ +&& test_internal_functions 000 false \ +&& test_internal_functions 001 false \ +&& test_internal_functions 002 false \ +&& test_internal_functions 003 false \ +|| trace 1 "\n\n[test_gatekeeper] ${On_Red}${BBlack} test_watcher_functions error: ${?} ${Color_Off}\n" + +trace 1 "\n\n[test_gatekeeper] ${BCyan}Tearing down...${Color_Off}\n" +wait + +stop_test_container + +trace 1 "\n\n[test_gatekeeper] ${BCyan}See ya!${Color_Off}\n" diff --git a/clients/javascript/cyphernode-client.js b/clients/javascript/cyphernode-client.js index afc1eaa..c36cc1a 100644 --- a/clients/javascript/cyphernode-client.js +++ b/clients/javascript/cyphernode-client.js @@ -15,10 +15,22 @@ CyphernodeClient.prototype._generateToken = function() { let current = Math.round(new Date().getTime()/1000) + 10 let p = '{"id":"' + this.api_id + '","exp":' + current + '}' // console.log("p=" + p) - let p64 = Buffer.from(p).toString('base64') + const re1 = /\+/g; + const re2 = /\//g; + const p64 = Buffer.from(p) + .toString("base64") + .replace(re1, "-") + .replace(re2, "_") + .split("=")[0]; let msg = this.h64 + '.' + p64 // console.log("msg=" + msg) - let s = CryptoJS.HmacSHA256(msg, this.api_key).toString() + const s = crypto + .createHmac("sha256", this.apiKey) + .update(msg) + .digest("base64") + .replace(re1, "-") + .replace(re2, "_") + .split("=")[0]; // let s2 = createHmac('sha256', this.api_key).update(msg).digest('hex') // let s3 = crypto.createHmac('sha256', this.api_key).update(msg).digest('hex'); // console.log("s=" + s) diff --git a/clients/shell/cyphernode-client.sh b/clients/shell/cyphernode-client.sh index 7504c76..237c1f7 100644 --- a/clients/shell/cyphernode-client.sh +++ b/clients/shell/cyphernode-client.sh @@ -7,7 +7,7 @@ invoke_cyphernode() local action=${1} local post=${2} - local p64=$(echo -n "{\"id\":\"${id}\",\"exp\":$((`date +"%s"`+10))}" | base64) + local p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=') local s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$key" -sha256 -r | cut -sd ' ' -f1) local token="$h64.$p64.$s" diff --git a/cyphernodeconf_docker/templates/gatekeeper/api.properties b/cyphernodeconf_docker/templates/gatekeeper/api.properties index 2a50779..0b0e275 100644 --- a/cyphernodeconf_docker/templates/gatekeeper/api.properties +++ b/cyphernodeconf_docker/templates/gatekeeper/api.properties @@ -10,7 +10,7 @@ action_installation_info=stats action_getmempoolinfo=stats action_getblockhash=stats -# Watcher can: +# Watcher can do what the stats can do, plus: action_watch=watcher action_unwatch=watcher action_watchxpub=watcher @@ -61,7 +61,6 @@ action_ots_stamp=spender action_ots_getfile=spender action_ln_getinvoice=spender action_ln_delinvoice=spender -action_ln_decodebolt11=spender action_ln_connectfund=spender action_ln_listfunds=spender action_ln_withdraw=spender diff --git a/cyphernodeconf_docker/templates/installer/testfeatures.sh b/cyphernodeconf_docker/templates/installer/testfeatures.sh index 65acf02..8b1140b 100644 --- a/cyphernodeconf_docker/templates/installer/testfeatures.sh +++ b/cyphernodeconf_docker/templates/installer/testfeatures.sh @@ -1,6 +1,6 @@ #!/bin/sh -apk add --update --no-cache openssl curl jq > /dev/null +apk add --update --no-cache openssl curl jq coreutils > /dev/null . /gatekeeper/keys.properties @@ -12,24 +12,21 @@ checkgatekeeper() { local k eval k='$ukey_'$id - local h64=$(echo "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64) + local h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=') # Let's test expiration: 1 second in payload, request 2 seconds later - local p64=$(echo "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+1))}" | base64) + local p64=$(echo -n '{"id":"'${id}'","exp":'$(date +"%s")'}' | basenc --base64url | tr -d '=') local s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1) local token="$h64.$p64.$s" - echo -e " Sleeping 2 seconds... " > /dev/console - sleep 2 - echo " Testing expired request... " > /dev/console rc=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $token" --cacert /gatekeeper/certs/cert.pem https://gatekeeper:<%= gatekeeper_port %>/v0/getblockinfo) [ "${rc}" -ne "403" ] && return 10 # Let's test authentication (signature) - p64=$(echo "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64) + p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=') s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1) token="$h64.$p64.a$s" @@ -47,7 +44,7 @@ checkgatekeeper() { id="002" eval k='$ukey_'$id - p64=$(echo "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64) + p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=') s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1) token="$h64.$p64.$s" @@ -58,7 +55,7 @@ checkgatekeeper() { id="003" eval k='$ukey_'$id - p64=$(echo "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64) + p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=') s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1) token="$h64.$p64.$s" diff --git a/doc/INSTALL-MANUAL-STEPS.md b/doc/INSTALL-MANUAL-STEPS.md index 5f00e36..761b6e1 100644 --- a/doc/INSTALL-MANUAL-STEPS.md +++ b/doc/INSTALL-MANUAL-STEPS.md @@ -142,15 +142,15 @@ sudo find ~/btcdata -type d -exec chmod 2775 {} \; ; sudo find ~/btcdata -type f ## Test the deployment ```shell -id="001";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="2df1eeea370eacdc5cf7e96c2d82140d1568079a5d4d87006ec8718a98883b36";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Authorization: Bearer $token" -k https://127.0.0.1:2009/v0/getbestblockhash -id="003";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Authorization: Bearer $token" -k https://127.0.0.1:2009/v0/getbalance -id="003";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Content-Type: application/json" -d '{"hash":"123","callbackUrl":"http://callback"}' -H "Authorization: Bearer $token" -k https://127.0.0.1:2009/v0/ots_stamp +id="001";key="2df1eeea370eacdc5cf7e96c2d82140d1568079a5d4d87006ec8718a98883b36";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/getbestblockhash +id="003";key="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/getbalance +id="003";key="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/ots_stamp ``` If you need the authorization header to copy/paste in another tool: ```shell -id="003";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+30))}" | base64);k="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";echo "Bearer $token" +id="003";key="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";echo "Bearer $token" ``` ```shell diff --git a/doc/INSTALL-MANUALLY.md b/doc/INSTALL-MANUALLY.md index ac62da7..4e3e426 100644 --- a/doc/INSTALL-MANUALLY.md +++ b/doc/INSTALL-MANUALLY.md @@ -124,15 +124,15 @@ pi@SP-BTC01:~ $ docker network connect cyphernodenet btcnode ## Test deployment from outside of the Swarm ```shell -id="001";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="2df1eeea370eacdc5cf7e96c2d82140d1568079a5d4d87006ec8718a98883b36";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Authorization: Bearer $token" -k https://127.0.0.1:2009/v0/getbestblockhash -id="003";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Authorization: Bearer $token" -k https://127.0.0.1:2009/v0/getbalance -id="003";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Content-Type: application/json" -d '{"hash":"123","callbackUrl":"http://callback"}' -H "Authorization: Bearer $token" -k https://127.0.0.1:2009/v0/ots_stamp +id="001";key="2df1eeea370eacdc5cf7e96c2d82140d1568079a5d4d87006ec8718a98883b36";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/getbestblockhash +id="003";key="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/getbalance +id="003";key="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/ots_stamp ``` If you need the authorization header to copy/paste in another tool: ```shell -id="003";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+60))}" | base64);k="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";echo "Bearer $token" +id="003";key="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";echo "Bearer $token" ``` ## Test deployment from any host of the swarm diff --git a/doc/INSTALL.md b/doc/INSTALL.md index 6e4bf8e..be644f3 100644 --- a/doc/INSTALL.md +++ b/doc/INSTALL.md @@ -53,15 +53,15 @@ proxy_docker/app/data/sqlmigrate* If you need the authorization header to copy/paste in another tool, put your API ID (id=) and API key (k=) in the following command: ```shell -id="003";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+60))}" | base64);k="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";echo "Bearer $token" +id="003";key="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";echo "Bearer $token" ``` Directly using curl on command line, put your API ID (id=) and API key (k=) in the following commands: ```shell -id="001";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="2df1eeea370eacdc5cf7e96c2d82140d1568079a5d4d87006ec8718a98883b36";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Authorization: Bearer $token" -k https://127.0.0.1:2009/v0/getbestblockhash -id="003";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Authorization: Bearer $token" -k https://127.0.0.1:2009/v0/getbalance -id="003";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Content-Type: application/json" -d '{"hash":"123","callbackUrl":"http://callback"}' -H "Authorization: Bearer $token" -k https://127.0.0.1:2009/v0/ots_stamp +id="001";key="2df1eeea370eacdc5cf7e96c2d82140d1568079a5d4d87006ec8718a98883b36";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/getbestblockhash +id="003";key="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/getbalance +id="003";key="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/ots_stamp ``` ## Manually test your installation directly on the Proxy: diff --git a/doc/README.md b/doc/README.md index 0b5293e..c14431d 100644 --- a/doc/README.md +++ b/doc/README.md @@ -85,9 +85,9 @@ id="003";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(ech Directly using curl on command line, put your API ID (id=) and API key (k=) in the following commands: ```shell -id="001";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="2df1eeea370eacdc5cf7e96c2d82140d1568079a5d4d87006ec8718a98883b36";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Authorization: Bearer $token" -k https://127.0.0.1:2009/v0/getbestblockhash -id="003";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Authorization: Bearer $token" -k https://127.0.0.1:2009/v0/getbalance -id="003";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Content-Type: application/json" -d '{"hash":"123","callbackUrl":"http://callback"}' -H "Authorization: Bearer $token" -k https://127.0.0.1:2009/v0/ots_stamp +id="001";key="2df1eeea370eacdc5cf7e96c2d82140d1568079a5d4d87006ec8718a98883b36";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/getbestblockhash +id="003";key="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/getbalance +id="003";key="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";h64=$(echo -n '{"alg":"HS256","typ":"JWT"}' | basenc --base64url | tr -d '=');p64=$(echo -n '{"id":"'${id}'","exp":'$((`date +"%s"`+10))'}' | basenc --base64url | tr -d '=');sig=$(echo -n "${h64}.${p64}" | openssl dgst -hmac "${key}" -sha256 -r -binary | basenc --base64url | tr -d '=');token="${h64}.${p64}.${sig}";curl -v -H "Authorization: Bearer ${token}" -k https://localhost:2009/v0/ots_stamp ```