-
Notifications
You must be signed in to change notification settings - Fork 154
Authentication failure in CLI client due to unencoded URL query parameters #2610
Description
Describe the bug
When using the Python CLI client, authentication fails with the error "Authentication failed, check API token" if any of the query parameters (such as the remote_user email address) contain special characters that alter their meaning in a URL query string (such as +).
The issue occurs because the script calculates the HMAC signature using the raw parameter values, but then appends these unencoded values directly to the URL:
url = base_url+path+'?'+('&'.join(flatten(data)))
When the requests library executes the HTTP call, characters like + in the unencoded query string are interpreted by the backend PHP server as a space ( ) during standard URL decoding. As a result, the server reconstructs the signature base string using the decoded values (e.g., with a space instead of a +), which results in a signature mismatch and rejected authentication.
To Reproduce
Steps to reproduce the behavior:
- Configure
filesender.pywith a username that contains special characters (for example,test+alias@example.com) and a valid API token. - Attempt to upload a file using the CLI client:
python3 filesender.py -r recipient@example.com file.txt - The server responds with HTTP 500 and the error:
"Authentication failed, check API token"(caused byauth_remote_signature_check_failedon the server-side).
Expected behavior
The Python client should URL-encode the query parameters when appending them to the URL, guaranteeing that the server decodes the exact same string that the client used for its HMAC calculation.
Proposed Solution
The issue can be resolved by correctly quoting the keys and values in the URL query string using urllib.parse.quote.
Here is a patch with the proposed fix:
--- a/scripts/client/filesender.py
+++ b/scripts/client/filesender.py
@@ -42,6 +42,7 @@ try:
import concurrent.futures
import hashlib
import urllib3
+ import urllib.parse
import os
import sys
import json
@@ -362,7 +363,12 @@ def call(method, path, data, content=None, rawContent=None, options={}, tryCount
bkey.extend(map(ord, apikey))
data['signature'] = hmac.new(bkey, signed, hashlib.sha1).hexdigest()
#print("signed: " + str(signed))
- url = base_url+path+'?'+('&'.join(flatten(data)))
+
+ flatdata_encoded = []
+ for item in flatten(data):
+ key, value = item.split('=', 1)
+ flatdata_encoded.append(urllib.parse.quote(key) + '=' + urllib.parse.quote(value))
+ url = base_url+path+'?'+('&'.join(flatdata_encoded))
headers = {
"Accept": "application/json",
"Content-Type": content_typeRegards