restrict api endpoints (#404)

Restrict API endpoints from agents
This commit is contained in:
bmc-msft
2021-01-05 14:40:58 -05:00
committed by GitHub
parent 7e56efa6a8
commit 633e5b5f02
20 changed files with 117 additions and 146 deletions

View File

@ -9,7 +9,7 @@ from onefuzztypes.models import Error
from onefuzztypes.requests import CanScheduleRequest from onefuzztypes.requests import CanScheduleRequest
from onefuzztypes.responses import CanSchedule from onefuzztypes.responses import CanSchedule
from ..onefuzzlib.agent_authorization import call_if_agent from ..onefuzzlib.endpoint_authorization import call_if_agent
from ..onefuzzlib.pools import Node from ..onefuzzlib.pools import Node
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
from ..onefuzzlib.tasks.main import Task from ..onefuzzlib.tasks.main import Task
@ -43,9 +43,6 @@ def post(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "POST": methods = {"POST": post}
m = post method = methods[req.method]
else: return call_if_agent(req, method)
raise Exception("invalid method")
return call_if_agent(req, m)

View File

@ -8,7 +8,7 @@ from onefuzztypes.models import Error, NodeCommandEnvelope
from onefuzztypes.requests import NodeCommandDelete, NodeCommandGet from onefuzztypes.requests import NodeCommandDelete, NodeCommandGet
from onefuzztypes.responses import BoolResult, PendingNodeCommand from onefuzztypes.responses import BoolResult, PendingNodeCommand
from ..onefuzzlib.agent_authorization import call_if_agent from ..onefuzzlib.endpoint_authorization import call_if_agent
from ..onefuzzlib.pools import NodeMessage from ..onefuzzlib.pools import NodeMessage
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
@ -43,11 +43,6 @@ def delete(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "GET": methods = {"DELETE": delete, "GET": get}
m = get method = methods[req.method]
elif req.method == "DELETE": return call_if_agent(req, method)
m = delete
else:
raise Exception("invalid method")
return call_if_agent(req, m)

View File

@ -16,8 +16,8 @@ from onefuzztypes.models import (
) )
from onefuzztypes.responses import BoolResult from onefuzztypes.responses import BoolResult
from ..onefuzzlib.agent_authorization import call_if_agent
from ..onefuzzlib.agent_events import on_state_update, on_worker_event from ..onefuzzlib.agent_events import on_state_update, on_worker_event
from ..onefuzzlib.endpoint_authorization import call_if_agent
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
@ -72,4 +72,6 @@ def post(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
return call_if_agent(req, post) methods = {"POST": post}
method = methods[req.method]
return call_if_agent(req, method)

View File

@ -12,10 +12,10 @@ from onefuzztypes.models import Error
from onefuzztypes.requests import AgentRegistrationGet, AgentRegistrationPost from onefuzztypes.requests import AgentRegistrationGet, AgentRegistrationPost
from onefuzztypes.responses import AgentRegistration from onefuzztypes.responses import AgentRegistration
from ..onefuzzlib.agent_authorization import call_if_agent
from ..onefuzzlib.azure.containers import StorageType from ..onefuzzlib.azure.containers import StorageType
from ..onefuzzlib.azure.creds import get_instance_url from ..onefuzzlib.azure.creds import get_instance_url
from ..onefuzzlib.azure.queue import get_queue_sas from ..onefuzzlib.azure.queue import get_queue_sas
from ..onefuzzlib.endpoint_authorization import call_if_agent
from ..onefuzzlib.pools import Node, NodeMessage, NodeTasks, Pool from ..onefuzzlib.pools import Node, NodeMessage, NodeTasks, Pool
from ..onefuzzlib.request import not_ok, ok, parse_uri from ..onefuzzlib.request import not_ok, ok, parse_uri
@ -116,11 +116,6 @@ def post(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "POST": methods = {"POST": post, "GET": get}
m = post method = methods[req.method]
elif req.method == "GET": return call_if_agent(req, method)
m = get
else:
raise Exception("invalid method")
return call_if_agent(req, m)

View File

@ -20,6 +20,7 @@ from ..onefuzzlib.azure.containers import (
get_container_sas_url, get_container_sas_url,
get_containers, get_containers,
) )
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
@ -90,4 +91,5 @@ def delete(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
methods = {"GET": get, "POST": post, "DELETE": delete} methods = {"GET": get, "POST": post, "DELETE": delete}
return methods[req.method](req) method = methods[req.method]
return call_if_user(req, method)

View File

@ -13,6 +13,7 @@ from ..onefuzzlib.azure.containers import (
container_exists, container_exists,
get_file_sas_url, get_file_sas_url,
) )
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.request import not_ok, parse_uri, redirect from ..onefuzzlib.request import not_ok, parse_uri, redirect
@ -47,4 +48,5 @@ def get(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
methods = {"GET": get} methods = {"GET": get}
return methods[req.method](req) method = methods[req.method]
return call_if_user(req, method)

View File

@ -7,6 +7,7 @@ import azure.functions as func
from onefuzztypes.job_templates import JobTemplateRequest from onefuzztypes.job_templates import JobTemplateRequest
from onefuzztypes.models import Error from onefuzztypes.models import Error
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.job_templates.templates import JobTemplateIndex from ..onefuzzlib.job_templates.templates import JobTemplateIndex
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
from ..onefuzzlib.user_credentials import parse_jwt_token from ..onefuzzlib.user_credentials import parse_jwt_token
@ -34,9 +35,6 @@ def post(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "GET": methods = {"GET": get, "POST": post}
return get(req) method = methods[req.method]
elif req.method == "POST": return call_if_user(req, method)
return post(req)
else:
raise Exception("invalid method")

View File

@ -13,6 +13,7 @@ from onefuzztypes.job_templates import (
from onefuzztypes.models import Error from onefuzztypes.models import Error
from onefuzztypes.responses import BoolResult from onefuzztypes.responses import BoolResult
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.job_templates.templates import JobTemplateIndex from ..onefuzzlib.job_templates.templates import JobTemplateIndex
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
@ -61,11 +62,6 @@ def delete(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "GET": methods = {"GET": get, "POST": post, "DELETE": delete}
return get(req) method = methods[req.method]
elif req.method == "POST": return call_if_user(req, method)
return post(req)
elif req.method == "DELETE":
return delete(req)
else:
raise Exception("invalid method")

View File

@ -8,6 +8,7 @@ from onefuzztypes.enums import ErrorCode, JobState
from onefuzztypes.models import Error, JobConfig, JobTaskInfo from onefuzztypes.models import Error, JobConfig, JobTaskInfo
from onefuzztypes.requests import JobGet, JobSearch from onefuzztypes.requests import JobGet, JobSearch
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.jobs import Job from ..onefuzzlib.jobs import Job
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
from ..onefuzzlib.tasks.main import Task from ..onefuzzlib.tasks.main import Task
@ -74,11 +75,6 @@ def delete(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "GET": methods = {"GET": get, "POST": post, "DELETE": delete}
return get(req) method = methods[req.method]
elif req.method == "POST": return call_if_user(req, method)
return post(req)
elif req.method == "DELETE":
return delete(req)
else:
raise Exception("invalid method")

View File

@ -9,6 +9,7 @@ from onefuzztypes.models import Error
from onefuzztypes.requests import NodeGet, NodeSearch, NodeUpdate from onefuzztypes.requests import NodeGet, NodeSearch, NodeUpdate
from onefuzztypes.responses import BoolResult from onefuzztypes.responses import BoolResult
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.pools import Node, NodeTasks from ..onefuzzlib.pools import Node, NodeTasks
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
@ -100,13 +101,6 @@ def patch(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "GET": methods = {"GET": get, "PATCH": patch, "DELETE": delete, "POST": post}
return get(req) method = methods[req.method]
elif req.method == "DELETE": return call_if_user(req, method)
return delete(req)
elif req.method == "PATCH":
return patch(req)
elif req.method == "POST":
return post(req)
else:
raise Exception("invalid method")

View File

@ -9,6 +9,7 @@ import azure.functions as func
from onefuzztypes.models import Error from onefuzztypes.models import Error
from onefuzztypes.requests import NotificationCreate, NotificationGet from onefuzztypes.requests import NotificationCreate, NotificationGet
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.notifications.main import Notification from ..onefuzzlib.notifications.main import Notification
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
@ -49,11 +50,6 @@ def delete(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "GET": methods = {"GET": get, "POST": post, "DELETE": delete}
return get(req) method = methods[req.method]
elif req.method == "POST": return call_if_user(req, method)
return post(req)
elif req.method == "DELETE":
return delete(req)
else:
raise Exception("invalid method")

View File

@ -39,25 +39,53 @@ def is_agent(token_data: UserInfo) -> bool:
return False return False
def call_if_agent( def is_user(token_data: UserInfo) -> bool:
req: func.HttpRequest, method: Callable[[func.HttpRequest], func.HttpResponse] return not is_agent(token_data)
) -> func.HttpResponse:
def reject(req: func.HttpRequest, token: UserInfo) -> func.HttpResponse:
logging.error(
"reject token. url:%s token:%s body:%s",
repr(req.url),
repr(token),
repr(req.get_body()),
)
return not_ok(
Error(code=ErrorCode.UNAUTHORIZED, errors=["Unrecognized agent"]),
status_code=401,
context="token verification",
)
def call_if(
req: func.HttpRequest,
method: Callable[[func.HttpRequest], func.HttpResponse],
*,
allow_user: bool = False,
allow_agent: bool = False
) -> func.HttpResponse:
token = parse_jwt_token(req) token = parse_jwt_token(req)
if isinstance(token, Error): if isinstance(token, Error):
return not_ok(token, status_code=401, context="token verification") return not_ok(token, status_code=401, context="token verification")
if not is_agent(token): if is_user(token) and not allow_user:
logging.error( return reject(req, token)
"rejecting token url:%s token:%s body:%s",
repr(req.url), if is_agent(token) and not allow_agent:
repr(token), return reject(req, token)
repr(req.get_body()),
)
return not_ok(
Error(code=ErrorCode.UNAUTHORIZED, errors=["Unrecognized agent"]),
status_code=401,
context="token verification",
)
return method(req) return method(req)
def call_if_user(
req: func.HttpRequest, method: Callable[[func.HttpRequest], func.HttpResponse]
) -> func.HttpResponse:
return call_if(req, method, allow_user=True)
def call_if_agent(
req: func.HttpRequest, method: Callable[[func.HttpRequest], func.HttpResponse]
) -> func.HttpResponse:
return call_if(req, method, allow_agent=True)

View File

@ -21,6 +21,7 @@ from ..onefuzzlib.azure.creds import (
) )
from ..onefuzzlib.azure.queue import get_queue_sas from ..onefuzzlib.azure.queue import get_queue_sas
from ..onefuzzlib.azure.vmss import list_available_skus from ..onefuzzlib.azure.vmss import list_available_skus
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.pools import Pool from ..onefuzzlib.pools import Pool
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
@ -136,11 +137,6 @@ def delete(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "GET": methods = {"GET": get, "POST": post, "DELETE": delete}
return get(req) method = methods[req.method]
elif req.method == "POST": return call_if_user(req, method)
return post(req)
elif req.method == "DELETE":
return delete(req)
else:
raise Exception("invalid method")

View File

@ -11,6 +11,7 @@ from onefuzztypes.models import Error
from onefuzztypes.requests import ProxyCreate, ProxyDelete, ProxyGet, ProxyReset from onefuzztypes.requests import ProxyCreate, ProxyDelete, ProxyGet, ProxyReset
from onefuzztypes.responses import BoolResult, ProxyGetResult from onefuzztypes.responses import BoolResult, ProxyGetResult
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.pools import Scaleset from ..onefuzzlib.pools import Scaleset
from ..onefuzzlib.proxy import Proxy from ..onefuzzlib.proxy import Proxy
from ..onefuzzlib.proxy_forward import ProxyForward from ..onefuzzlib.proxy_forward import ProxyForward
@ -114,13 +115,6 @@ def delete(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "GET": methods = {"GET": get, "POST": post, "DELETE": delete, "PATCH": patch}
return get(req) method = methods[req.method]
elif req.method == "POST": return call_if_user(req, method)
return post(req)
elif req.method == "DELETE":
return delete(req)
elif req.method == "PATCH":
return patch(req)
else:
raise Exception("invalid method")

View File

@ -8,6 +8,7 @@ from onefuzztypes.enums import ErrorCode, VmState
from onefuzztypes.models import Error, ReproConfig from onefuzztypes.models import Error, ReproConfig
from onefuzztypes.requests import ReproGet from onefuzztypes.requests import ReproGet
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.repro import Repro from ..onefuzzlib.repro import Repro
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
from ..onefuzzlib.user_credentials import parse_jwt_token from ..onefuzzlib.user_credentials import parse_jwt_token
@ -73,11 +74,6 @@ def delete(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "GET": methods = {"GET": get, "POST": post, "DELETE": delete}
return get(req) method = methods[req.method]
elif req.method == "POST": return call_if_user(req, method)
return post(req)
elif req.method == "DELETE":
return delete(req)
else:
raise Exception("invalid method")

View File

@ -16,6 +16,7 @@ from onefuzztypes.responses import BoolResult
from ..onefuzzlib.azure.creds import get_base_region, get_regions from ..onefuzzlib.azure.creds import get_base_region, get_regions
from ..onefuzzlib.azure.vmss import list_available_skus from ..onefuzzlib.azure.vmss import list_available_skus
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.pools import Pool, Scaleset from ..onefuzzlib.pools import Pool, Scaleset
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
@ -144,13 +145,6 @@ def patch(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "GET": methods = {"GET": get, "POST": post, "DELETE": delete, "PATCH": patch}
return get(req) method = methods[req.method]
elif req.method == "POST": return call_if_user(req, method)
return post(req)
elif req.method == "DELETE":
return delete(req)
elif req.method == "PATCH":
return patch(req)
else:
raise Exception("invalid method")

View File

@ -10,6 +10,7 @@ from onefuzztypes.models import Error, TaskConfig
from onefuzztypes.requests import TaskGet, TaskSearch from onefuzztypes.requests import TaskGet, TaskSearch
from onefuzztypes.responses import BoolResult from onefuzztypes.responses import BoolResult
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.jobs import Job from ..onefuzzlib.jobs import Job
from ..onefuzzlib.pools import NodeTasks from ..onefuzzlib.pools import NodeTasks
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
@ -99,11 +100,6 @@ def delete(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "GET": methods = {"GET": get, "POST": post, "DELETE": delete}
return get(req) method = methods[req.method]
elif req.method == "POST": return call_if_user(req, method)
return post(req)
elif req.method == "DELETE":
return delete(req)
else:
raise Exception("invalid method")

View File

@ -15,6 +15,7 @@ from onefuzztypes.requests import (
) )
from onefuzztypes.responses import BoolResult from onefuzztypes.responses import BoolResult
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
from ..onefuzzlib.webhooks import Webhook from ..onefuzzlib.webhooks import Webhook
@ -105,13 +106,6 @@ def delete(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "GET": methods = {"GET": get, "POST": post, "DELETE": delete, "PATCH": patch}
return get(req) method = methods[req.method]
elif req.method == "POST": return call_if_user(req, method)
return post(req)
elif req.method == "DELETE":
return delete(req)
elif req.method == "PATCH":
return patch(req)
else:
raise Exception("invalid method")

View File

@ -9,6 +9,7 @@ import azure.functions as func
from onefuzztypes.models import Error from onefuzztypes.models import Error
from onefuzztypes.requests import WebhookGet from onefuzztypes.requests import WebhookGet
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
from ..onefuzzlib.webhooks import Webhook, WebhookMessageLog from ..onefuzzlib.webhooks import Webhook, WebhookMessageLog
@ -28,7 +29,6 @@ def post(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "POST": methods = {"POST": post}
return post(req) method = methods[req.method]
else: return call_if_user(req, method)
raise Exception("invalid method")

View File

@ -9,6 +9,7 @@ import azure.functions as func
from onefuzztypes.models import Error from onefuzztypes.models import Error
from onefuzztypes.requests import WebhookGet from onefuzztypes.requests import WebhookGet
from ..onefuzzlib.endpoint_authorization import call_if_user
from ..onefuzzlib.request import not_ok, ok, parse_request from ..onefuzzlib.request import not_ok, ok, parse_request
from ..onefuzzlib.webhooks import Webhook from ..onefuzzlib.webhooks import Webhook
@ -29,7 +30,6 @@ def post(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest) -> func.HttpResponse: def main(req: func.HttpRequest) -> func.HttpResponse:
if req.method == "POST": methods = {"POST": post}
return post(req) method = methods[req.method]
else: return call_if_user(req, method)
raise Exception("invalid method")