Skip to content

Commit fad8ff7

Browse files
authored
Merge pull request #505 from radofuchs/LCORE_287_authorized_openshift_compatibility
LCORE-287: update documentation for authorized endpoint to align with openshift
2 parents c7a5f03 + 86bf3fa commit fad8ff7

29 files changed

+231
-59
lines changed

docs/openapi.json

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,17 @@
689689
}
690690
},
691691
"400": {
692-
"description": "Missing or invalid credentials provided by client",
692+
"description": "Missing or invalid credentials provided by client for the noop and noop-with-token authentication modules",
693+
"content": {
694+
"application/json": {
695+
"schema": {
696+
"$ref": "#/components/schemas/UnauthorizedResponse"
697+
}
698+
}
699+
}
700+
},
701+
"401": {
702+
"description": "Missing or invalid credentials provided by client for the k8s authentication module",
693703
"content": {
694704
"application/json": {
695705
"schema": {
@@ -922,19 +932,27 @@
922932
"John Doe",
923933
"Adam Smith"
924934
]
935+
},
936+
"skip_userid_check": {
937+
"type": "boolean",
938+
"title": "Skip User Id Check",
939+
"description": "Whether to skip the user ID check",
940+
"examples": [true, false]
925941
}
926942
},
927943
"type": "object",
928944
"required": [
929945
"user_id",
930-
"username"
946+
"username",
947+
"skip_userid_check"
931948
],
932949
"title": "AuthorizedResponse",
933950
"description": "Model representing a response to an authorization request.\n\nAttributes:\n user_id: The ID of the logged in user.\n username: The name of the logged in user.",
934951
"examples": [
935952
{
936953
"user_id": "123e4567-e89b-12d3-a456-426614174000",
937-
"username": "user1"
954+
"username": "user1",
955+
"skip_userid_check": false
938956
}
939957
]
940958
},

