fix(ui_sso.py): initial commit, adding checking token endpoint response for allowed team ids

Allows ui access control to work for the given team ids
This commit is contained in:
Krrish Dholakia
2025-09-19 17:02:49 -07:00
parent 90ee9e4587
commit 75b98a7909
2 changed files with 37 additions and 5 deletions
+18 -4
View File
@@ -163,6 +163,7 @@ class JWTHandler:
return False
def get_team_ids_from_jwt(self, token: dict) -> List[str]:
if self.litellm_jwtauth.team_ids_jwt_field is not None:
team_ids: Optional[List[str]] = get_nested_value(
data=token,
@@ -483,7 +484,18 @@ class JWTHandler:
# Supported algos: https://pyjwt.readthedocs.io/en/stable/algorithms.html
# "Warning: Make sure not to mix symmetric and asymmetric algorithms that interpret
# the key in different ways (e.g. HS* and RS*)."
algorithms = ["RS256", "RS384", "RS512", "PS256", "PS384", "PS512", "ES256", "ES384", "ES512", "EdDSA"]
algorithms = [
"RS256",
"RS384",
"RS512",
"PS256",
"PS384",
"PS512",
"ES256",
"ES384",
"ES512",
"EdDSA",
]
audience = os.getenv("JWT_AUDIENCE")
decode_options = None
@@ -540,7 +552,9 @@ class JWTHandler:
raise Exception(f"Validation fails: {str(e)}")
elif public_key is not None and isinstance(public_key, str):
try:
cert = x509.load_pem_x509_certificate(public_key.encode(), default_backend())
cert = x509.load_pem_x509_certificate(
public_key.encode(), default_backend()
)
# Extract public key
key = cert.public_key().public_bytes(
@@ -565,7 +579,7 @@ class JWTHandler:
raise Exception(f"Validation fails: {str(e)}")
raise Exception("Invalid JWT Submitted")
async def close(self):
await self.http_handler.close()
@@ -1214,4 +1228,4 @@ class JWTAuthManager:
end_user_object=end_user_object,
token=api_key,
team_membership=team_membership_object,
)
)
+19 -1
View File
@@ -193,7 +193,7 @@ def generic_response_convertor(
response,
jwt_handler: JWTHandler,
sso_jwt_handler: Optional[JWTHandler] = None,
):
) -> CustomOpenID:
generic_user_id_attribute_name = os.getenv(
"GENERIC_USER_ID_ATTRIBUTE", "preferred_username"
)
@@ -226,6 +226,7 @@ def generic_response_convertor(
team_ids = jwt_handler.get_team_ids_from_jwt(cast(dict, response))
all_teams.extend(team_ids)
return CustomOpenID(
id=response.get(generic_user_id_attribute_name),
display_name=response.get(generic_user_display_name_attribute_name),
@@ -340,6 +341,22 @@ async def get_generic_sso_response(
params={"include_client_id": generic_include_client_id},
headers=additional_generic_sso_headers_dict,
)
access_token_str: Optional[str] = generic_sso.access_token
if access_token_str and sso_jwt_handler:
import jwt
access_token_payload = jwt.decode(
access_token_str, options={"verify_signature": False}
)
result_team_ids: Optional[List[str]] = (
getattr(result, "team_ids", []) if result else []
)
if not result_team_ids:
team_ids = sso_jwt_handler.get_team_ids_from_jwt(access_token_payload)
setattr(result, "team_ids", team_ids)
except Exception as e:
verbose_proxy_logger.exception(
f"Error verifying and processing generic SSO: {e}. Passed in headers: {additional_generic_sso_headers_dict}"
@@ -612,6 +629,7 @@ async def auth_callback(request: Request, state: Optional[str] = None): # noqa:
microsoft_client_id=microsoft_client_id,
redirect_url=redirect_url,
)
elif generic_client_id is not None:
result, received_response = await get_generic_sso_response(
request=request,