fix(proxy): support wildcard patterns in JWT role_permissions.models

can_rbac_role_call_model used a plain list membership check, so
wildcard patterns like "bedrock-claude-*" or "*" in role_permissions
models config were treated as literal strings and never matched
concrete model names. Use fnmatch for pattern matching, consistent
with how wildcards work in team/key model gating.

Fixes #27536
This commit is contained in:
Jonathan Wrede 2026-05-10 18:31:19 +00:00
parent 0af33fbe70
commit b9f9f90340
2 changed files with 44 additions and 6 deletions

View file

@ -874,13 +874,15 @@ class JWTAuthManager:
if role_based_models is None or model is None:
return True
if model not in role_based_models:
raise HTTPException(
status_code=403,
detail=f"Role={rbac_role} not allowed to call model={model}. Allowed models={role_based_models}",
)
if model in role_based_models or any(
fnmatch.fnmatch(model, pattern) for pattern in role_based_models
):
return True
return True
raise HTTPException(
status_code=403,
detail=f"Role={rbac_role} not allowed to call model={model}. Allowed models={role_based_models}",
)
@staticmethod
def check_scope_based_access(

View file

@ -1051,6 +1051,42 @@ def test_can_rbac_role_call_model_no_role_permissions():
)
def test_can_rbac_role_call_model_wildcard():
"""Wildcard patterns in role_permissions.models should match model names."""
from litellm.proxy.auth.handle_jwt import JWTAuthManager
from litellm.proxy._types import RoleBasedPermissions
roles_based_permissions = [
RoleBasedPermissions(
role=LitellmUserRoles.INTERNAL_USER,
models=["bedrock-claude-*"],
),
RoleBasedPermissions(
role=LitellmUserRoles.PROXY_ADMIN,
models=["*"],
),
]
assert JWTAuthManager.can_rbac_role_call_model(
rbac_role=LitellmUserRoles.INTERNAL_USER,
general_settings={"role_permissions": roles_based_permissions},
model="bedrock-claude-draft-rep-sonnet",
)
assert JWTAuthManager.can_rbac_role_call_model(
rbac_role=LitellmUserRoles.PROXY_ADMIN,
general_settings={"role_permissions": roles_based_permissions},
model="any-model-name",
)
with pytest.raises(HTTPException):
JWTAuthManager.can_rbac_role_call_model(
rbac_role=LitellmUserRoles.INTERNAL_USER,
general_settings={"role_permissions": roles_based_permissions},
model="openai-gpt-4",
)
@pytest.mark.parametrize(
"route, request_data, expected_model",
[