docs/openapi.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,8 @@ Returns:
397397
| Status Code | Description | Component |
398398
|-------------|-------------|-----------|
399399
| 200 | The user is logged-in and authorized to access OLS | [AuthorizedResponse](#authorizedresponse) |
400-
| 400 | Missing or invalid credentials provided by client | [UnauthorizedResponse](#unauthorizedresponse) |
400+
| 400 | Missing or invalid credentials provided by client for noop and noop-with-token | [UnauthorizedResponse](#unauthorizedresponse) |
401+
| 401 | Missing or invalid credentials provided by client for k8s | [UnauthorizedResponse](#unauthorizedresponse) |
401402
| 403 | User is not authorized | [ForbiddenResponse](#forbiddenresponse) |
402403
## GET `/metrics`
403404

@@ -515,6 +516,7 @@ Attributes:
515516
|-------|------|-------------|
516517
| user_id | string | User ID, for example UUID |
517518
| username | string | User name |
519+
| skip_userid_check | bool | Whether to skip user_id check |
518520

519521

520522
## CORSConfiguration

docs/output.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,8 @@ Returns:
397397
| Status Code | Description | Component |
398398
|-------------|-------------|-----------|
399399
| 200 | The user is logged-in and authorized to access OLS | [AuthorizedResponse](#authorizedresponse) |
400-
| 400 | Missing or invalid credentials provided by client | [UnauthorizedResponse](#unauthorizedresponse) |
400+
| 400 | Missing or invalid credentials provided by client for noop and noop-with-token | [UnauthorizedResponse](#unauthorizedresponse) |
401+
| 401 | Missing or invalid credentials provided by client for k8s | [UnauthorizedResponse](#unauthorizedresponse) |
401402
| 403 | User is not authorized | [ForbiddenResponse](#forbiddenresponse) |
402403
## GET `/metrics`
403404

@@ -509,12 +510,14 @@ Model representing a response to an authorization request.
509510
Attributes:
510511
user_id: The ID of the logged in user.
511512
username: The name of the logged in user.
513+
skip_userid_check: Whether to skip user_id check
512514

513515

514516
| Field | Type | Description |
515517
|-------|------|-------------|
516518
| user_id | string | User ID, for example UUID |
517519
| username | string | User name |
520+
| skip_userid_check | bool | skip user_id check |
518521

519522

520523
## CORSConfiguration

src/app/endpoints/authorized.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@
2020
"model": AuthorizedResponse,
2121
},
2222
400: {
23-
"description": "Missing or invalid credentials provided by client",
23+
"description": "Missing or invalid credentials provided by client for the noop and"
24+
"noop-with-token authentication modules",
25+
"model": UnauthorizedResponse,
26+
},
27+
401: {
28+
"description": "Missing or invalid credentials provided by client for the"
29+
"k8s authentication module",
2430
"model": UnauthorizedResponse,
2531
},
2632
403: {
@@ -44,5 +50,7 @@ async def authorized_endpoint_handler(
4450
AuthorizedResponse: Contains the user ID and username of the authenticated user.
4551
"""
4652
# Ignore the user token, we should not return it in the response
47-
user_id, user_name, _ = auth
48-
return AuthorizedResponse(user_id=user_id, username=user_name)
53+
user_id, user_name, skip_userid_check, _ = auth
54+
return AuthorizedResponse(
55+
user_id=user_id, username=user_name, skip_userid_check=skip_userid_check
56+
)

src/app/endpoints/feedback.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ async def feedback_endpoint_handler(
110110
"""
111111
logger.debug("Feedback received %s", str(feedback_request))
112112

113-
user_id, _, _ = auth
113+
user_id, _, _, _ = auth
114114
try:
115115
store_feedback(user_id, feedback_request.model_dump(exclude={"model_config"}))
116116
except Exception as e:
@@ -195,7 +195,7 @@ async def update_feedback_status(
195195
Returns:
196196
FeedbackStatusUpdateResponse: Indicates whether feedback is enabled.
197197
"""
198-
user_id, _, _ = auth
198+
user_id, _, _, _ = auth
199199
requested_status = feedback_update_request.get_value()
200200

201201
with feedback_status_lock:

src/app/endpoints/query.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ async def query_endpoint_handler(
180180
# log Llama Stack configuration
181181
logger.info("Llama stack config: %s", configuration.llama_stack_configuration)
182182

183-
user_id, _, token = auth
183+
user_id, _, _, token = auth
184184

185185
user_conversation: UserConversation | None = None
186186
if query_request.conversation_id:

src/app/endpoints/streaming_query.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ async def streaming_query_endpoint_handler( # pylint: disable=too-many-locals
556556
# log Llama Stack configuration
557557
logger.info("Llama stack config: %s", configuration.llama_stack_configuration)
558558

559-
user_id, _user_name, token = auth
559+
user_id, _user_name, _skip_userid_check, token = auth
560560

561561
user_conversation: UserConversation | None = None
562562
if query_request.conversation_id:

src/auth/interface.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,26 @@
99

1010
from fastapi import Request
1111

12-
from constants import DEFAULT_USER_NAME, DEFAULT_USER_UID, NO_USER_TOKEN
12+
from constants import (
13+
DEFAULT_USER_NAME,
14+
DEFAULT_SKIP_USER_ID_CHECK,
15+
DEFAULT_USER_UID,
16+
NO_USER_TOKEN,
17+
)
1318

1419
UserID = str
1520
UserName = str
21+
SkipUserIdCheck = bool
1622
Token = str
1723

18-
AuthTuple = tuple[UserID, UserName, Token]
24+
AuthTuple = tuple[UserID, UserName, SkipUserIdCheck, Token]
1925

20-
NO_AUTH_TUPLE: AuthTuple = (DEFAULT_USER_UID, DEFAULT_USER_NAME, NO_USER_TOKEN)
26+
NO_AUTH_TUPLE: AuthTuple = (
27+
DEFAULT_USER_UID,
28+
DEFAULT_USER_NAME,
29+
DEFAULT_SKIP_USER_ID_CHECK,
30+
NO_USER_TOKEN,
31+
)
2132

2233

2334
class AuthInterface(ABC): # pylint: disable=too-few-public-methods

src/auth/jwk_token.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ def __init__(
118118
"""Initialize the required allowed paths for authorization checks."""
119119
self.virtual_path: str = virtual_path
120120
self.config: JwkConfiguration = config
121+
self.skip_userid_check = False
121122

122123
async def __call__(self, request: Request) -> AuthTuple:
123124
"""Authenticate the JWT in the headers against the keys from the JWK url."""
@@ -190,4 +191,4 @@ async def __call__(self, request: Request) -> AuthTuple:
190191

191192
logger.info("Successfully authenticated user %s (ID: %s)", username, user_id)
192193

193-
return user_id, username, user_token
194+
return user_id, username, self.skip_userid_check, user_token

src/auth/k8s.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from kubernetes.config import ConfigException
1212

1313
from configuration import configuration
14-
from auth.utils import extract_user_token
1514
from auth.interface import AuthInterface
1615
from constants import DEFAULT_VIRTUAL_PATH
1716

@@ -227,18 +226,33 @@ class K8SAuthDependency(AuthInterface): # pylint: disable=too-few-public-method
227226
def __init__(self, virtual_path: str = DEFAULT_VIRTUAL_PATH) -> None:
228227
"""Initialize the required allowed paths for authorization checks."""
229228
self.virtual_path = virtual_path
229+
self.skip_userid_check = False
230230

231-
async def __call__(self, request: Request) -> tuple[str, str, str]:
231+
async def __call__(self, request: Request) -> tuple[str, str, bool, str]:
232232
"""Validate FastAPI Requests for authentication and authorization.
233233
234234
Args:
235235
request: The FastAPI request object.
236236
237237
Returns:
238238
The user's UID and username if authentication and authorization succeed
239-
user_id check is skipped with noop auth to allow consumers provide user_id
239+
user_id check should never be skipped with K8s authentication
240+
If user_id check should be skipped - always return False for k8s
241+
User's token
240242
"""
241-
token = extract_user_token(request.headers)
243+
authorization_header = request.headers.get("Authorization")
244+
if not authorization_header:
245+
raise HTTPException(
246+
status_code=401, detail="Unauthorized: No auth header found"
247+
)
248+
249+
token = _extract_bearer_token(authorization_header)
250+
if not token:
251+
raise HTTPException(
252+
status_code=401,
253+
detail="Unauthorized: Bearer token not found or invalid",
254+
)
255+
242256
user_info = get_user_info(token)
243257
if user_info is None:
244258
raise HTTPException(
@@ -267,4 +281,9 @@ async def __call__(self, request: Request) -> tuple[str, str, str]:
267281
logger.error("API exception during SubjectAccessReview: %s", e)
268282
raise HTTPException(status_code=403, detail="Internal server error") from e
269283

270-
return user_info.user.uid, user_info.user.username, token
284+
return (
285+
user_info.user.uid,
286+
user_info.user.username,
287+
self.skip_userid_check,
288+
token,
289+
)

0 commit comments

Comments
 (0)