mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-22 08:25:21 +08:00
fix(auth): reject malformed credential payloads before authentication
This commit is contained in:
@@ -111,7 +111,11 @@ class UserRouterGroup(group.RouterGroup):
|
||||
async def _() -> str:
|
||||
if getattr(getattr(self.ap, 'deployment', None), 'mode', 'oss') == 'cloud':
|
||||
return self.http_status(403, 'password_login_disabled', 'Password login is disabled on LangBot Cloud')
|
||||
json_data = await quart.request.json
|
||||
json_data = await quart.request.get_json(silent=True)
|
||||
if not isinstance(json_data, dict) or not all(
|
||||
isinstance(json_data.get(field), str) for field in ('user', 'password')
|
||||
):
|
||||
return self.http_status(400, -1, 'Invalid request parameters')
|
||||
|
||||
user_email = json_data['user']
|
||||
password = json_data['password']
|
||||
|
||||
@@ -241,33 +241,42 @@ class TestInvalidPayload:
|
||||
"""Tests for error handling with invalid payloads."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_missing_json_body(self, quart_test_client):
|
||||
"""
|
||||
POST endpoint without JSON body handles gracefully.
|
||||
"""
|
||||
# /api/v1/user/auth expects JSON with 'user' and 'password'
|
||||
async def test_missing_json_body(self, quart_test_client, fake_api_app):
|
||||
"""A missing login body is rejected before authentication."""
|
||||
response = await quart_test_client.post('/api/v1/user/auth')
|
||||
|
||||
# Should return error (500, 400, or 401) with stable JSON structure
|
||||
assert response.status_code in (400, 500, 401)
|
||||
data = await response.get_json()
|
||||
|
||||
# Verify error response has expected structure
|
||||
assert 'code' in data
|
||||
assert 'msg' in data
|
||||
assert response.status_code == 400
|
||||
assert await response.get_json() == {'code': -1, 'msg': 'Invalid request parameters'}
|
||||
fake_api_app.user_service.authenticate.assert_not_awaited()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_invalid_json_structure(self, quart_test_client):
|
||||
"""
|
||||
POST with wrong JSON structure returns stable error.
|
||||
"""
|
||||
response = await quart_test_client.post('/api/v1/user/auth', json={'wrong_field': 'value'})
|
||||
@pytest.mark.parametrize(
|
||||
'payload',
|
||||
[
|
||||
{'wrong_field': 'value'},
|
||||
[],
|
||||
{'user': None, 'password': 'secret'},
|
||||
{'user': '[email protected]', 'password': 42},
|
||||
],
|
||||
)
|
||||
async def test_invalid_json_structure(self, quart_test_client, fake_api_app, payload):
|
||||
"""Malformed credential fields never reach the authentication service."""
|
||||
response = await quart_test_client.post('/api/v1/user/auth', json=payload)
|
||||
|
||||
# Should return error with stable JSON structure
|
||||
assert response.status_code in (400, 500, 401)
|
||||
data = await response.get_json()
|
||||
assert 'code' in data
|
||||
assert 'msg' in data
|
||||
assert response.status_code == 400
|
||||
assert await response.get_json() == {'code': -1, 'msg': 'Invalid request parameters'}
|
||||
fake_api_app.user_service.authenticate.assert_not_awaited()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize('password', ['', 'existing-password'])
|
||||
async def test_string_credentials_reach_authentication(self, quart_test_client, fake_api_app, password):
|
||||
response = await quart_test_client.post(
|
||||
'/api/v1/user/auth', json={'user': '[email protected]', 'password': password}
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert (await response.get_json())['data']['token'] == 'fake_token'
|
||||
fake_api_app.user_service.authenticate.assert_awaited_once_with('[email protected]', password, None)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('mock_circular_import_chain')
|
||||
|
||||
Reference in New Issue
Block a user