Skip to content

Commit

Permalink
Addressed comments and added star priority option
Browse files Browse the repository at this point in the history
  • Loading branch information
val500 committed Oct 7, 2024
1 parent ab46b35 commit b5988fb
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 19 deletions.
2 changes: 1 addition & 1 deletion docs/reference/job-schema.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ The following table lists the key elements that a job definition file should con
- | (Optional) URL to send job status updates to. These updates originate from the agent and get posted to the server which then posts the update to the webhook. If no webhook is specified, these updates will not be generated.
* - ``job_priority``
- integer
- | (Optional) Integer specifying how much priority this job has. Jobs with higher job_priority will be selected by agents before other jobs. Specifying a job priority requires authorization in the form of a JWT obtained by sending a GET request to /v1/authenticate/<client-id> with a valid client_id and client-key.
- | (Optional) Integer specifying how much priority this job has. Jobs with higher job_priority will be selected by agents before other jobs. Specifying a job priority requires authorization in the form of a JWT obtained by sending a POST request to /v1/oauth2/token with a client id and client key specified in an Authorization header.

Example jobs in YAML
----------------------------
Expand Down
36 changes: 19 additions & 17 deletions server/src/api/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,30 +100,32 @@ def has_attachments(data: dict) -> bool:
)


def check_token_permission(
def check_token_priority_permission(
auth_token: str, secret_key: str, priority: int, queue: str
) -> bool:
"""
Validates token received from client and checks if it can
push a job to the queue with the requested priority
"""
if auth_token is None:
abort(401, "No authentication token specified")
else:
try:
decoded_jwt = jwt.decode(
auth_token,
secret_key,
algorithms="HS256",
options={"require": ["exp", "iat", "sub", "max_priority"]},
)
except jwt.exceptions.ExpiredSignatureError:
abort(403, "Token has expired")
except jwt.exceptions.InvalidTokenError:
abort(403, "Invalid Token")
abort(401, "Unauthorized")
try:
decoded_jwt = jwt.decode(
auth_token,
secret_key,
algorithms="HS256",
options={"require": ["exp", "iat", "sub"]},
)
except jwt.exceptions.ExpiredSignatureError:
abort(403, "Token has expired")
except jwt.exceptions.InvalidTokenError:
abort(403, "Invalid Token")

max_priority = decoded_jwt["max_priority"].get(queue, 0)
return max_priority >= priority
max_priority_dict = decoded_jwt.get("max_priority", {})
star_priority = max_priority_dict.get("*", 0)
queue_priority = max_priority_dict.get(queue, 0)
max_priority = max(star_priority, queue_priority)
return max_priority >= priority


def job_builder(data: dict, auth_token: str):
Expand Down Expand Up @@ -152,7 +154,7 @@ def job_builder(data: dict, auth_token: str):
if "job_priority" in data:
priority_level = data["job_priority"]
job_queue = data["job_queue"]
allowed = check_token_permission(
allowed = check_token_priority_permission(
auth_token,
os.environ.get("JWT_SIGNING_KEY"),
priority_level,
Expand Down
37 changes: 36 additions & 1 deletion server/tests/test_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
Unit tests for Testflinger v1 API
"""

from datetime import datetime
from datetime import datetime, timedelta
from io import BytesIO
import json
import os
Expand Down Expand Up @@ -824,3 +824,38 @@ def test_priority_invalid_queue(mongo_app_with_permissions):
"/v1/job", json=job, headers={"Authorization": token}
)
assert 403 == job_response.status_code


def test_priority_expired_token(mongo_app_with_permissions):
"""Tests rejection of priority job with expired token"""
app, _, _, _, _ = mongo_app_with_permissions
secret_key = os.environ.get("JWT_SIGNING_KEY")
expired_token_payload = {
"exp": datetime.utcnow() - timedelta(seconds=2),
"iat": datetime.utcnow() - timedelta(seconds=4),
"sub": "access_token",
"max_priority": {},
}
token = jwt.encode(expired_token_payload, secret_key, algorithm="HS256")
job = {"job_queue": "myqueue", "job_priority": 100}
job_response = app.post(
"/v1/job", json=job, headers={"Authorization": token}
)
assert 403 == job_response.status_code
assert "Token has expired" in job_response.text


def test_missing_fields_in_token(mongo_app_with_permissions):
"""Tests rejection of priority job with token with missing fields"""
app, _, _, _, _ = mongo_app_with_permissions
secret_key = os.environ.get("JWT_SIGNING_KEY")
incomplete_token_payload = {
"max_priority": {},
}
token = jwt.encode(incomplete_token_payload, secret_key, algorithm="HS256")
job = {"job_queue": "myqueue", "job_priority": 100}
job_response = app.post(
"/v1/job", json=job, headers={"Authorization": token}
)
assert 403 == job_response.status_code
assert "Invalid Token" in job_response.text

0 comments on commit b5988fb

Please sign in to comment.