Fix non-ASCII token authentication crashes
This commit is contained in:
+4
-2
@@ -199,7 +199,9 @@ def create_app(data_dir=None, provider_transport=None):
|
|||||||
return JSONResponse({'detail': 'Fremde Herkunft nicht erlaubt.'}, status_code=403)
|
return JSONResponse({'detail': 'Fremde Herkunft nicht erlaubt.'}, status_code=403)
|
||||||
if path == '/mcp' or path.startswith('/mcp/'):
|
if path == '/mcp' or path.startswith('/mcp/'):
|
||||||
supplied = request.headers.get('authorization', '')
|
supplied = request.headers.get('authorization', '')
|
||||||
if not secrets.compare_digest(supplied, 'Bearer ' + mcp_token):
|
# ASGI headers are decoded as Latin-1; compare their original bytes.
|
||||||
|
# compare_digest(str, str) rejects non-ASCII characters.
|
||||||
|
if not secrets.compare_digest(supplied.encode('latin-1'), ('Bearer ' + mcp_token).encode('utf-8')):
|
||||||
return JSONResponse({'detail': 'MCP-Token erforderlich.'}, status_code=401)
|
return JSONResponse({'detail': 'MCP-Token erforderlich.'}, status_code=401)
|
||||||
elif path.startswith('/api/') and path != '/api/login':
|
elif path.startswith('/api/') and path != '/api/login':
|
||||||
session = request.cookies.get('atelier_session', '')
|
session = request.cookies.get('atelier_session', '')
|
||||||
@@ -237,7 +239,7 @@ def create_app(data_dir=None, provider_transport=None):
|
|||||||
attempts[ip] = recent
|
attempts[ip] = recent
|
||||||
if len(recent) >= 10:
|
if len(recent) >= 10:
|
||||||
raise HTTPException(429, 'Zu viele Versuche. Bitte eine Minute warten.')
|
raise HTTPException(429, 'Zu viele Versuche. Bitte eine Minute warten.')
|
||||||
if not secrets.compare_digest(body.token, admin_token):
|
if not secrets.compare_digest(body.token.encode('utf-8'), admin_token.encode('utf-8')):
|
||||||
recent.append(stamp)
|
recent.append(stamp)
|
||||||
raise HTTPException(401, 'Zugangsschlüssel stimmt nicht.')
|
raise HTTPException(401, 'Zugangsschlüssel stimmt nicht.')
|
||||||
for key in list(sessions):
|
for key in list(sessions):
|
||||||
|
|||||||
@@ -181,3 +181,27 @@ def test_german_metadata_is_a_proposal_only(client):
|
|||||||
assert response.json()['title'] == 'Kundenanfrage höflich absagen'
|
assert response.json()['title'] == 'Kundenanfrage höflich absagen'
|
||||||
assert set(response.json()) == {'title','description','category','tags'}
|
assert set(response.json()) == {'title','description','category','tags'}
|
||||||
assert client.get('/api/prompts').json() == before
|
assert client.get('/api/prompts').json() == before
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('configured', ['ascii-test-token', 'synthetic-ü-token-🔐'])
|
||||||
|
def test_mcp_non_ascii_tokens_never_crash(tmp_path, monkeypatch, configured):
|
||||||
|
monkeypatch.setenv('MCP_TOKEN', configured)
|
||||||
|
with TestClient(create_app(tmp_path)) as c:
|
||||||
|
initialize={'jsonrpc':'2.0','id':1,'method':'initialize','params':{'protocolVersion':'2025-03-26','capabilities':{},'clientInfo':{'name':'regression','version':'1'}}}
|
||||||
|
accept={'Accept':'application/json, text/event-stream'}
|
||||||
|
for path in ['/mcp', '/mcp/']:
|
||||||
|
for wrong in [b'', b'Bearer wrong', 'Bearer falsch-ä'.encode('utf-8'), b'Bearer \xff']:
|
||||||
|
assert c.post(path,headers={**accept,'Authorization':wrong},json=initialize).status_code == 401
|
||||||
|
headers={**accept,'Authorization':('Bearer '+configured).encode('utf-8')}
|
||||||
|
response=c.post(path,headers=headers,json=initialize)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json()['result']['serverInfo']['name'] == 'CasaDePrompt'
|
||||||
|
listed=c.post(path,headers=headers,json={'jsonrpc':'2.0','id':2,'method':'tools/list','params':{}})
|
||||||
|
assert len(listed.json()['result']['tools']) == 4
|
||||||
|
|
||||||
|
|
||||||
|
def test_web_login_with_unicode_token(tmp_path, monkeypatch):
|
||||||
|
monkeypatch.setenv('ADMIN_TOKEN', 'synthetic-ä-admin-🔐')
|
||||||
|
with TestClient(create_app(tmp_path)) as c:
|
||||||
|
assert c.post('/api/login',json={'token':'falsch-ü'}).status_code == 401
|
||||||
|
assert c.post('/api/login',json={'token':'synthetic-ä-admin-🔐'}).status_code == 200
|
||||||
|
|||||||
Reference in New Issue
Block a user