โ† eval5_submission_v1s

fastapi_14786

resolved RESOLVED PASS ยท 8 tool calls ยท 106 s ยท fastapi/fastapi

Task input

๐Ÿ› Strip whitespaces from `Authorization` header credentials

## Description

Fixes whitespace handling in authorization header parameter extraction to comply with [RFC 6750](https://datatracker.ietf.org/doc/html/rfc6750#section-2.1).

## Problem

The current implementation preserves leading/trailing whitespace in the extracted credential parameter. While RFC 6750 allows one or more spaces (`1*SP`) between "Bearer" and the token, the token definition (`b64token`) doesn't include whitespace characters, meaning spaces should be treated as separators only.

This causes the extracted credentials to include extraneous whitespace, which can lead to authentication failures.

## Solution

Added `.strip()` to the parameter extraction to remove leading and trailing whitespace:
```python
return scheme, param.strip()
```

## Reproduction

### Before the fix:
```python
from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer

app = FastAPI()
security = HTTPBearer()

@app.get("/users/me")
def read_current_user(
    credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)]
):
    return {"scheme": credentials.scheme, "credentials": credentials.credentials}
```

**Test case 1: Single space (correct)**
```bash
curl -X 'GET' \
  'http://127.0.0.1:8000/users/me' \
  -H 'Authorization: Bearer xxx'
```
Response: `{"scheme":"Bearer","credentials":"xxx"}` โœ“

**Test case 2: Multiple spaces**
```bash
curl -X 'GET' \
  'http://127.0.0.1:8000/users/me' \
  -H 'Authorization: Bearer   xxx'
```
Response: `{"scheme":"Bearer","credentials":"  xxx"}` โœ—

**Test case 3: Trailing whitespace**
```bash
curl -X 'GET' \
  'http://127.0.0.1:8000/users/me' \
  -H 'Authorization: Bearer xxx '
```
Response: `{"scheme":"Bearer","credentials":"xxx "}` โœ—

### After the fix:

All three test cases now return: `{"scheme":"Bearer","credentials":"xxx"}` โœ“

## Changes

- Modified `get_authorization_scheme_param()` in `fastapi/security/utils.py` to strip whitespace from the parameter
- Added test cases to verify the fix handles multiple spaces and trailing whitespace correctly

## Checklist

- [x] Tests added to cover the bug fix
- [x] Existing tests pass

Tool calls (9)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"get_authorization_scheme_param\" fastapi/security/utils.py"
}
{"status": "ok", "stdout": "4:def get_authorization_scheme_param(\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "4:def get_authorization_scheme_param(\n", "stderr": "", "exit_code": 0}
2read_file
{
 "filepath": "fastapi/security/utils.py"
}
{"status": "ok", "filepath": "fastapi/security/utils.py", "content": "from typing import Optional\n\n\ndef get_authorization_scheme_param(\n authorization_heade
full
{"status": "ok", "filepath": "fastapi/security/utils.py", "content": "from typing import Optional\n\n\ndef get_authorization_scheme_param(\n    authorization_header_value: Optional[str],\n) -> tuple[str, str]:\n    if not authorization_header_value:\n        return \"\", \"\"\n    scheme, _, param = authorization_header_value.partition(\" \")\n    return scheme, param", "start_line": 1, "end_line": 10, "total_lines": 10, "is_truncated": false}
3write_file
{
 "content": "from fastapi.security.utils import get_authorization_scheme_param\n\ndef test_get_authorization_scheme_param_whitespace():\n    # Test case 1: Single space (correct)\n    assert get_authorization_scheme_param(\"Bearer xxx\") == (\"Bearer\", \"xxx\")\n    \n    # Test case 2: Multiple spaces\n    assert get_authorization_scheme_param(\"Bearer   xxx\") == (\"Bearer\", \"xxx\")\n    \n    # Test case 3: Trailing whitespace\n    assert get_authorization_scheme_param(\"Bearer xxx \") == (\"Bearer\", \"xxx\")\n    \n    # Test case 4: Leading whitespace in param (already covered by multiple spaces, but explicit)\n    assert get_authorization_scheme_param(\"Bearer  xxx\") == (\"Bearer\", \"xxx\")\n    \n    # Test case 5: No param\n    assert get_authorization_scheme_param(\"Bearer\") == (\"Bearer\", \"\")\n    \n    # Test case 6: Empty header\n    assert get_authorization_scheme_param(None) == (\"\", \"\")\n    assert get_authorization_scheme_param(\"\") == (\"\", \"\")\n",
 "filepath": "/tmp/test_auth_whitespace.py"
}
{"status": "error", "error_type": "FileWriteError", "error_message": "Path traversal detected: '/tmp/test_auth_whitespace.py' escapes workspace root."}
full
{"status": "error", "error_type": "FileWriteError", "error_message": "Path traversal detected: '/tmp/test_auth_whitespace.py' escapes workspace root."}
4write_file
{
 "content": "from fastapi.security.utils import get_authorization_scheme_param\n\ndef test_get_authorization_scheme_param_whitespace():\n    # Test case 1: Single space (correct)\n    assert get_authorization_scheme_param(\"Bearer xxx\") == (\"Bearer\", \"xxx\")\n    \n    # Test case 2: Multiple spaces\n    assert get_authorization_scheme_param(\"Bearer   xxx\") == (\"Bearer\", \"xxx\")\n    \n    # Test case 3: Trailing whitespace\n    assert get_authorization_scheme_param(\"Bearer xxx \") == (\"Bearer\", \"xxx\")\n    \n    # Test case 4: Leading whitespace in param (already covered by multiple spaces, but explicit)\n    assert get_authorization_scheme_param(\"Bearer  xxx\") == (\"Bearer\", \"xxx\")\n    \n    # Test case 5: No param\n    assert get_authorization_scheme_param(\"Bearer\") == (\"Bearer\", \"\")\n    \n    # Test case 6: Empty header\n    assert get_authorization_scheme_param(None) == (\"\", \"\")\n    assert get_authorization_scheme_param(\"\") == (\"\", \"\")\n",
 "filepath": "test_auth_whitespace.py"
}
{"status": "ok", "filepath": "test_auth_whitespace.py", "size": 920}
full
{"status": "ok", "filepath": "test_auth_whitespace.py", "size": 920}
5run_command
{
 "command": "python3 -m pytest test_auth_whitespace.py"
}
{"status": "error", "error_type": "CommandError", "error_message": "============================= test session starts ==============================\nplatform l
full
{"status": "error", "error_type": "CommandError", "error_message": "============================= test session starts ==============================\nplatform linux -- Python 3.13.14, pytest-9.1.1, pluggy-1.6.0\ncodspeed: 5.0.3 (disabled, mode: walltime, callgraph: enabled, timer_resolution: 1.0ns)\nrootdir: /workspace\nconfigfile: pytest.ini (WARNING: ignoring pytest config in pyproject.toml!)\nplugins: anyio-4.15.1, sugar-1.1.1, inline-snapshot-0.35.4, timeout-2.4.0, xdist-3.8.0, codspeed-5.0.3, cov-7.1.0\ncollected 1 item\n\ntest_auth_whitespace.py F                                                [100%]\n\n=================================== FAILURES ===================================\n________________ test_get_authorization_scheme_param_whitespace ________________\n\n    def test_get_authorization_scheme_param_whitespace():\n        # Test case 1: Single space (correct)\n        assert get_authorization_scheme_param(\"Bearer xxx\") == (\"Bearer\", \"xxx\")\n    \n        # Test case 2: Multiple spaces\n>       assert get_authorization_scheme_param(\"Bearer   xxx\") == (\"Bearer\", \"xxx\")\nE       AssertionError: assert ('Bearer', '  xxx') == ('Bearer', 'xxx')\nE         \nE         At index 1 diff: '  xxx' != 'xxx'\nE         Use -v to get more diff\n\ntest_auth_whitespace.py:8: AssertionError\n=========================== short test summary info ============================\nFAILED test_auth_whitespace.py::test_get_authorization_scheme_param_whitespace\n============================== 1 failed in 0.44s ===============================\n", "details": {"stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.13.14, pytest-9.1.1, pluggy-1.6.0\ncodspeed: 5.0.3 (disabled, mode: walltime, callgraph: enabled, timer_resolution: 1.0ns)\nrootdir: /workspace\nconfigfile: pytest.ini (WARNING: ignoring pytest config in pyproject.toml!)\nplugins: anyio-4.15.1, sugar-1.1.1, inline-snapshot-0.35.4, timeout-2.4.0, x
6edit_file
{
 "filepath": "fastapi/security/utils.py",
 "new_string": "    return scheme, param.strip()",
 "old_string": "    return scheme, param"
}
{"status": "ok", "filepath": "fastapi/security/utils.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/security/utils.py\n+++ b/fastapi/securit
full
{"status": "ok", "filepath": "fastapi/security/utils.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/security/utils.py\n+++ b/fastapi/security/utils.py\n@@ -7,4 +7,4 @@\n     if not authorization_header_value:\n         return \"\", \"\"\n     scheme, _, param = authorization_header_value.partition(\" \")\n-    return scheme, param\n+    return scheme, param.strip()\n", "is_truncated": false}
7run_command
{
 "command": "python3 -m pytest test_auth_whitespace.py"
}
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.13.14, pytest-9.1.1, pl
full
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.13.14, pytest-9.1.1, pluggy-1.6.0\ncodspeed: 5.0.3 (disabled, mode: walltime, callgraph: enabled, timer_resolution: 1.0ns)\nrootdir: /workspace\nconfigfile: pytest.ini (WARNING: ignoring pytest config in pyproject.toml!)\nplugins: anyio-4.15.1, sugar-1.1.1, inline-snapshot-0.35.4, timeout-2.4.0, xdist-3.8.0, codspeed-5.0.3, cov-7.1.0\ncollected 1 item\n\ntest_auth_whitespace.py .                                                [100%]\n\n============================== 1 passed in 1.27s ===============================\n", "stderr": "", "exit_code": 0}
8run_command
{
 "command": "rm test_auth_whitespace.py"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
9submit_patch
{}
{"status": "ok", "patch_size": 404, "files_changed": 1}
full
{"status": "ok", "patch_size": 404, "files_changed": 1}

Patch

diff --git a/fastapi/security/utils.py b/fastapi/security/utils.py
index 002e68b4..fd349aec 100644
--- a/fastapi/security/utils.py
+++ b/fastapi/security/utils.py
@@ -7,4 +7,4 @@ def get_authorization_scheme_param(
     if not authorization_header_value:
         return "", ""
     scheme, _, param = authorization_header_value.partition(" ")
-    return scheme, param
+    return scheme, param.strip()

Test output

show
.........                                                                [100%]
=============================== warnings summary ===============================
../../../../../../kaggle/tmp/envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45
  /kaggle/tmp/envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.
    _PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
9 passed, 1 warning in 0.69s