Skip to content

Commit 8c24935

Browse files
committed
Allow authorization header to be omitted
Endpoints configured for the anybody (`*`) authorization should work without an Authorization header. This change allows requests without the header to be processed, returning a default user identity, which will obviously receive the anybody role (`*`) (because everyone receives it), so if the configuration allows particular endpoints to be reachable by the `*` role, guests (no auth header) users will be authorized to use it.
1 parent d89f7a3 commit 8c24935

File tree

4 files changed

+19
-7
lines changed

4 files changed

+19
-7
lines changed

src/auth/interface.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@
99

1010
from fastapi import Request
1111

12+
from constants import DEFAULT_USER_NAME, DEFAULT_USER_UID, NO_USER_TOKEN
13+
1214
UserID = str
1315
UserName = str
1416
Token = str
1517

1618
AuthTuple = tuple[UserID, UserName, Token]
1719

20+
NO_AUTH_TUPLE: AuthTuple = (DEFAULT_USER_UID, DEFAULT_USER_NAME, NO_USER_TOKEN)
21+
1822

1923
class AuthInterface(ABC): # pylint: disable=too-few-public-methods
2024
"""Base class for all authentication method implementations."""

src/auth/jwk_token.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from constants import (
2020
DEFAULT_VIRTUAL_PATH,
2121
)
22-
from auth.interface import AuthInterface
22+
from auth.interface import NO_AUTH_TUPLE, AuthInterface, AuthTuple
2323
from auth.utils import extract_user_token
2424
from models.config import JwkConfiguration
2525

@@ -120,10 +120,12 @@ def __init__(
120120
self.virtual_path: str = virtual_path
121121
self.config: JwkConfiguration = config
122122

123-
async def __call__(self, request: Request) -> tuple[str, str, str]:
123+
async def __call__(self, request: Request) -> AuthTuple:
124124
"""Authenticate the JWT in the headers against the keys from the JWK url."""
125-
user_token = extract_user_token(request.headers)
125+
if not request.headers.get("Authorization"):
126+
return NO_AUTH_TUPLE
126127

128+
user_token = extract_user_token(request.headers)
127129
jwk_set = await get_jwk_set(str(self.config.url))
128130

129131
try:

src/authorization/resolvers.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from auth.interface import AuthTuple
1111
from models.config import JwtRoleRule, AccessRule, JsonPathOperator, Action
12+
import constants
1213

1314
logger = logging.getLogger(__name__)
1415

@@ -71,6 +72,10 @@ def evaluate_role_rules(rule: JwtRoleRule, jwt_claims: dict[str, Any]) -> UserRo
7172
def _get_claims(auth: AuthTuple) -> dict[str, Any]:
7273
"""Get the JWT claims from the auth tuple."""
7374
_, _, token = auth
75+
if token == constants.NO_USER_TOKEN:
76+
# No claims for guests
77+
return {}
78+
7479
jwt_claims = json.loads(token)
7580

7681
if not jwt_claims:

tests/unit/auth/test_jwk_token.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from authlib.jose import JsonWebKey, JsonWebToken
1313

1414
from auth.jwk_token import JwkTokenAuthDependency, _jwk_cache
15+
from constants import DEFAULT_USER_NAME, DEFAULT_USER_UID, NO_USER_TOKEN
1516
from models.config import JwkConfiguration, JwtConfiguration
1617

1718
TEST_USER_ID = "test-user-123"
@@ -267,11 +268,11 @@ async def test_no_auth_header(
267268

268269
dependency = JwkTokenAuthDependency(default_jwk_configuration)
269270

270-
with pytest.raises(HTTPException) as exc_info:
271-
await dependency(no_token_request)
271+
user_id, username, token_claims = await dependency(no_token_request)
272272

273-
assert exc_info.value.status_code == 400
274-
assert exc_info.value.detail == "No Authorization header found"
273+
assert user_id == DEFAULT_USER_UID
274+
assert username == DEFAULT_USER_NAME
275+
assert token_claims == NO_USER_TOKEN
275276

276277

277278
async def test_no_bearer(

0 commit comments

Comments
 (0)